initial commit

This commit is contained in:
Magistu
2023-01-31 13:12:58 +03:00
commit 46daaa5d56
202 changed files with 12463 additions and 0 deletions

View File

@@ -0,0 +1,329 @@
package ru.magistu.siegemachines.entity;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.*;
import javax.annotation.Nullable;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.item.PrimedTnt;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.ProtectionEnchantment;
import net.minecraft.world.level.*;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.FireBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
public class Breakdown
{
private static final ExplosionDamageCalculator EXPLOSION_DAMAGE_CALCULATOR = new ExplosionDamageCalculator();
private final boolean fire;
private final Explosion.BlockInteraction blockInteraction;
private final RandomSource random = RandomSource.create();
private final Level level;
private final double x;
private final double y;
private final double z;
@Nullable
private final Entity source;
private final float radius;
private final DamageSource damageSource;
private final ExplosionDamageCalculator damageCalculator;
private final ObjectArrayList<BlockPos> toBlow = new ObjectArrayList<>();
private final Map<Player, Vec3> hitPlayers = Maps.newHashMap();
private final Vec3 position;
private final Explosion explosion;
private final Entity machine;
private final float power;
public Breakdown(Level p_i50007_1_, @Nullable Entity machine, @Nullable Entity p_i50007_2_, double p_i50007_3_, double p_i50007_5_, double p_i50007_7_, float p_i50007_9_, boolean p_i50007_10_, float power, Explosion.BlockInteraction p_i50007_11_) {
this(p_i50007_1_, p_i50007_2_, machine, (DamageSource)null, (ExplosionDamageCalculator)null, p_i50007_3_, p_i50007_5_, p_i50007_7_, p_i50007_9_, p_i50007_10_, power, p_i50007_11_);
}
public Breakdown(Level p_i231610_1_, @Nullable Entity machine, @Nullable Entity p_i231610_2_, @Nullable DamageSource p_i231610_3_, @Nullable ExplosionDamageCalculator p_i231610_4_, double p_i231610_5_, double p_i231610_7_, double p_i231610_9_, float p_i231610_11_, boolean p_i231610_12_, float power, Explosion.BlockInteraction p_i231610_13_) {
this.explosion = new Explosion(p_i231610_1_, p_i231610_2_, p_i231610_3_, p_i231610_4_, p_i231610_5_, p_i231610_7_, p_i231610_9_, p_i231610_11_, p_i231610_12_, p_i231610_13_);
this.level = p_i231610_1_;
this.machine = machine;
this.source = p_i231610_2_;
this.radius = p_i231610_11_;
this.x = p_i231610_5_;
this.y = p_i231610_7_;
this.z = p_i231610_9_;
this.fire = p_i231610_12_;
this.power = power;
this.blockInteraction = p_i231610_13_;
this.damageSource = p_i231610_3_ == null && p_i231610_2_ instanceof LivingEntity ? DamageSource.explosion((LivingEntity) p_i231610_2_) : p_i231610_3_;
this.damageCalculator = p_i231610_4_ == null ? this.makeDamageCalculator(p_i231610_2_) : p_i231610_4_;
this.position = new Vec3(this.x, this.y, this.z);
}
private ExplosionDamageCalculator makeDamageCalculator(@Nullable Entity p_234894_1_) {
return (p_234894_1_ == null ? EXPLOSION_DAMAGE_CALCULATOR : new EntityBasedExplosionDamageCalculator(p_234894_1_));
}
public static float getSeenPercent(Vec3 p_222259_0_, Entity p_222259_1_) {
AABB axisalignedbb = p_222259_1_.getBoundingBox();
double d0 = 1.0D / ((axisalignedbb.maxX - axisalignedbb.minX) * 2.0D + 1.0D);
double d1 = 1.0D / ((axisalignedbb.maxY - axisalignedbb.minY) * 2.0D + 1.0D);
double d2 = 1.0D / ((axisalignedbb.maxZ - axisalignedbb.minZ) * 2.0D + 1.0D);
double d3 = (1.0D - Math.floor(1.0D / d0) * d0) / 2.0D;
double d4 = (1.0D - Math.floor(1.0D / d2) * d2) / 2.0D;
if (!(d0 < 0.0D) && !(d1 < 0.0D) && !(d2 < 0.0D)) {
int i = 0;
int j = 0;
for(float f = 0.0F; f <= 1.0F; f = (float)((double)f + d0)) {
for(float f1 = 0.0F; f1 <= 1.0F; f1 = (float)((double)f1 + d1)) {
for(float f2 = 0.0F; f2 <= 1.0F; f2 = (float)((double)f2 + d2)) {
double d5 = Mth.lerp((double)f, axisalignedbb.minX, axisalignedbb.maxX);
double d6 = Mth.lerp((double)f1, axisalignedbb.minY, axisalignedbb.maxY);
double d7 = Mth.lerp((double)f2, axisalignedbb.minZ, axisalignedbb.maxZ);
Vec3 vector3d = new Vec3(d5 + d3, d6, d7 + d4);
if (p_222259_1_.level.clip(new ClipContext(vector3d, p_222259_0_, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, p_222259_1_)).getType() == HitResult.Type.MISS) {
++i;
}
++j;
}
}
}
return (float)i / (float)j;
} else {
return 0.0F;
}
}
public void explode()
{
Set<BlockPos> set = Sets.newHashSet();
int i = 16;
for(int j = 0; j < 16; ++j) {
for(int k = 0; k < 16; ++k) {
for(int l = 0; l < 16; ++l) {
if (j == 0 || j == 15 || k == 0 || k == 15 || l == 0 || l == 15) {
double d0 = (double)((float)j / 15.0F * 2.0F - 1.0F);
double d1 = (double)((float)k / 15.0F * 2.0F - 1.0F);
double d2 = (double)((float)l / 15.0F * 2.0F - 1.0F);
double d3 = Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
d0 = d0 / d3;
d1 = d1 / d3;
d2 = d2 / d3;
float f = this.power * this.radius * (0.7F + this.level.random.nextFloat() * 0.6F);
double d4 = this.x;
double d6 = this.y;
double d8 = this.z;
for(float f1 = 0.3F; f > 0.0F; f -= this.power * 0.5F) {
BlockPos blockpos = new BlockPos(d4, d6, d8);
BlockState blockstate = this.level.getBlockState(blockpos);
FluidState fluidstate = this.level.getFluidState(blockpos);
Optional<Float> optional = this.damageCalculator.getBlockExplosionResistance(this.explosion, this.level, blockpos, blockstate, fluidstate);
if (optional.isPresent()) {
f -= (optional.get() + 0.3F) * 0.3F;
}
if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this.explosion, this.level, blockpos, blockstate, f)) {
set.add(blockpos);
}
d4 += d0 * (double)0.3F;
d6 += d1 * (double)0.3F;
d8 += d2 * (double)0.3F;
}
}
}
}
}
this.toBlow.addAll(set);
float f2 = 1.5f * this.radius;
int k1 = Mth.floor(this.x - (double)f2 - 1.0D);
int l1 = Mth.floor(this.x + (double)f2 + 1.0D);
int i2 = Mth.floor(this.y - (double)f2 - 1.0D);
int i1 = Mth.floor(this.y + (double)f2 + 1.0D);
int j2 = Mth.floor(this.z - (double)f2 - 1.0D);
int j1 = Mth.floor(this.z + (double)f2 + 1.0D);
List<Entity> list = this.level.getEntities(this.source, new AABB((double)k1, (double)i2, (double)j2, (double)l1, (double)i1, (double)j1));
Vec3 vector3d = new Vec3(this.x, this.y, this.z);
for(int k2 = 0; k2 < list.size(); ++k2) {
Entity entity = list.get(k2);
if (!entity.ignoreExplosion() && !entity.equals(this.machine) && !entity.equals(this.source)) {
double d12 = (Mth.sqrt((float) entity.distanceToSqr(vector3d)) / f2);
if (d12 <= 1.0D) {
double d5 = entity.getX() - this.x;
double d7 = (entity instanceof PrimedTnt ? entity.getY() : entity.getEyeY()) - this.y;
double d9 = entity.getZ() - this.z;
double d13 = Mth.sqrt((float) (d5 * d5 + d7 * d7 + d9 * d9));
if (d13 != 0.0D) {
d5 = d5 / d13;
d7 = d7 / d13;
d9 = d9 / d13;
double d14 = getSeenPercent(vector3d, entity);
double d10 = (1.0D - d12) * d14;
if (!(entity instanceof ItemEntity)) {
entity.hurt(this.getDamageSource(), (float) ((int) ((d10 * d10 + d10) / 2.0D * 7.0D * (double) f2 + 1.0D)));
}
double d11 = d10;
if (entity instanceof LivingEntity) {
d11 = ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity)entity, d10);
}
entity.setDeltaMovement(entity.getDeltaMovement().add(d5 * d11, d7 * d11, d9 * d11));
if (entity instanceof Player) {
Player playerentity = (Player)entity;
if (!playerentity.isSpectator() && (!playerentity.isCreative() || !playerentity.getAbilities().flying)) {
this.hitPlayers.put(playerentity, new Vec3(d5 * d10, d7 * d10, d9 * d10));
}
}
}
}
}
}
}
public void finalizeExplosion(boolean p_77279_1_) {
if (this.level.isClientSide) {
//this.level.playLocalSound(this.x, this.y, this.z, SoundEvents.GENERIC_EXPLODE, SoundCategory.BLOCKS, 4.0F, (1.0F + (this.level.random.nextFloat() - this.level.random.nextFloat()) * 0.2F) * 0.7F, false);
}
boolean flag = this.blockInteraction != Explosion.BlockInteraction.NONE;
if (p_77279_1_) {
if (!(this.radius < 2.0F) && flag) {
this.level.addParticle(ParticleTypes.EXPLOSION_EMITTER, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D);
} else {
this.level.addParticle(ParticleTypes.EXPLOSION, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D);
}
}
if (flag) {
ObjectArrayList<Pair<ItemStack, BlockPos>> objectarraylist = new ObjectArrayList<>();
Util.shuffle(this.toBlow, random);
for(BlockPos blockpos : this.toBlow) {
BlockState blockstate = this.level.getBlockState(blockpos);
Block block = blockstate.getBlock();
if (!blockstate.isAir()) {
BlockPos blockpos1 = blockpos.immutable();
this.level.getProfiler().push("explosion_blocks");
if (this.level instanceof ServerLevel) {
BlockEntity tileentity = blockstate.hasBlockEntity() ? this.level.getBlockEntity(blockpos) : null;
LootContext.Builder lootcontext$builder = (new LootContext.Builder((ServerLevel)this.level)).withRandom(this.level.random).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(blockpos)).withParameter(LootContextParams.TOOL, ItemStack.EMPTY).withOptionalParameter(LootContextParams.BLOCK_ENTITY, tileentity).withOptionalParameter(LootContextParams.THIS_ENTITY, this.source);
if (this.blockInteraction == Explosion.BlockInteraction.DESTROY) {
lootcontext$builder.withParameter(LootContextParams.EXPLOSION_RADIUS, this.radius);
}
blockstate.getDrops(lootcontext$builder).forEach((p_229977_2_) -> {
addBlockDrops(objectarraylist, p_229977_2_, blockpos1);
});
}
this.level.setBlock(blockpos, Blocks.AIR.defaultBlockState(), 3);
this.level.getProfiler().pop();
}
}
for(Pair<ItemStack, BlockPos> pair : objectarraylist) {
Block.popResource(this.level, pair.getSecond(), pair.getFirst());
}
}
if (this.fire) {
for(BlockPos blockpos2 : this.toBlow) {
if (this.random.nextInt(3) == 0 && this.level.getBlockState(blockpos2).isAir() && this.level.getBlockState(blockpos2.below()).isSolidRender(this.level, blockpos2.below())) {
this.level.setBlockAndUpdate(blockpos2, FireBlock.getState(this.level, blockpos2));
}
}
}
}
private static void addBlockDrops(ObjectArrayList<Pair<ItemStack, BlockPos>> p_46068_, ItemStack p_46069_, BlockPos p_46070_) {
int i = p_46068_.size();
for(int j = 0; j < i; ++j) {
Pair<ItemStack, BlockPos> pair = p_46068_.get(j);
ItemStack itemstack = pair.getFirst();
if (ItemEntity.areMergable(itemstack, p_46069_)) {
ItemStack itemstack1 = ItemEntity.merge(itemstack, p_46069_, 16);
p_46068_.set(j, Pair.of(itemstack1, pair.getSecond()));
if (p_46069_.isEmpty()) {
return;
}
}
}
p_46068_.add(Pair.of(p_46069_, p_46070_));
}
public DamageSource getDamageSource() {
return this.damageSource;
}
public Map<Player, Vec3> getHitPlayers() {
return this.hitPlayers;
}
@Nullable
public LivingEntity getSourceMob() {
if (this.source == null) {
return null;
} else if (this.source instanceof PrimedTnt) {
return ((PrimedTnt)this.source).getOwner();
} else if (this.source instanceof LivingEntity) {
return (LivingEntity)this.source;
} else {
if (this.source instanceof Projectile) {
Entity entity = ((Projectile)this.source).getOwner();
if (entity instanceof LivingEntity) {
return (LivingEntity)entity;
}
}
return null;
}
}
public void clearToBlow() {
this.toBlow.clear();
}
public List<BlockPos> getToBlow() {
return this.toBlow;
}
public Vec3 getPosition() {
return this.position;
}
@Nullable
public Entity getExploder() {
return this.source;
}
}

View File

@@ -0,0 +1,41 @@
package ru.magistu.siegemachines.entity;
import ru.magistu.siegemachines.SiegeMachines;
import ru.magistu.siegemachines.entity.machine.*;
import ru.magistu.siegemachines.entity.projectile.Cannonball;
import ru.magistu.siegemachines.entity.projectile.GiantArrow;
import ru.magistu.siegemachines.entity.projectile.Stone;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobCategory;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
public class EntityTypes
{
public static final DeferredRegister<EntityType<?>> DEFERRED_REGISTER = DeferredRegister.create(ForgeRegistries.ENTITY_TYPES, SiegeMachines.ID);
public static final RegistryObject<EntityType<Cannonball>> CANNONBALL = addRegistry("cannonball", Cannonball::new, 0.5f, 0.5f);
public static final RegistryObject<EntityType<Stone>> STONE = addRegistry("stone", Stone::new, 0.6f, 0.6f);
public static final RegistryObject<EntityType<GiantArrow>> GIANT_ARROW = DEFERRED_REGISTER.register("giant_arrow", () -> EntityType.Builder.<GiantArrow>of(GiantArrow::new, MobCategory.MISC).clientTrackingRange(4).updateInterval(20).sized(0.5f, 0.5f).build(new ResourceLocation(SiegeMachines.ID, "giant_arrow").toString()));
public static final RegistryObject<EntityType<Mortar>> MORTAR = addRegistry("mortar", Mortar::new, 2.0f, 1.0f);
public static final RegistryObject<EntityType<Culverin>> CULVERIN = addRegistry("culverin", Culverin::new, 2.0f, 1.0f);
public static final RegistryObject<EntityType<Trebuchet>> TREBUCHET = addRegistry("trebuchet", Trebuchet::new, 5.0f, 9.0f);
public static final RegistryObject<EntityType<Catapult>> CATAPULT = addRegistry("catapult", Catapult::new, 3.0f, 3.0f);
public static final RegistryObject<EntityType<Ballista>> BALLISTA = addRegistry("ballista", Ballista::new, 1.5f, 1.5f);
public static final RegistryObject<EntityType<BatteringRam>> BATTERING_RAM = addRegistry("battering_ram", BatteringRam::new, 4.0f, 3.0f);
public static <T extends Entity> RegistryObject<EntityType<T>> addRegistry(String name, EntityType.EntityFactory<T> constructor, float sizex, float sizey)
{
return DEFERRED_REGISTER.register(name, () -> EntityType.Builder.of(constructor, MobCategory.MISC).sized(sizex, sizey).build(new ResourceLocation(SiegeMachines.ID, name).toString()));
}
public static void register(IEventBus eventBus)
{
DEFERRED_REGISTER.register(eventBus);
}
}

View File

@@ -0,0 +1,11 @@
package ru.magistu.siegemachines.entity;
import ru.magistu.siegemachines.gui.machine.crosshair.Crosshair;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public interface IReloading
{
@OnlyIn(Dist.CLIENT)
Crosshair createCrosshair();
}

View File

@@ -0,0 +1,211 @@
package ru.magistu.siegemachines.entity.machine;
import ru.magistu.siegemachines.SiegeMachines;
import ru.magistu.siegemachines.client.SoundTypes;
import ru.magistu.siegemachines.gui.machine.crosshair.Crosshair;
import ru.magistu.siegemachines.gui.machine.crosshair.ReloadingCrosshair;
import ru.magistu.siegemachines.item.ModItems;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
import software.bernie.geckolib3.core.builder.AnimationBuilder;
import software.bernie.geckolib3.core.builder.ILoopType;
import software.bernie.geckolib3.core.controller.AnimationController;
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
import software.bernie.geckolib3.core.manager.AnimationData;
import software.bernie.geckolib3.core.manager.AnimationFactory;
import software.bernie.geckolib3.util.GeckoLibUtil;
public class Ballista extends ShootingMachine implements IAnimatable
{
private final AnimationFactory factory = GeckoLibUtil.createFactory(this);
static AnimationBuilder SHOOTING_ANIM = new AnimationBuilder().addAnimation("Shooting", ILoopType.EDefaultLoopTypes.LOOP);
static AnimationBuilder RELOADING_ANIM = new AnimationBuilder().addAnimation("Reloading", ILoopType.EDefaultLoopTypes.LOOP);
public enum State
{
SHOOTING,
RELOADING
}
public State state = State.RELOADING;
public Ballista(EntityType<? extends Mob> entitytype, Level level)
{
super(entitytype, level, MachineType.BALLISTA);
}
private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event)
{
switch (state) {
case SHOOTING -> {
event.getController().setAnimation(SHOOTING_ANIM);
return PlayState.CONTINUE;
}
case RELOADING -> {
event.getController().setAnimation(RELOADING_ANIM);
return PlayState.CONTINUE;
}
}
return PlayState.CONTINUE;
}
@Override
public void registerControllers(AnimationData data)
{
AnimationController<?> controller = new AnimationController<>(this, "controller", 1, (t) ->
{
if (this.state.equals(State.RELOADING))
{
return (double) (this.type.delaytime - this.delayticks) / this.type.delaytime;
}
return t;
}, this::predicate);
data.addAnimationController(controller);
}
@Override
public AnimationFactory getFactory()
{
return this.factory;
}
@Override
protected InteractionResult mobInteract(Player player, InteractionHand hand)
{
if (super.mobInteract(player, hand) == InteractionResult.SUCCESS)
{
return InteractionResult.SUCCESS;
}
if (!this.level.isClientSide() && !this.isVehicle())
{
player.startRiding(this);
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
public void startShooting(Player player)
{
if (this.delayticks <= 0 && this.useticks <= 0 && this.shootingticks <= 0)
{
this.state = State.SHOOTING;
this.useticks = this.type.usetime;
this.shootingticks = this.type.userealisetime;
Vec3 pos = this.position();
this.level.playLocalSound(pos.x, pos.y, pos.z, SoundTypes.BALLISTA_SHOOTING.get(), SoundSource.BLOCKS, 1.4f, 1.0f, false);
}
}
@Override
public void shoot()
{
if (!level.isClientSide())
{
super.shoot();
}
}
// @Override
// public void travel(Vec3 pos)
// {
// if (this.isAlive())
// {
// if (this.isVehicle())
// {
// LivingEntity livingentity = (LivingEntity) this.getControllingPassenger();
//
// this.setTurretRotationsDest(livingentity.getXRot(), livingentity.getYRot() - this.getYaw());
// this.updateTurretRotations();
// }
// super.travel(pos);
// }
//
// }
@Override
public void travel(Vec3 pos)
{
if (this.isAlive())
{
if (this.isVehicle() && this.useticks <= 0 && this.delayticks <= 0)
{
LivingEntity livingentity = (LivingEntity) this.getControllingPassenger();
this.setTurretRotations(livingentity.getXRot(), this.getTurretYaw());
this.updateTurretRotations();
this.setYawDest(livingentity.getYRot());
this.updateYaw();
}
super.travel(pos);
}
}
@Override
public void tick()
{
if (this.useticks != 0 && --this.useticks <= 0)
{
this.state = State.RELOADING;
this.useticks = 0;
this.delayticks = this.type.delaytime;
}
if (this.shootingticks != 0 && --this.shootingticks <= 0)
{
this.useRealise();
this.shootingticks = 0;
}
if (!level.isClientSide() && this.isOnGround())
{
this.setDeltaMovement(this.getDeltaMovement().multiply(0.0, 1.0, 0.0));
}
if (this.delayticks > 0 && this.isVehicle())
{
if (this.delayticks % 21 == 0)
{
Vec3 pos = this.position();
this.level.playLocalSound(pos.x, pos.y, pos.z, SoundTypes.BALLISTA_RELOADING.get(), SoundSource.BLOCKS, 1.0f, 1.0f, false);
}
--this.delayticks;
}
if (this.renderupdateticks-- <= 0)
{
this.updateMachineRender();
this.renderupdateticks = SiegeMachines.RENDER_UPDATE_TIME;
}
super.tick();
}
@Override
@OnlyIn(Dist.CLIENT)
public Crosshair createCrosshair()
{
return new ReloadingCrosshair();
}
@Override
public Item getMachineItem()
{
return ModItems.BALLISTA.get();
}
}

View File

@@ -0,0 +1,256 @@
package ru.magistu.siegemachines.entity.machine;
import ru.magistu.siegemachines.SiegeMachines;
import ru.magistu.siegemachines.client.SoundTypes;
import ru.magistu.siegemachines.entity.Breakdown;
import ru.magistu.siegemachines.item.ModItems;
import ru.magistu.siegemachines.network.PacketHandler;
import ru.magistu.siegemachines.network.PacketMachineUse;
import ru.magistu.siegemachines.network.PacketMachineUseRealise;
import net.minecraft.core.BlockPos;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
import software.bernie.geckolib3.core.builder.AnimationBuilder;
import software.bernie.geckolib3.core.builder.ILoopType;
import software.bernie.geckolib3.core.controller.AnimationController;
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
import software.bernie.geckolib3.core.manager.AnimationData;
import software.bernie.geckolib3.core.manager.AnimationFactory;
import software.bernie.geckolib3.util.GeckoLibUtil;
public class BatteringRam extends Machine implements IAnimatable
{
private final AnimationFactory factory = GeckoLibUtil.createFactory(this);
static AnimationBuilder MOVING_ANIM = new AnimationBuilder().addAnimation("Moving", ILoopType.EDefaultLoopTypes.LOOP);
static AnimationBuilder HITTING_ANIM = new AnimationBuilder().addAnimation("Hitting", ILoopType.EDefaultLoopTypes.LOOP);
static AnimationBuilder RELOADING_ANIM = new AnimationBuilder().addAnimation("Reloading", ILoopType.EDefaultLoopTypes.LOOP);
public int hittingticks = 0;
private int wheelssoundticks = 10;
public enum State
{
HITTING,
RELOADING
}
public State state = State.RELOADING;
private double wheelspitch = 0.0;
private double wheelsspeed = 0.0;
public BatteringRam(EntityType<? extends Mob> entitytype, Level level)
{
super(entitytype, level, MachineType.BATTERING_RAM);
}
private <E extends IAnimatable> PlayState wheels_predicate(AnimationEvent<E> event)
{
event.getController().setAnimation(MOVING_ANIM);
return PlayState.CONTINUE;
}
private <E extends IAnimatable> PlayState reloading_predicate(AnimationEvent<E> event)
{
switch (state)
{
case HITTING:
event.getController().setAnimation(HITTING_ANIM);
return PlayState.CONTINUE;
case RELOADING:
event.getController().setAnimation(RELOADING_ANIM);
return PlayState.CONTINUE;
}
return PlayState.CONTINUE;
}
@Override
public void registerControllers(AnimationData data)
{
AnimationController<?> wheels_controller = new AnimationController<>(this, "wheels_controller", 1, (t) -> {
double d = this.getWheelsSpeed();
this.wheelsspeed = d > 0 ? Math.min(d, 1.0) : Math.max(d, -1.0);
return wheelspitch += 0.015 * this.wheelsspeed;
}, this::wheels_predicate);
data.addAnimationController(wheels_controller);
AnimationController<?> reloading_controller = new AnimationController<>(this, "controller", 1, (t) ->
{
if (this.state.equals(State.RELOADING))
{
return (double) (this.type.delaytime - this.delayticks) / this.type.delaytime;
}
return t;
}, this::reloading_predicate);
data.addAnimationController(reloading_controller);
}
@Override
public AnimationFactory getFactory()
{
return this.factory;
}
@Override
protected InteractionResult mobInteract(Player player, InteractionHand hand)
{
if (!this.level.isClientSide() && !this.isVehicle())
{
player.startRiding(this);
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
@Override
public void travel(Vec3 pos)
{
if (this.isAlive())
{
if (this.isVehicle())
{
LivingEntity livingentity = (LivingEntity) this.getControllingPassenger();
this.setYawDest(livingentity.getYRot());
this.updateYaw();
float f1 = livingentity.zza;
if (f1 <= 0.0f)
{
f1 *= 0.25f;
}
this.setSpeed(0.04f);
pos = new Vec3(0.0f, pos.y, f1);
}
super.travel(pos);
}
}
@Override
public void tick()
{
if (this.useticks != 0 && --this.useticks <= 0)
{
this.state = State.RELOADING;
this.useticks = 0;
this.delayticks = this.type.delaytime;
}
if (this.hittingticks != 0 && --this.hittingticks <= 0)
{
this.useRealise();
this.hittingticks = 0;
}
if (!level.isClientSide() && this.isOnGround())
{
this.setDeltaMovement(this.getDeltaMovement().multiply(0.0, 1.0, 0.0));
}
if (this.delayticks > 0 && this.isVehicle())
{
--this.delayticks;
}
if (this.renderupdateticks-- <= 0)
{
this.updateMachineRender();
this.renderupdateticks = SiegeMachines.RENDER_UPDATE_TIME;
}
// if (this.getWheelsSpeed() > 0.0081 && this.wheelssoundticks-- <= 0)
// {
// this.level.playLocalSound(this.getX(), this.getY(), this.getZ(), SoundTypes.RAM_WHEELS.get(), SoundCategory.NEUTRAL, 0.6f, 1.0f, true);
// this.wheelssoundticks = 20;
// }
super.tick();
}
@Override
public void use(Player player)
{
if (!this.level.isClientSide())
{
PacketHandler.sendPacketToAllInArea(new PacketMachineUse(this.getId()), this.blockPosition(), SiegeMachines.RENDER_UPDATE_RANGE_SQR);
}
if (this.delayticks <= 0 && this.useticks <= 0 && this.hittingticks <= 0)
{
this.state = State.HITTING;
this.useticks = this.type.usetime;
this.hittingticks = this.type.userealisetime;
Vec3 pos = this.position();
this.level.playLocalSound(pos.x, pos.y, pos.z, SoundTypes.RAM_HITTING.get(), SoundSource.BLOCKS, 0.5f, 0.9f, false);
}
}
public void ramHit(BlockPos blockpos)
{
if (!this.level.isClientSide())
{
Breakdown breakdown = new Breakdown(this.level, this, this.getControllingPassenger(), blockpos.getX(), blockpos.getY(), blockpos.getZ(), 2, false, 3.0f, Explosion.BlockInteraction.BREAK);
breakdown.explode();
breakdown.finalizeExplosion(true);
}
}
@Override
public void useRealise()
{
if (!this.level.isClientSide())
{
PacketHandler.sendPacketToAllInArea(new PacketMachineUseRealise(this.getId()), this.blockPosition(), SiegeMachines.RENDER_UPDATE_RANGE_SQR);
BlockPos blockpos = new BlockPos(this.getHitPos());
this.ramHit(blockpos);
}
}
public double getWheelsSpeed()
{
if (this.isOnGround())
{
return this.getViewVector(5.0f).multiply(1, 0, 1).dot(this.getDeltaMovement());
}
return 0.0;
}
@Override
public void push(double p_70024_1_, double p_70024_3_, double p_70024_5_) {
// this.setDeltaMovement(this.getDeltaMovement().add(p_70024_1_, p_70024_3_, p_70024_5_));
// this.hasImpulse = true;
}
@Override
public Item getMachineItem()
{
return ModItems.BATTERING_RAM.get();
}
protected Vec3 getHitPos()
{
double pitch = this.getTurretPitch() * Math.PI / 180.0;
double yaw = (this.getViewYRot(0.5f) + this.getTurretYaw()) * Math.PI / 180.0;
return this.position().add(applyRotations(this.type.turretpivot, 0.0, yaw).add(applyRotations(this.type.turretvector, pitch, yaw)));
}
}

View File

@@ -0,0 +1,212 @@
package ru.magistu.siegemachines.entity.machine;
import ru.magistu.siegemachines.SiegeMachines;
import ru.magistu.siegemachines.client.SoundTypes;
import ru.magistu.siegemachines.gui.machine.crosshair.Crosshair;
import ru.magistu.siegemachines.gui.machine.crosshair.ReloadingCrosshair;
import ru.magistu.siegemachines.item.ModItems;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
import software.bernie.geckolib3.core.builder.AnimationBuilder;
import software.bernie.geckolib3.core.builder.ILoopType;
import software.bernie.geckolib3.core.controller.AnimationController;
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
import software.bernie.geckolib3.core.manager.AnimationData;
import software.bernie.geckolib3.core.manager.AnimationFactory;
import software.bernie.geckolib3.util.GeckoLibUtil;
public class Catapult extends ShootingMachine implements IAnimatable
{
private final AnimationFactory factory = GeckoLibUtil.createFactory(this);
static AnimationBuilder SHOOTING_ANIM = new AnimationBuilder().addAnimation("Shooting", ILoopType.EDefaultLoopTypes.LOOP);
static AnimationBuilder RELOADING_ANIM = new AnimationBuilder().addAnimation("Reloading", ILoopType.EDefaultLoopTypes.LOOP);
static AnimationBuilder IDLE_RELOADED_ANIM = new AnimationBuilder().addAnimation("IdleReloaded", ILoopType.EDefaultLoopTypes.LOOP);
static AnimationBuilder IDLE_NOT_RELOADED_ANIM = new AnimationBuilder().addAnimation("IdleNotReloaded", ILoopType.EDefaultLoopTypes.LOOP);
public enum State
{
SHOOTING,
RELOADING,
IDLE_RELOADED,
IDLE_NOT_RELOADED
}
public State state = State.RELOADING;
public Catapult(EntityType<? extends Mob> entitytype, Level level)
{
super(entitytype, level, MachineType.CATAPULT);
}
private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event)
{
switch (state) {
case SHOOTING -> {
event.getController().setAnimation(SHOOTING_ANIM);
return PlayState.CONTINUE;
}
case IDLE_RELOADED -> {
event.getController().setAnimation(IDLE_RELOADED_ANIM);
return PlayState.CONTINUE;
}
case RELOADING -> {
event.getController().setAnimation(RELOADING_ANIM);
return PlayState.CONTINUE;
}
case IDLE_NOT_RELOADED -> {
event.getController().setAnimation(IDLE_NOT_RELOADED_ANIM);
return PlayState.CONTINUE;
}
}
return PlayState.CONTINUE;
}
@Override
public void registerControllers(AnimationData data)
{
AnimationController<?> controller = new AnimationController<>(this, "controller", 1, (t) ->
{
if (this.state.equals(State.RELOADING))
{
return (double) (this.type.delaytime - this.delayticks) / this.type.delaytime;
}
return t;
}, this::predicate);
data.addAnimationController(controller);
}
@Override
public AnimationFactory getFactory()
{
return this.factory;
}
@Override
protected InteractionResult mobInteract(Player player, InteractionHand hand)
{
ItemStack stack = player.getItemInHand(hand);
if (super.mobInteract(player, hand) == InteractionResult.SUCCESS)
{
return InteractionResult.SUCCESS;
}
if (!this.level.isClientSide() && !this.isVehicle())
{
player.startRiding(this);
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
public void startShooting(Player player)
{
if (this.delayticks <= 0 && this.useticks <= 0 && this.shootingticks <= 0)
{
this.state = State.SHOOTING;
this.useticks = this.type.usetime;
this.shootingticks = this.type.userealisetime;
Vec3 pos = this.position();
this.level.playLocalSound(pos.x, pos.y, pos.z, SoundTypes.CATAPULT_SHOOTING.get(), SoundSource.BLOCKS, 1.5f, 1.0f, false);
}
}
@Override
public void shoot()
{
if (!level.isClientSide())
{
super.shoot();
}
}
@Override
public void travel(Vec3 pos)
{
if (this.isAlive())
{
if (this.isVehicle() && this.useticks <= 0 && this.delayticks <= 0)
{
LivingEntity livingentity = (LivingEntity) this.getControllingPassenger();
this.setTurretRotations(livingentity.getXRot(), this.getTurretYaw());
this.updateTurretRotations();
this.setYawDest(livingentity.getYRot());
this.updateYaw();
}
super.travel(pos);
}
}
@Override
public void tick()
{
if (this.useticks != 0 && --this.useticks <= 0)
{
this.state = State.RELOADING;
this.useticks = 0;
this.delayticks = this.type.delaytime;
}
if (this.shootingticks != 0 && --this.shootingticks <= 0)
{
this.useRealise();
this.shootingticks = 0;
}
if (!level.isClientSide() && this.isOnGround())
{
this.setDeltaMovement(this.getDeltaMovement().multiply(0.0, 1.0, 0.0));
}
if (this.delayticks > 0 && this.isVehicle())
{
if (this.delayticks % 20 == 0)
{
Vec3 pos = this.position();
this.level.playLocalSound(pos.x, pos.y, pos.z, SoundTypes.CATAPULT_RELOADING.get(), SoundSource.BLOCKS, 1.0f, 1.0f, false);
}
if (--this.delayticks <= 0)
{
this.state = State.IDLE_RELOADED;
}
}
if (this.renderupdateticks-- <= 0)
{
this.updateMachineRender();
this.renderupdateticks = SiegeMachines.RENDER_UPDATE_TIME;
}
super.tick();
}
@Override
@OnlyIn(Dist.CLIENT)
public Crosshair createCrosshair()
{
return new ReloadingCrosshair();
}
@Override
public Item getMachineItem()
{
return ModItems.CATAPULT.get();
}
}

View File

@@ -0,0 +1,273 @@
package ru.magistu.siegemachines.entity.machine;
import ru.magistu.siegemachines.SiegeMachines;
import ru.magistu.siegemachines.client.SoundTypes;
import ru.magistu.siegemachines.entity.IReloading;
import ru.magistu.siegemachines.gui.machine.crosshair.Crosshair;
import ru.magistu.siegemachines.gui.machine.crosshair.ReloadingCrosshair;
import net.minecraft.ChatFormatting;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
import software.bernie.geckolib3.core.builder.AnimationBuilder;
import software.bernie.geckolib3.core.builder.ILoopType;
import software.bernie.geckolib3.core.controller.AnimationController;
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
import software.bernie.geckolib3.core.manager.AnimationData;
import software.bernie.geckolib3.core.manager.AnimationFactory;
import software.bernie.geckolib3.util.GeckoLibUtil;
public class Culverin extends ShootingMachine implements IAnimatable, IReloading
{
private final AnimationFactory factory = GeckoLibUtil.createFactory(this);
static AnimationBuilder MOVING_ANIM = new AnimationBuilder().addAnimation("Moving", ILoopType.EDefaultLoopTypes.LOOP);
private double wheelspitch = 0.0;
private double wheelsspeed = 0.0;
private int wheelssoundticks = 10;
public Culverin(EntityType<? extends Mob> entitytype, Level level)
{
super(entitytype, level, MachineType.CULVERIN);
}
private <E extends IAnimatable> PlayState wheels_predicate(AnimationEvent<E> event)
{
event.getController().setAnimation(MOVING_ANIM);
return PlayState.CONTINUE;
}
@Override
public void registerControllers(AnimationData data)
{
AnimationController<?> wheels_controller = new AnimationController<>(this, "wheels_controller", 1, (t) -> {
double d = this.getWheelsSpeed();
this.wheelsspeed = d > 0 ? Math.min(d, 1.0) : Math.max(d, -1.0);
return wheelspitch += 0.013 * this.wheelsspeed;
}, this::wheels_predicate);
data.addAnimationController(wheels_controller);
}
@Override
public AnimationFactory getFactory()
{
return this.factory;
}
@Override
protected InteractionResult mobInteract(Player player, InteractionHand hand)
{
ItemStack stack = player.getItemInHand(hand);
if (stack.getItem().equals(Items.FLINT_AND_STEEL))
{
if (this.useticks <= 0 && this.shootingticks <= 0)
{
stack.hurtAndBreak(1, player, (p_213833_1_) ->
{
p_213833_1_.broadcastBreakEvent(hand);
net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(player, this.useItem, hand);
});
this.startShooting(player);
}
return InteractionResult.SUCCESS;
}
if (stack.getItem().equals(Items.GUNPOWDER))
{
if (!this.inventory.containsItem(Items.GUNPOWDER))
{
if (!player.isCreative())
{
stack.shrink(1);
}
this.inventory.putItem(Items.GUNPOWDER);
}
return InteractionResult.SUCCESS;
}
if (super.mobInteract(player, hand) == InteractionResult.SUCCESS)
{
return InteractionResult.SUCCESS;
}
if (!this.level.isClientSide() && !this.isVehicle())
{
player.startRiding(this);
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
@Override
public void travel(Vec3 pos)
{
if (this.isAlive())
{
if (this.isVehicle())
{
LivingEntity livingentity = (LivingEntity) this.getControllingPassenger();
this.setTurretRotationsDest(livingentity.getXRot(), livingentity.getYRot() - this.getYaw());
this.setYawDest(livingentity.getYRot());
this.updateYaw();
this.updateTurretRotations();
float f0 = livingentity.xxa * 0.2f;
float f1 = livingentity.zza;
if (f1 <= 0.0f)
{
f1 *= 0.5f;
}
this.setSpeed(0.04f);
pos = new Vec3(f0, pos.y, f1);
}
super.travel(pos);
}
}
@Override
public void tick()
{
if (this.useticks != 0 && --this.useticks <= 0)
{
this.useticks = 0;
this.delayticks = this.type.delaytime;
}
if (this.shootingticks != 0 && --this.shootingticks <= 0)
{
if (this.inventory.containsItem(Items.GUNPOWDER))
{
this.useRealise();
}
else if (!this.level.isClientSide())
{
Entity passenger = this.getControllingPassenger();
if (passenger instanceof Player)
{
passenger.sendSystemMessage(Component.translatable(SiegeMachines.ID + ".no_gunpowder").withStyle(ChatFormatting.RED));
}
}
this.shootingticks = 0;
}
if (!level.isClientSide() && this.isOnGround())
{
this.setDeltaMovement(this.getWheelsDeltaMovement());
}
if (this.delayticks > 0 && this.isVehicle())
{
--this.delayticks;
}
if (this.renderupdateticks-- <= 0)
{
this.updateMachineRender();
this.renderupdateticks = SiegeMachines.RENDER_UPDATE_TIME;
}
if (this.getWheelsSpeed() > 0.0081 && this.wheelssoundticks-- <= 0)
{
this.level.playLocalSound(this.getX(), this.getY(), this.getZ(), SoundTypes.CANNON_WHEELS.get(), SoundSource.NEUTRAL, 0.3f, 1.0f, true);
this.wheelssoundticks = 20;
}
super.tick();
}
@Override
public void startShooting(Player player)
{
if (this.delayticks <= 0 && this.useticks <= 0 && this.shootingticks <= 0)
{
if (!this.level.isClientSide())
{
this.level.playSound(null, this.getX(), this.getY(), this.getZ(), SoundTypes.FUSE.get(), SoundSource.BLOCKS, this.getVolumeFromDist(this.distanceTo(player)), 0.8f);
}
this.useticks = this.type.usetime;
this.shootingticks = this.type.userealisetime;
}
}
@Override
public void shoot()
{
if (!level.isClientSide())
{
super.shoot();
this.setDeltaMovement(this.getDeltaMovement().subtract(this.getShotView().scale(0.25)));
this.hasImpulse = true;
this.inventory.shrinkItem(Items.GUNPOWDER);
}
else
{
this.blowParticles(ParticleTypes.FLAME, 0.035, 25);
this.blowParticles(ParticleTypes.CLOUD, 0.2, 60);
Vec3 pos = this.position();
this.level.playLocalSound(pos.x, pos.y, pos.z, SoundTypes.MORTAR_SHOOTING.get(), SoundSource.BLOCKS, 1.5f/*this.getVolumeFromDist(1.5f, 64.0f, this.distanceTo(player))*/, 0.85f + this.level.random.nextFloat() * 0.3f, false);
}
}
public double getWheelsSpeed()
{
if (this.isOnGround())
{
return this.getViewVector(5.0f).multiply(1, 0, 1).dot(this.getDeltaMovement());
}
return 0.0;
}
public Vec3 getWheelsDeltaMovement()
{
if (this.isOnGround())
{
Vec3 view = this.getViewVector(1.0f);
Vec3 movement = this.getDeltaMovement();
double d0 = movement.x * view.x + movement.z * view.z;
double d1 = d0 * view.x;
double d2 = 0.0;
double d3 = d0 * view.z;
return new Vec3(d1, d2, d3);
}
return Vec3.ZERO;
}
@Override
@OnlyIn(Dist.CLIENT)
public Crosshair createCrosshair()
{
return new ReloadingCrosshair();
}
@Override
public Item getMachineItem()
{
return null;
// return ModItems.CULVERIN.get();
}
}

View File

@@ -0,0 +1,714 @@
package ru.magistu.siegemachines.entity.machine;
import ru.magistu.siegemachines.SiegeMachines;
import ru.magistu.siegemachines.gui.machine.MachineContainer;
import ru.magistu.siegemachines.network.PacketHandler;
import ru.magistu.siegemachines.network.PacketMachine;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.core.NonNullList;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import net.minecraft.world.Container;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.Nameable;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.damagesource.EntityDamageSource;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.HoneyBlock;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.network.NetworkHooks;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
public abstract class Machine extends Mob implements MenuProvider
{
public MachineInventory inventory = new MachineInventory();
public static int rows = 1;
public final MachineType type;
private float turretpitch = -25.0f;
private float turretpitchprev = this.turretpitch;
protected float turretpitchdest = this.turretpitch;
private float turretyaw = 0.0f;
private float turretyawprev = this.turretyaw;
protected float turretyawdest = this.turretyaw;
protected float yawdest = this.getYRot();
public int useticks = -1;
public int delayticks;
protected int renderupdateticks = 0;
public int deploymentticks = 0;
protected Machine(EntityType<? extends Mob> entitytype, Level level, MachineType type)
{
super(entitytype, level);
this.type = type;
this.delayticks = this.type.delaytime;
rows = this.type.rows;
}
public static AttributeSupplier.Builder setEntityAttributes(MachineType type) {
return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, type.health)
.add(Attributes.KNOCKBACK_RESISTANCE, 0.5F)
.add(Attributes.MOVEMENT_SPEED, 0.0D)
.add(Attributes.ATTACK_DAMAGE, 0.0D)
.add(Attributes.FOLLOW_RANGE, 0.0D);
}
public ItemStack getMachineItemWithData() {
ItemStack stack = new ItemStack(this.getMachineItem());
CompoundTag nbt = this.saveWithoutId(new CompoundTag());
nbt.remove("Pos");
nbt.remove("Motion");
nbt.remove("FallDistance");
nbt.remove("Fire");
nbt.remove("Air");
nbt.remove("OnGround");
nbt.remove("Invulnerable");
nbt.remove("PortalCooldown");
nbt.remove("UUID");
nbt.remove("Passengers");
nbt.remove("DelayTicks");
nbt.remove("UseTicks");
stack.addTagElement("EntityTag", nbt);
return stack;
}
@Override
public boolean isInvulnerableTo(DamageSource damagesource) {
return damagesource == DamageSource.CACTUS ||
damagesource == DamageSource.WITHER ||
damagesource == DamageSource.MAGIC ||
damagesource == DamageSource.DROWN ||
damagesource == DamageSource.STARVE ||
super.isInvulnerableTo(damagesource);
}
public float adjustDamage(DamageSource damagesource, float f) {
if (damagesource.isFire()) {
f *= 1.5f;
}
if (damagesource.isExplosion()) {
f *= 1.25f;
}
if (damagesource.isCreativePlayer()) {
f *= 2;
}
if (damagesource.getEntity() instanceof AbstractArrow) {
f *= 0.5f;
}
return f;
}
public abstract Item getMachineItem();
@Override
public void tick() {
if (this.deploymentticks > 0) {
this.deploymentticks--;
}
super.tick();
}
@Override
public boolean hurt(@NotNull DamageSource damagesource, float f) {
if (!net.minecraftforge.common.ForgeHooks.onLivingAttack(this, damagesource, f)) return false;
if (damagesource.getEntity() instanceof Player
&& !damagesource.isProjectile()
&& !damagesource.isExplosion()
&& !damagesource.isMagic()
&& this.getPassengers().isEmpty()) {
this.spawnAtLocation(this.getMachineItemWithData());
this.remove();
return false;
}
if (this.isInvulnerableTo(damagesource)) {
return false;
} else if (this.level.isClientSide) {
return false;
} else if (this.isDeadOrDying()) {
return false;
} else if (damagesource.isFire() && this.hasEffect(MobEffects.FIRE_RESISTANCE)) {
return false;
} else {
f = adjustDamage(damagesource, f);
this.noActionTime = 0;
this.animationSpeed = 1.5F;
boolean flag1 = true;
if ((float) this.invulnerableTime > 10.0F)
{
if (f <= this.lastHurt)
{
return false;
}
this.actuallyHurt(damagesource, f - this.lastHurt);
this.lastHurt = f;
flag1 = false;
}
else
{
this.lastHurt = f;
this.invulnerableTime = 20;
this.actuallyHurt(damagesource, f);
this.hurtDuration = 10;
this.hurtTime = this.hurtDuration;
}
this.hurtDir = 0.0F;
Entity entity1 = damagesource.getEntity();
if (entity1 != null)
{
if (entity1 instanceof LivingEntity)
{
this.setLastHurtByMob((LivingEntity) entity1);
}
if (entity1 instanceof Player)
{
this.lastHurtByPlayerTime = 1;
this.lastHurtByPlayer = (Player) entity1;
}
else if (entity1 instanceof TamableAnimal wolfEntity) {
if (wolfEntity.isTame()) {
this.lastHurtByPlayerTime = 100;
LivingEntity livingentity = wolfEntity.getOwner();
if (livingentity != null && livingentity.getType() == EntityType.PLAYER) {
this.lastHurtByPlayer = (Player) livingentity;
}
else {
this.lastHurtByPlayer = null;
}
}
}
}
if (flag1) {
if (damagesource instanceof EntityDamageSource && ((EntityDamageSource) damagesource).isThorns()) {
this.level.broadcastEntityEvent(this, (byte) 33);
}
else {
byte b0;
if (damagesource.isFire()) {
b0 = 37;
}
else if (damagesource == DamageSource.SWEET_BERRY_BUSH) {
b0 = 44;
}
else {
b0 = 2;
}
this.level.broadcastEntityEvent(this, b0);
}
this.markHurt();
if (entity1 != null)
{
double d1 = entity1.getX() - this.getX();
double d0;
for (d0 = entity1.getZ() - this.getZ(); d1 * d1 + d0 * d0 < 1.0E-4D; d0 = (Math.random() - Math.random()) * 0.01D)
{
d1 = (Math.random() - Math.random()) * 0.01D;
}
this.hurtDir = (float) (Mth.atan2(d0, d1) * (double) (180F / (float) Math.PI) - (double) this.getYRot());
}
else
{
this.hurtDir = (float) ((int) (Math.random() * 2.0D) * 180);
}
}
if (this.isDeadOrDying())
{
SoundEvent soundevent = this.getDeathSound();
if (flag1 && soundevent != null)
{
this.playSound(soundevent, this.getSoundVolume(), this.getVoicePitch());
}
this.die(damagesource);
}
else if (flag1)
{
this.playHurtSound(damagesource);
}
if (entity1 instanceof ServerPlayer)
{
CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer) entity1, this, damagesource, f, f, false);
}
return true;
}
}
@Override
@Nullable
protected SoundEvent getHurtSound(@NotNull DamageSource p_184601_1_)
{
return null;
}
@Override
@Nullable
protected SoundEvent getDeathSound()
{
return null;
}
@Override
public boolean removeWhenFarAway(double p_213397_1_)
{
return false;
}
@Nullable
@Override
public Entity getControllingPassenger()
{
return this.getPassengers().isEmpty() ? null : this.getPassengers().get(0);
}
@Override
public boolean canRiderInteract()
{
return true;
}
@Override
public void addAdditionalSaveData(@NotNull CompoundTag nbt)
{
super.addAdditionalSaveData(nbt);
ListTag listnbt = new ListTag();
for(ItemStack itemstack : this.inventory.items)
{
CompoundTag compoundnbt = new CompoundTag();
if (!itemstack.isEmpty())
{
itemstack.save(compoundnbt);
}
listnbt.add(compoundnbt);
}
nbt.put("Items", listnbt);
nbt.put("TurretRotations", this.newFloatList(this.turretpitch, this.turretyaw));
nbt.putInt("DealyTicks", this.delayticks);
nbt.putInt("UseTicks", this.useticks);
}
@Override
protected void dropCustomDeathLoot(DamageSource p_213333_1_, int p_213333_2_, boolean p_213333_3_)
{
super.dropCustomDeathLoot(p_213333_1_, p_213333_2_, p_213333_3_);
this.inventory.items.forEach(this::spawnAtLocation);
this.inventory.clearContent();
}
public void remove()
{
if (!this.dead)
{
this.dead = true;
this.level.broadcastEntityEvent(this, (byte)3);
}
super.remove(RemovalReason.DISCARDED);
}
@Override
@OnlyIn(Dist.CLIENT)
public void handleEntityEvent(byte b) {
switch (b) {
case 2, 33, 36, 37, 44 -> {
boolean flag1 = b == 33;
boolean flag2 = b == 36;
boolean flag3 = b == 37;
boolean flag = b == 44;
this.animationSpeed = 1.5F;
this.invulnerableTime = 20;
this.hurtDuration = 10;
this.hurtTime = this.hurtDuration;
this.hurtDir = 0.0F;
if (flag1) {
this.playSound(SoundEvents.THORNS_HIT, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
}
DamageSource damagesource;
if (flag3) {
damagesource = DamageSource.ON_FIRE;
} else if (flag2) {
damagesource = DamageSource.DROWN;
} else if (flag) {
damagesource = DamageSource.SWEET_BERRY_BUSH;
} else {
damagesource = DamageSource.GENERIC;
}
SoundEvent soundevent1 = this.getHurtSound(damagesource);
if (soundevent1 != null) {
this.playSound(soundevent1, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
}
this.hurt(DamageSource.GENERIC, 0.0F);
}
case 3 -> {
SoundEvent soundevent = this.getDeathSound();
if (soundevent != null) {
this.playSound(soundevent, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
}
this.setHealth(0.0F);
this.remove();
}
case 29, 30, 46 -> {
for (int j = 0; j < 128; ++j) {
double d0 = (double) j / 127.0D;
float f = (this.random.nextFloat() - 0.5F) * 0.2F;
float f1 = (this.random.nextFloat() - 0.5F) * 0.2F;
float f2 = (this.random.nextFloat() - 0.5F) * 0.2F;
double d1 = Mth.lerp(d0, this.xo, this.getX()) + (this.random.nextDouble() - 0.5D) * (double) this.getBbWidth() * 2.0D;
double d2 = Mth.lerp(d0, this.yo, this.getY()) + this.random.nextDouble() * (double) this.getBbHeight();
double d3 = Mth.lerp(d0, this.zo, this.getZ()) + (this.random.nextDouble() - 0.5D) * (double) this.getBbWidth() * 2.0D;
this.level.addParticle(ParticleTypes.PORTAL, d1, d2, d3, f, f1, f2);
}
}
case 54 -> HoneyBlock.showJumpParticles(this);
default -> super.handleEntityEvent(b);
}
}
@Override
public void readAdditionalSaveData(@NotNull CompoundTag nbt)
{
super.readAdditionalSaveData(nbt);
if (nbt.contains("Items", 9))
{
ListTag listnbt = nbt.getList("Items", 10);
for(int i = 0; i < this.inventory.items.size(); ++i)
{
this.inventory.items.set(i, ItemStack.of(listnbt.getCompound(i)));
}
}
if (nbt.contains("TurretRotations", 5))
{
ListTag turretrotations = nbt.getList("TurretRotations", 5);
setTurretRotations(turretrotations.getFloat(0), turretrotations.getFloat(1));
}
if (nbt.contains("DealyTicks"))
{
this.delayticks = nbt.getInt("DealyTicks");
}
if (nbt.contains("UseTicks"))
{
this.useticks = nbt.getInt("UseTicks");
}
}
public float getGlobalTurretYaw()
{
return Mth.lerp(0.5f, this.yRotO, this.getYRot()) + Mth.lerp(0.5f, this.turretyawprev, this.turretyaw);
}
public float getYaw()
{
return this.getYRot();
}
public void setYaw(float yaw)
{
this.setYRot(yaw);
this.yRotO = this.getYRot();
this.yBodyRot = this.getYRot();
this.yHeadRot = this.yBodyRot;
}
public float getYawDest()
{
return this.yawdest;
}
public void setYawDest(float yaw)
{
this.yawdest = yaw;
}
public float getTurretPitch(float f)
{
return Mth.lerp(f, this.turretpitchprev, this.turretpitch);
}
public float getTurretYaw(float f)
{
return Mth.lerp(f, this.turretyawprev, this.turretyaw);
}
public float getTurretPitch()
{
return this.getTurretPitch(0.5f);
}
public float getTurretYaw()
{
return this.getTurretYaw(0.5f);
}
public void setTurretRotations(float pitch, float yaw)
{
this.turretpitchprev = this.turretpitch;
this.turretyawprev = this.turretyaw;
this.turretpitch = pitch;
this.turretyaw = yaw;
}
public float getTurretPitchDest()
{
return this.turretpitchdest;
}
public float getTurretYawDest()
{
return this.turretyawdest;
}
public void setTurretRotationsDest(float pitch, float yaw)
{
this.turretpitchdest = pitch;
this.turretyawdest = yaw;
}
public void updateMachineRender()
{
if (!this.level.isClientSide())
{
PacketHandler.sendPacketToAllInArea(new PacketMachine(
this.getId(),
this.delayticks,
this.useticks,
this.turretpitch,
this.turretyaw), this.blockPosition(), SiegeMachines.RENDER_UPDATE_RANGE_SQR);
}
}
public void updateYaw()
{
float newyaw = this.turn(this.getYaw(), this.getYawDest(), this.type.rotationspeed);
if (this.getYaw() != newyaw)
this.setYaw(newyaw);
}
public void updateTurretRotations()
{
float newyaw = this.turn(this.getTurretYaw(), this.getTurretYawDest(), this.type.turretspeed, this.type.turretminyaw, this.type.turretmaxyaw);
boolean shouldrotate = this.checkYaw(newyaw, this.getTurretYaw(), this.type.turretspeed);
float newpitch = shouldrotate ? this.turn(this.getTurretPitch(), this.getTurretPitchDest(), this.type.turretspeed, this.type.turretminpitch, this.type.turretmaxpitch) : this.getTurretPitch();
if (this.turretpitch != newpitch || this.turretyaw != newyaw)
this.setTurretRotations(newpitch, newyaw);
}
public boolean checkYaw(float yaw, float currentYaw, float speed) {
return !this.type.yawfirst || Math.abs(yaw - currentYaw) <= speed / 2 || yaw <= this.type.turretminyaw || yaw >= this.type.turretmaxyaw;
}
public float turn(float rotation, float rotationDest, float speed) {
return this.turn(rotation, rotationDest, speed, -180, 180);
}
public float turn(float rotation, float rotationDest, float speed, float minRotation, float maxRotation)
{
boolean hasLimit = maxRotation - minRotation < 360;
float deltaRotation = rotationDest - rotation;
deltaRotation = Mth.wrapDegrees(deltaRotation);
float newRotation;
if (deltaRotation > speed / 2) {
newRotation = rotation + speed;
}
else if (deltaRotation < -speed / 2) {
newRotation = rotation - speed;
}
else {
newRotation = rotation + deltaRotation / 2;
}
if (hasLimit) {
if (newRotation > -minRotation) {
newRotation = -minRotation;
}
if (newRotation < -maxRotation) {
newRotation = -maxRotation;
}
}
return newRotation;
}
protected static Vec3 applyRotations(Vec3 vec, double pitch, double yaw) {
double d0 = vec.x * Math.cos(yaw) - vec.y * Math.sin(pitch) * Math.sin(yaw) - vec.z * Math.sin(yaw) * Math.cos(pitch);
double d1 = vec.y * Math.cos(pitch) - vec.z * Math.sin(pitch);
double d2 = vec.x * Math.sin(yaw) + vec.y * Math.sin(pitch) * Math.cos(yaw) + vec.z * Math.cos(yaw) * Math.cos(pitch);
return new Vec3(d0, d1, d2);
}
protected float getVolumeFromDist(float dist) {
return (float) 0.5 * Math.max((float) 6.0 - dist, 0.0f) / (float) 6.0;
}
public abstract void use(Player player);
public abstract void useRealise();
@Override
public MachineContainer createMenu(int id, @NotNull Inventory inv, @NotNull Player player) {
return new MachineContainer(id, inv, this);
}
public void openInventoryGui() {
Entity passenger = this.getControllingPassenger();
if (passenger instanceof ServerPlayer) {
this.stopRiding();
NetworkHooks.openScreen((ServerPlayer) passenger, this, this.blockPosition());
}
}
@Override
public Vec3 getDismountLocationForPassenger(LivingEntity entity) {
double yaw = (this.getGlobalTurretYaw()) * Math.PI / 180.0;
return this.position().add(applyRotations(this.type.passengerpos, 0.0, yaw));
}
@Override
public boolean shouldRiderSit() {
return false;
}
@Override
public void positionRider(@NotNull Entity entity) {
MoveFunction setPos = Entity::setPos;
if (this.hasPassenger(entity)) {
double yaw = (this.getGlobalTurretYaw()) * Math.PI / 180.0;
Vec3 pos = this.position().add(applyRotations(this.type.passengerpos, 0.0, yaw));
setPos.accept(entity, pos.x, pos.y, pos.z);
}
}
public static class MachineInventory implements Container, Nameable {
public NonNullList<ItemStack> items = NonNullList.withSize(9 * rows, ItemStack.EMPTY);
@Override
public int getContainerSize() {
return 9 * rows;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public @NotNull ItemStack getItem(int id) {
return this.items.get(id);
}
@Override
public @NotNull ItemStack removeItem(int id, int p_70298_2_) {
return this.items.set(id, ItemStack.EMPTY);
}
@Override
public @NotNull ItemStack removeItemNoUpdate(int id) {
return this.items.remove(id);
}
@Override
public void setItem(int id, @NotNull ItemStack item) {
this.items.set(id, item);
}
@Override
public void setChanged() {}
@Override
public boolean stillValid(@NotNull Player player)
{
return true;
}
@Override
public void clearContent() {
this.items = NonNullList.withSize(9 * rows, ItemStack.EMPTY);
}
public boolean containsItem(Item item) {
return this.items.stream().anyMatch(itemStack -> itemStack.getItem().equals(item));
}
public void putItem(Item item) {
for (int i = 0; i < this.items.size(); ++i) {
ItemStack itemstack = this.items.get(i);
if (itemstack.isEmpty()) {
this.items.set(i, new ItemStack(item));
break;
}
if (itemstack.getItem().equals(item) && itemstack.getCount() < itemstack.getMaxStackSize()) {
itemstack.setCount(itemstack.getCount() + 1);
break;
}
}
}
public void shrinkItem(Item item) {
for (ItemStack itemstack : this.items) {
if (itemstack.getItem().equals(item)) {
itemstack.shrink(1);
break;
}
}
}
@Override
public Component getName() {
return this.getName();
}
}
}

View File

@@ -0,0 +1,50 @@
package ru.magistu.siegemachines.entity.machine;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.Pose;
import org.jetbrains.annotations.NotNull;
public class MachinePartEntity extends net.minecraftforge.entity.PartEntity<Machine>
{
public final Machine parentmob;
public final String name;
private final EntityDimensions size;
public MachinePartEntity(Machine parent, String name, float width, float height)
{
super(parent);
this.size = EntityDimensions.scalable(width, height);
this.refreshDimensions();
this.parentmob = parent;
this.name = name;
}
@Override
protected void defineSynchedData() {}
@Override
protected void readAdditionalSaveData(@NotNull CompoundTag p_70037_1_) {}
@Override
protected void addAdditionalSaveData(@NotNull CompoundTag p_213281_1_) {}
public boolean hurt(@NotNull DamageSource source, float value) {
return !this.isInvulnerableTo(source) && this.parentmob.hurt(source, value);
}
public boolean is(@NotNull Entity entity) {
return this == entity || this.parentmob == entity;
}
public Packet<?> getAddEntityPacket() {
throw new UnsupportedOperationException();
}
public @NotNull EntityDimensions getDimensions(@NotNull Pose pose) {
return this.size;
}
}

View File

@@ -0,0 +1,87 @@
package ru.magistu.siegemachines.entity.machine;
import ru.magistu.siegemachines.entity.projectile.ProjectileBuilder;
import net.minecraft.world.phys.Vec3;
public enum MachineType {
MORTAR(80, 1, 0.0f, 85.0f, 0.0f, 0.0f, 0.5f, 0.5f, true, 10, 10, 200,
new Vec3(17.0, 0.0, -10.0).scale(1 / 16.0), new Vec3(0.0, 17.0, 7.0).scale(1 / 16.0), new Vec3(0.0, 0.0, 12.0).scale(1 / 16.0),
2.5f, 0.2f, ProjectileBuilder.CANNON_AMMO, true),
CULVERIN(80, 1, 0.0f, 85.0f, 0.0f, 0.0f, 0.5f, 0.5f, true, 10, 10, 200,
new Vec3(30.0, 0.0, -40.0).scale(1 / 16.0), new Vec3(0.0, 17.0, 7.0).scale(1 / 16.0), new Vec3(0.0, 0.0, 12.0).scale(1 / 16.0),
3.0f, 0.2f, ProjectileBuilder.CANNON_AMMO, true),
TREBUCHET(300, 1, -45.0f, 75.0f, 0.0f, 0.0f, 0.1f, 0.5f, true, 38, 137, 400,
new Vec3(40.0, 0.0, -60.0).scale(1 / 16.0), new Vec3(0.0, 19.0, -3.0), new Vec3(0.0, 10.0, -1.0),
2.8f, 0.2f, ProjectileBuilder.THROWING_AMMO, false),
CATAPULT(100, 1, 0.0f, 75.0f, 0.0f, 0.0f, 0.2f, 1.0f, true, 2, 10, 200,
new Vec3(30.0, 0.0, -40.0).scale(1 / 16.0), new Vec3(0.0, 51.0, -5.0).scale(1 / 16.0), new Vec3(0.0, 0.0, 0.0),
2.0f, 0.2f, ProjectileBuilder.THROWING_AMMO, false),
BALLISTA(50, 1, -30.0f, 60.0f, -180.0f, 180.0f, 4.5f, 0.0f, false, 1, 20, 120,
new Vec3(0.0, 0.0, -30.0).scale(1 / 16.0), new Vec3(0.0, 22.5, 0.0).scale(1 / 16.0), new Vec3(0.0, 0.0, 17.0).scale(1 / 16.0),
4.5f, 0.04f, ProjectileBuilder.BALLISTA_AMMO, false),
BATTERING_RAM(250, 1, 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 0.0f, false, 5, 5, 100,
new Vec3(12.0, 0.0, -48.0).scale(1 / 16.0), new Vec3(0.0, 26.0, 36.0).scale(1 / 16.0), new Vec3(0.0, 0.0, 32.0).scale(1 / 16.0),
0.0f, 0.5f, ProjectileBuilder.NO_AMMO, false);
public final int health;
public final int rows;
public final float turretminpitch;
public final float turretmaxpitch;
public final float turretminyaw;
public final float turretmaxyaw;
public final float rotationspeed;
public final float turretspeed;
public final boolean yawfirst;
public final int userealisetime;
public final int usetime;
public final int delaytime;
public final Vec3 passengerpos;
public final Vec3 turretpivot;
public final Vec3 turretvector;
public final float projectilespeed;
public final float inaccuracy;
public final ProjectileBuilder[] ammo;
public final boolean usesgunpowder;
MachineType(
int health,
int rows,
float turretminpitch,
float turretmaxpitch,
float turretminyaw,
float turretmaxyaw,
float rotationspeed,
float turretspeed,
boolean yawfirst,
int shootingtime,
int usetime,
int delaytime,
Vec3 passengerpos,
Vec3 turretpivot,
Vec3 turretvector,
float projectilespeed,
float inaccuracy,
ProjectileBuilder[] ammo,
boolean usesgunpowder)
{
this.health = health;
this.rows = rows;
this.turretminpitch = turretminpitch;
this.turretmaxpitch = turretmaxpitch;
this.turretminyaw = turretminyaw;
this.turretmaxyaw = turretmaxyaw;
this.rotationspeed = rotationspeed;
this.turretspeed = turretspeed;
this.yawfirst = yawfirst;
this.userealisetime = shootingtime;
this.usetime = usetime;
this.delaytime = delaytime;
this.passengerpos = passengerpos;
this.turretpivot = turretpivot;
this.turretvector = turretvector;
this.projectilespeed = projectilespeed;
this.inaccuracy = inaccuracy;
this.ammo = ammo;
this.usesgunpowder = usesgunpowder;
}
}

View File

@@ -0,0 +1,275 @@
package ru.magistu.siegemachines.entity.machine;
import ru.magistu.siegemachines.SiegeMachines;
import ru.magistu.siegemachines.client.SoundTypes;
import ru.magistu.siegemachines.entity.IReloading;
import ru.magistu.siegemachines.gui.machine.crosshair.Crosshair;
import ru.magistu.siegemachines.gui.machine.crosshair.ReloadingCrosshair;
import ru.magistu.siegemachines.item.ModItems;
import net.minecraft.ChatFormatting;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
import software.bernie.geckolib3.core.builder.AnimationBuilder;
import software.bernie.geckolib3.core.builder.ILoopType;
import software.bernie.geckolib3.core.controller.AnimationController;
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
import software.bernie.geckolib3.core.manager.AnimationData;
import software.bernie.geckolib3.core.manager.AnimationFactory;
import software.bernie.geckolib3.util.GeckoLibUtil;
public class Mortar extends ShootingMachine implements IAnimatable, IReloading
{
private final AnimationFactory factory = GeckoLibUtil.createFactory(this);
static AnimationBuilder MOVING_ANIM = new AnimationBuilder().addAnimation("Moving", ILoopType.EDefaultLoopTypes.LOOP);
public int shootingticks = 0;
private double wheelspitch = 0.0;
private double wheelsspeed = 0.0;
private int wheelssoundticks = 10;
public Mortar(EntityType<? extends Mob> entitytype, Level level)
{
super(entitytype, level, MachineType.MORTAR);
}
private <E extends IAnimatable> PlayState wheels_predicate(AnimationEvent<E> event)
{
event.getController().setAnimation(MOVING_ANIM);
return PlayState.CONTINUE;
}
@Override
public void registerControllers(AnimationData data)
{
AnimationController<?> wheels_controller = new AnimationController<>(this, "wheels_controller", 1, (t) -> {
double d = this.getWheelsSpeed();
this.wheelsspeed = d > 0 ? Math.min(d, 1.0) : Math.max(d, -1.0);
return wheelspitch += 0.013 * this.wheelsspeed;
}, this::wheels_predicate);
data.addAnimationController(wheels_controller);
}
@Override
public AnimationFactory getFactory()
{
return this.factory;
}
@Override
protected InteractionResult mobInteract(Player player, InteractionHand hand)
{
ItemStack stack = player.getItemInHand(hand);
if (stack.getItem().equals(Items.FLINT_AND_STEEL))
{
if (this.useticks <= 0 && this.shootingticks <= 0)
{
stack.hurtAndBreak(1, player, (p_213833_1_) ->
{
p_213833_1_.broadcastBreakEvent(hand);
net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(player, this.useItem, hand);
});
this.startShooting(player);
}
return InteractionResult.SUCCESS;
}
if (stack.getItem().equals(Items.GUNPOWDER))
{
if (!this.inventory.containsItem(Items.GUNPOWDER))
{
if (!player.isCreative())
{
stack.shrink(1);
}
this.inventory.putItem(Items.GUNPOWDER);
}
return InteractionResult.SUCCESS;
}
if (super.mobInteract(player, hand) == InteractionResult.SUCCESS)
{
return InteractionResult.SUCCESS;
}
if (!this.level.isClientSide() && !this.isVehicle())
{
player.startRiding(this);
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
@Override
public void travel(Vec3 pos)
{
if (this.isAlive())
{
if (this.isVehicle())
{
LivingEntity livingentity = (LivingEntity) this.getControllingPassenger();
this.setTurretRotationsDest(livingentity.getXRot(), livingentity.getYRot() - this.getYaw());
this.setYawDest(livingentity.getYRot());
this.updateYaw();
this.updateTurretRotations();
float f0 = livingentity.xxa * 0.2f;
float f1 = livingentity.zza;
if (f1 <= 0.0f)
{
f1 *= 0.5f;
}
this.setSpeed(0.04f);
pos = new Vec3(f0, pos.y, f1);
}
super.travel(pos);
}
}
@Override
public void tick()
{
if (this.useticks != 0 && --this.useticks <= 0)
{
this.useticks = 0;
this.delayticks = this.type.delaytime;
}
if (this.shootingticks != 0 && --this.shootingticks <= 0)
{
if (this.inventory.containsItem(Items.GUNPOWDER))
{
this.useRealise();
}
else if (!this.level.isClientSide())
{
Entity passenger = this.getControllingPassenger();
if (passenger instanceof Player)
{
passenger.sendSystemMessage(Component.translatable(SiegeMachines.ID + ".no_gunpowder").withStyle(ChatFormatting.RED));
}
}
this.shootingticks = 0;
}
if (!level.isClientSide() && this.isOnGround())
{
this.setDeltaMovement(this.getWheelsDeltaMovement());
}
if (this.delayticks > 0 && this.isVehicle())
{
--this.delayticks;
}
if (this.renderupdateticks-- <= 0)
{
this.updateMachineRender();
this.renderupdateticks = SiegeMachines.RENDER_UPDATE_TIME;
}
if (this.getWheelsSpeed() > 0.0081 && this.wheelssoundticks-- <= 0)
{
this.level.playLocalSound(this.getX(), this.getY(), this.getZ(), SoundTypes.CANNON_WHEELS.get(), SoundSource.NEUTRAL, 0.3f, 1.0f, true);
this.wheelssoundticks = 20;
}
super.tick();
}
@Override
public void startShooting(Player player)
{
if (this.delayticks <= 0 && this.useticks <= 0 && this.shootingticks <= 0)
{
if (!this.level.isClientSide())
{
this.level.playSound(null, this.getX(), this.getY(), this.getZ(), SoundTypes.FUSE.get(), SoundSource.BLOCKS, this.getVolumeFromDist(this.distanceTo(player)), 0.8f);
}
this.useticks = this.type.usetime;
this.shootingticks = this.type.userealisetime;
}
}
@Override
public void shoot()
{
if (!level.isClientSide())
{
super.shoot();
this.setDeltaMovement(this.getDeltaMovement().subtract(this.getShotView().scale(0.25)));
this.hasImpulse = true;
this.inventory.shrinkItem(Items.GUNPOWDER);
}
else
{
this.blowParticles(ParticleTypes.FLAME, 0.035, 25);
this.blowParticles(ParticleTypes.CLOUD, 0.2, 60);
Vec3 pos = this.position();
this.level.playLocalSound(pos.x, pos.y, pos.z, SoundTypes.MORTAR_SHOOTING.get(), SoundSource.BLOCKS, 1.5f/*this.getVolumeFromDist(1.5f, 64.0f, this.distanceTo(player))*/, 0.85f + this.level.random.nextFloat() * 0.3f, false);
}
}
public double getWheelsSpeed()
{
if (this.isOnGround())
{
return this.getViewVector(5.0f).multiply(1, 0, 1).dot(this.getDeltaMovement());
}
return 0.0;
}
public Vec3 getWheelsDeltaMovement()
{
if (this.isOnGround())
{
Vec3 view = this.getViewVector(1.0f);
Vec3 movement = this.getDeltaMovement();
double d0 = movement.x * view.x + movement.z * view.z;
double d1 = d0 * view.x;
double d2 = 0.0;
double d3 = d0 * view.z;
return new Vec3(d1, d2, d3);
}
return Vec3.ZERO;
}
@Override
@OnlyIn(Dist.CLIENT)
public Crosshair createCrosshair()
{
return new ReloadingCrosshair();
}
@Override
public Item getMachineItem()
{
return ModItems.MORTAR.get();
}
}

View File

@@ -0,0 +1,190 @@
package ru.magistu.siegemachines.entity.machine;
import com.mojang.math.Vector3d;
import ru.magistu.siegemachines.SiegeMachines;
import ru.magistu.siegemachines.entity.IReloading;
import ru.magistu.siegemachines.entity.projectile.Missile;
import ru.magistu.siegemachines.entity.projectile.ProjectileBuilder;
import ru.magistu.siegemachines.network.*;
import net.minecraft.ChatFormatting;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import java.util.Arrays;
import java.util.Random;
public abstract class ShootingMachine extends Machine implements IReloading
{
public int shootingticks = 0;
protected ShootingMachine(EntityType<? extends Mob> entitytype, Level level, MachineType type)
{
super(entitytype, level, type);
}
public abstract void startShooting(Player player);
public void shoot()
{
if (this.type.ammo.length == 0)
{
return;
}
ProjectileBuilder projectilebuilder = this.getProjectileBuilder();
if (projectilebuilder.equals(ProjectileBuilder.NONE))
{
Entity passenger = this.getControllingPassenger();
if (passenger instanceof Player)
{
passenger.sendSystemMessage(Component.translatable(SiegeMachines.ID + ".no_ammo").withStyle(ChatFormatting.RED));
}
return;
}
LivingEntity livingentity = (LivingEntity) this.getControllingPassenger();
Projectile projectile = projectilebuilder.factory.create(projectilebuilder.entitytype, this.level, new Vector3d(this.getShotPos().x, this.getShotPos().y, this.getShotPos().z), livingentity == null ? this : livingentity, projectilebuilder.projectilitem);
if (projectile instanceof Missile)
{
Missile missile = (Missile) projectile;
missile.setItem(new ItemStack(missile.getDefaultItem()));
}
projectile.shootFromRotation(this, this.getTurretPitch(), this.getGlobalTurretYaw(), 0.0f, this.type.projectilespeed, this.type.inaccuracy);
this.level.addFreshEntity(projectile);
this.inventory.shrinkItem(projectilebuilder.item);
}
@Override
public void use(Player player)
{
if (!this.level.isClientSide())
{
PacketHandler.sendPacketToAllInArea(new PacketMachineUse(this.getId()), this.blockPosition(), SiegeMachines.RENDER_UPDATE_RANGE_SQR);
}
this.startShooting(player);
}
@Override
public void useRealise()
{
if (!this.level.isClientSide())
{
PacketHandler.sendPacketToAllInArea(new PacketMachineUseRealise(this.getId()), this.blockPosition(), SiegeMachines.RENDER_UPDATE_RANGE_SQR);
}
this.shoot();
}
@Override
protected InteractionResult mobInteract(Player player, InteractionHand hand)
{
ItemStack stack = player.getItemInHand(hand);
if (this.isValidAmmo(stack))
{
if (!this.hasAmmo())
{
if (!player.isCreative())
{
stack.shrink(1);
}
this.inventory.putItem(stack.getItem());
}
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
protected Vec3 getShotPos()
{
double pitch = this.getTurretPitch() * Math.PI / 180.0;
double yaw = (this.getViewYRot(0.5f) + this.getTurretYaw()) * Math.PI / 180.0;
return this.position().add(applyRotations(this.type.turretpivot, 0.0, yaw).add(applyRotations(this.type.turretvector, pitch, yaw)));
}
protected Vec3 getShotView()
{
double pitch = this.getTurretPitch() * Math.PI / 180.0;
double yaw = this.getGlobalTurretYaw() * Math.PI / 180.0;
double d0 = -Math.sin(yaw) * Math.cos(pitch);
double d1 = -Math.sin(pitch);
double d2 = Math.cos(yaw) * Math.cos(pitch);
return new Vec3(d0, d1, d2).normalize();
}
protected void blowParticles(ParticleOptions particle, double speed, int amount)
{
for (int i = 0; i < amount; ++i)
{
Vec3 pos = this.getShotPos();
Vec3 inaccuracy = new Vec3(new Random().nextGaussian() * 0.2,
new Random().nextGaussian() * 0.2,
new Random().nextGaussian() * 0.2);
Vec3 velocity = this.getShotView().add(inaccuracy).scale(speed);
this.level.addParticle(particle, pos.x, pos.y, pos.z, velocity.x, velocity.y, velocity.z);
}
}
@Override
public void updateMachineRender()
{
super.updateMachineRender();
if (!this.level.isClientSide())
{
for (int i = 0; i < rows * 9; ++i)
{
if (this.isValidAmmo(this.inventory.getItem(i)))
{
PacketHandler.sendPacketToAllInArea(
new PacketMachineInventorySlot(this.getId(), i, this.inventory.getItem(i)),
this.blockPosition(),
SiegeMachines.RENDER_UPDATE_RANGE_SQR);
}
}
}
}
public boolean isValidAmmo(ItemStack stack)
{
return this.isValidAmmo(stack.getItem());
}
public boolean isValidAmmo(Item entry)
{
return Arrays.stream(this.type.ammo).anyMatch(builder -> builder.item.equals(entry));
}
public ItemStack getAmmo()
{
return this.inventory.items.stream().filter(this::isValidAmmo).findFirst().orElse(ItemStack.EMPTY);
}
public boolean hasAmmo()
{
return this.inventory.items.stream().anyMatch(this::isValidAmmo);
}
public ProjectileBuilder getProjectileBuilder()
{
ItemStack ammo = this.getAmmo();
if (ammo.equals(ItemStack.EMPTY))
{
return ProjectileBuilder.NONE;
}
return Arrays.stream(this.type.ammo).filter(builder -> builder.item.equals(ammo.getItem())).findFirst().orElse(ProjectileBuilder.NONE);
}
}

View File

@@ -0,0 +1,261 @@
package ru.magistu.siegemachines.entity.machine;
import ru.magistu.siegemachines.SiegeMachines;
import ru.magistu.siegemachines.client.SoundTypes;
import ru.magistu.siegemachines.gui.machine.crosshair.Crosshair;
import ru.magistu.siegemachines.gui.machine.crosshair.ReloadingCrosshair;
import ru.magistu.siegemachines.item.ModItems;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
import software.bernie.geckolib3.core.builder.AnimationBuilder;
import software.bernie.geckolib3.core.builder.ILoopType;
import software.bernie.geckolib3.core.controller.AnimationController;
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
import software.bernie.geckolib3.core.manager.AnimationData;
import software.bernie.geckolib3.core.manager.AnimationFactory;
import software.bernie.geckolib3.util.GeckoLibUtil;
public class Trebuchet extends ShootingMachine implements IAnimatable
{
private final AnimationFactory factory = GeckoLibUtil.createFactory(this);
static AnimationBuilder SHOOTING_ANIM = new AnimationBuilder().addAnimation("Shooting", ILoopType.EDefaultLoopTypes.LOOP);
static AnimationBuilder RELOADING_ANIM = new AnimationBuilder().addAnimation("Reloading", ILoopType.EDefaultLoopTypes.LOOP);
static AnimationBuilder IDLE_RELOADED_ANIM = new AnimationBuilder().addAnimation("IdleReloaded", ILoopType.EDefaultLoopTypes.LOOP);
static AnimationBuilder IDLE_NOT_RELOADED_ANIM = new AnimationBuilder().addAnimation("IdleNotReloaded", ILoopType.EDefaultLoopTypes.LOOP);
private final MachinePartEntity[] subentities;
private final MachinePartEntity backside;
private final Vec3 backsidepos;
public enum State
{
SHOOTING,
RELOADING,
IDLE_RELOADED,
IDLE_NOT_RELOADED
}
public State state = State.RELOADING;
public Trebuchet(EntityType<? extends Mob> entitytype, Level level)
{
super(entitytype, level, MachineType.TREBUCHET);
this.backside = new MachinePartEntity(this, "backside", 5.0F, 2.0F);
this.backsidepos = new Vec3(0.0, 0.0, -85.0).scale(1.0 / 16.0);
this.subentities = new MachinePartEntity[] { this.backside };
}
private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event)
{
switch (state) {
case SHOOTING -> {
event.getController().setAnimation(SHOOTING_ANIM);
return PlayState.CONTINUE;
}
case IDLE_RELOADED -> {
event.getController().setAnimation(IDLE_RELOADED_ANIM);
return PlayState.CONTINUE;
}
case RELOADING -> {
event.getController().setAnimation(RELOADING_ANIM);
return PlayState.CONTINUE;
}
case IDLE_NOT_RELOADED -> {
event.getController().setAnimation(IDLE_NOT_RELOADED_ANIM);
return PlayState.CONTINUE;
}
}
return PlayState.CONTINUE;
}
private void tickPart(MachinePartEntity subentity, double p_226526_2_, double p_226526_4_, double p_226526_6_)
{
subentity.setPos(this.getX() + p_226526_2_, this.getY() + p_226526_4_, this.getZ() + p_226526_6_);
}
@Override
public void aiStep()
{
Vec3[] avector3d = new Vec3[this.subentities.length];
Vec3 pos = this.position().add(applyRotations(this.backsidepos, 0.0, this.getYaw()));
this.tickPart(this.backside, pos.x, pos.y, pos.z);
for(int i = 0; i < this.subentities.length; ++i)
{
avector3d[i] = new Vec3(this.subentities[i].getX(), this.subentities[i].getY(), this.subentities[i].getZ());
}
for(int i = 0; i < this.subentities.length; ++i)
{
this.subentities[i].xo = avector3d[i].x;
this.subentities[i].yo = avector3d[i].y;
this.subentities[i].zo = avector3d[i].z;
this.subentities[i].xOld = avector3d[i].x;
this.subentities[i].yOld = avector3d[i].y;
this.subentities[i].zOld = avector3d[i].z;
}
super.aiStep();
}
public MachinePartEntity[] getSubEntities() {
return this.subentities;
}
@Override
public net.minecraftforge.entity.PartEntity<?>[] getParts()
{
return this.subentities;
}
@Override
public void registerControllers(AnimationData data)
{
AnimationController<?> controller = new AnimationController<>(this, "controller", 1, (t) ->
{
if (this.state.equals(State.RELOADING))
{
return (double) (this.type.delaytime - this.delayticks) / this.type.delaytime;
}
return t;
}, this::predicate);
data.addAnimationController(controller);
}
@Override
public AnimationFactory getFactory()
{
return this.factory;
}
@Override
protected InteractionResult mobInteract(Player player, InteractionHand hand)
{
ItemStack stack = player.getItemInHand(hand);
if (super.mobInteract(player, hand) == InteractionResult.SUCCESS)
{
return InteractionResult.SUCCESS;
}
if (!this.level.isClientSide() && !this.isVehicle())
{
player.startRiding(this);
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
public void startShooting(Player player)
{
if (this.delayticks <= 0 && this.useticks <= 0 && this.shootingticks <= 0)
{
this.state = State.SHOOTING;
this.useticks = this.type.usetime;
this.shootingticks = this.type.userealisetime;
Vec3 pos = this.position();
this.level.playLocalSound(pos.x, pos.y, pos.z, SoundTypes.TREBUCHET_SHOOTING.get(), SoundSource.BLOCKS, 1.0f, 1.0f, false);
}
}
@Override
public void shoot()
{
if (!level.isClientSide())
{
super.shoot();
}
}
@Override
public void travel(Vec3 pos)
{
if (this.isAlive())
{
if (this.isVehicle() && this.useticks <= 0 && this.delayticks <= 0)
{
LivingEntity livingentity = (LivingEntity) this.getControllingPassenger();
this.setTurretRotations(livingentity.getXRot(), this.getTurretYaw());
this.updateTurretRotations();
this.setYawDest(livingentity.getYRot());
this.updateYaw();
}
super.travel(pos);
}
}
@Override
public void tick()
{
if (this.useticks != 0 && --this.useticks <= 0)
{
this.state = State.RELOADING;
this.useticks = 0;
this.delayticks = this.type.delaytime;
}
if (this.shootingticks != 0 && --this.shootingticks <= 0)
{
this.useRealise();
this.shootingticks = 0;
}
if (!level.isClientSide() && this.isOnGround())
{
this.setDeltaMovement(this.getDeltaMovement().multiply(0.0, 1.0, 0.0));
}
if (this.delayticks > 0 && this.isVehicle())
{
if (this.delayticks % 40 == 0)
{
Vec3 pos = this.position();
this.level.playLocalSound(pos.x, pos.y, pos.z, SoundTypes.TREBUCHET_RELOADING.get(), SoundSource.BLOCKS, 1.0f, 1.0f, false);
}
if (--this.delayticks <= 0)
{
this.state = State.IDLE_RELOADED;
}
}
if (this.renderupdateticks-- <= 0)
{
this.updateMachineRender();
this.renderupdateticks = SiegeMachines.RENDER_UPDATE_TIME;
}
super.tick();
}
@Override
@OnlyIn(Dist.CLIENT)
public Crosshair createCrosshair()
{
return new ReloadingCrosshair();
}
@Override
public Item getMachineItem()
{
return ModItems.TREBUCHET.get();
}
}

View File

@@ -0,0 +1,22 @@
package ru.magistu.siegemachines.entity.projectile;
import com.mojang.math.Vector3d;
import ru.magistu.siegemachines.item.ModItems;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
public class Cannonball extends Missile
{
public Cannonball(EntityType<Cannonball> type, Level level)
{
super(type, level);
this.item = ModItems.CANNONBALL.get();
}
public Cannonball(EntityType<Stone> entitytype, Level level, Vector3d pos, LivingEntity entity, Item item)
{
super(entitytype, level, pos, entity, MissileType.CANNONBALL, item);
}
}

View File

@@ -0,0 +1,8 @@
package ru.magistu.siegemachines.entity.projectile;
public enum FlightType
{
NONE,
AHEAD,
SPINNING
}

View File

@@ -0,0 +1,42 @@
package ru.magistu.siegemachines.entity.projectile;
import com.mojang.math.Vector3d;
import ru.magistu.siegemachines.item.ModItems;
import net.minecraft.network.protocol.Packet;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraftforge.network.NetworkHooks;
import org.jetbrains.annotations.NotNull;
public class GiantArrow extends AbstractArrow
{
private final Packet<?> spawningpacket = NetworkHooks.getEntitySpawningPacket(this);
public GiantArrow(EntityType<GiantArrow> type, Level level)
{
super(type, level);
}
public GiantArrow(EntityType<GiantArrow> entitytype, Level level, Vector3d pos, LivingEntity entity, Item item)
{
super(entitytype, entity, level);
this.setPos(pos.x, pos.y, pos.z);
this.setBaseDamage(5.0F);
}
@Override
protected @NotNull ItemStack getPickupItem()
{
return new ItemStack(ModItems.GIANT_ARROW.get());
}
@Override
public @NotNull Packet<?> getAddEntityPacket()
{
return spawningpacket;
}
}

View File

@@ -0,0 +1,13 @@
package ru.magistu.siegemachines.entity.projectile;
import com.mojang.math.Vector3d;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
public interface IProjectileFactory<T extends Projectile>
{
T create(EntityType<T> entitytype, Level level, Vector3d pos, LivingEntity entity, Item item);
}

View File

@@ -0,0 +1,200 @@
package ru.magistu.siegemachines.entity.projectile;
import com.mojang.math.Vector3d;
import ru.magistu.siegemachines.item.ModItems;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.BlockParticleOption;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.network.protocol.Packet;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.damagesource.CombatRules;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.ThrowableItemProjectile;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.ShieldItem;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.network.NetworkHooks;
import org.jetbrains.annotations.NotNull;
public abstract class Missile extends ThrowableItemProjectile
{
public MissileType type = MissileType.STONE;
public Item item = ModItems.STONE.get();
public Missile(EntityType<? extends Missile> entitytype, Level level)
{
super(entitytype, level);
}
public Missile(EntityType<? extends Missile> entitytype, Level level, Vector3d pos, LivingEntity entity, MissileType type, Item item)
{
super(entitytype, entity, level);
this.type = type;
this.item = item;
this.setPos(pos.x, pos.y, pos.z);
}
@Override
public @NotNull Item getDefaultItem()
{
return this.item;
}
@Override
public @NotNull Packet<?> getAddEntityPacket()
{
return NetworkHooks.getEntitySpawningPacket(this);
}
@Override
public void onHit(HitResult result)
{
float f = 2.0F;
if (result.getType() == HitResult.Type.ENTITY)
{
EntityHitResult entityRTR = (EntityHitResult)result;
Vec3 pos = entityRTR.getLocation();
Entity entity = entityRTR.getEntity();
float damage = this.type.mass * (float) this.getDeltaMovement().length();
DamageSource damagesource = DamageSource.thrown(this, this.getOwner());
if (this.type.armorpiercing >= 1.0f)
{
damagesource = damagesource.bypassArmor();
}
else if (this.type.armorpiercing > 0.0f && entity instanceof LivingEntity livingentity)
{
if(livingentity instanceof Player player) {
if(player.isBlocking() && (item == ModItems.GIANT_ARROW.get() || item == Items.ARROW) && (player.getItemInHand(InteractionHand.MAIN_HAND).getItem() instanceof ShieldItem || player.isBlocking() && player.getItemInHand(InteractionHand.OFF_HAND).getItem() instanceof ShieldItem)) {
return;
}
}
damage -= (1.0f - this.type.armorpiercing) * (damage - CombatRules.getDamageAfterAbsorb(damage, 0, 0));
damagesource = damagesource.bypassArmor();
}
if (!this.level.isClientSide() && this.type.explosive)
{
this.level.explode(this.getOwner(), pos.x, pos.y, pos.z, 3.0F, Explosion.BlockInteraction.NONE);
this.remove(RemovalReason.KILLED);
}
entity.hurt(damagesource, damage);
Vec3 vector3d = this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D).normalize().scale((double) this.type.knockback * 0.6D);
if (vector3d.lengthSqr() > 0.0D)
{
entity.push(vector3d.x, 0.1D, vector3d.z);
}
}
if (result.getType() == HitResult.Type.BLOCK)
{
BlockHitResult blockRTR = (BlockHitResult)result;
BlockPos blockpos = blockRTR.getBlockPos();
BlockState blockstate = this.level.getBlockState(blockpos);
boolean smoothimpact = (blockstate == Blocks.SAND.defaultBlockState() ||
blockstate == Blocks.RED_SAND.defaultBlockState() ||
blockstate == Blocks.DIRT.defaultBlockState() ||
blockstate == Blocks.GRASS_BLOCK.defaultBlockState() ||
blockstate == Blocks.DIRT_PATH.defaultBlockState() ||
blockstate == Blocks.COARSE_DIRT.defaultBlockState() ||
blockstate == Blocks.SNOW_BLOCK.defaultBlockState()) &&
blockRTR.getDirection() == Direction.UP;
if (blockRTR.getDirection() == Direction.UP)
{
if (this.type.explosive)
{
for (int r = 0; r < this.type.explosionradius; ++r)
{
for (float a = 0; a < 2 * Math.PI; a += Math.PI / 4)
{
BlockPos pos = blockRTR.getBlockPos().offset(r * Math.cos(a), 0, -r * Math.sin(a));
if (this.level.getBlockState(pos) == Blocks.GRASS_BLOCK.defaultBlockState())
{
this.level.setBlockAndUpdate(pos, Blocks.DIRT.defaultBlockState());
}
}
}
}
if (!this.level.isClientSide())
{
this.remove(RemovalReason.KILLED);
if (smoothimpact && this.type.explosive)
{
this.level.explode(this.getOwner(), blockpos.getX(), blockpos.getY(), blockpos.getZ(), this.type.explosionradius * f, Explosion.BlockInteraction.NONE);
}
}
else if (smoothimpact)
{
this.dustExplosion(new BlockParticleOption(ParticleTypes.BLOCK, blockstate).setPos(blockpos), blockpos, this.type.explosionradius / 2, 50);
}
}
if (!this.level.isClientSide() && !smoothimpact && this.type.explosive)
{
this.level.explode(this.getOwner(), blockpos.getX(), blockpos.getY(), blockpos.getZ(), this.type.explosionradius * f, Explosion.BlockInteraction.BREAK);
}
}
if (result.getType() == HitResult.Type.MISS)
{
this.level.playSound((Player)this.getOwner(), this.getOnPos(), SoundEvents.ANVIL_BREAK, SoundSource.AMBIENT, 1.0f, 1.0f);
if(!this.level.isClientSide())
{
this.remove(RemovalReason.KILLED);
}
}
if (!this.level.isClientSide())
{
this.remove(RemovalReason.KILLED);
}
}
private void dustExplosion(ParticleOptions particle, BlockPos blockpos, double speed, int amount)
{
this.dustExplosion(particle, blockpos.getX(), blockpos.getY(), blockpos.getZ(), speed, amount);
}
private void dustExplosion(ParticleOptions particle, double x, double y, double z, double speed, int amount)
{
for (int i = 0; i < amount; ++i)
{
Vec3 movement = this.getDeltaMovement();
double d0 = x - 0.05 + this.level.random.nextDouble() * 0.3;
double d1 = y + 1.0;
double d2 = z - 0.05 + this.level.random.nextDouble() * 0.3;
double d3 = movement.x * this.level.random.nextDouble() * speed;
double d4 = -movement.y * this.level.random.nextDouble() * speed * 10.0f;
double d5 = movement.z * this.level.random.nextDouble() * speed;
this.level.addParticle(particle, d0, d1, d2, d3, d4, d5);
}
}
@Override
public void tick()
{
if (this.type.flighttype == FlightType.SPINNING)
{
this.setXRot(this.getXRot() + 0.5f);
}
super.tick();
}
}

View File

@@ -0,0 +1,25 @@
package ru.magistu.siegemachines.entity.projectile;
public enum MissileType
{
CANNONBALL(15.0f, 1.5f, true, 3.0f, FlightType.SPINNING, 1.0f),
STONE(50.0f, 1.5f, true, 3.0f, FlightType.SPINNING, 1.0f),
GIANT_ARROW(5.0f, 1.5f, false, 0.0f, FlightType.AHEAD, 0.5f);
public final float mass;
public final float knockback;
public final boolean explosive;
public final float explosionradius;
public final FlightType flighttype;
public final float armorpiercing;
MissileType(float mass, float knockback, boolean explosive, float explosionradius, FlightType headingtype, float armorpiercing)
{
this.mass = mass;
this.knockback = knockback;
this.explosive = explosive;
this.explosionradius = explosionradius;
this.flighttype = headingtype;
this.armorpiercing = armorpiercing;
}
}

View File

@@ -0,0 +1,49 @@
package ru.magistu.siegemachines.entity.projectile;
import ru.magistu.siegemachines.entity.EntityTypes;
import ru.magistu.siegemachines.item.ModItems;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.projectile.Arrow;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
public class ProjectileBuilder<T extends Projectile>
{
public final static ProjectileBuilder<Stone> NONE = new ProjectileBuilder<>(Items.AIR, EntityTypes.STONE.get(), Stone::new);
public final static ProjectileBuilder[] NO_AMMO = new ProjectileBuilder[]{};
public final static ProjectileBuilder[] CANNON_AMMO = new ProjectileBuilder[]{
new ProjectileBuilder(ModItems.CANNONBALL.get(), EntityTypes.CANNONBALL.get(), Cannonball::new)};
public final static ProjectileBuilder[] THROWING_AMMO = new ProjectileBuilder[]{
new ProjectileBuilder(Items.COBBLESTONE, ModItems.STONE.get(), EntityTypes.STONE.get(), Stone::new)};
public final static ProjectileBuilder[] BALLISTA_AMMO = new ProjectileBuilder[]{
new ProjectileBuilder(ModItems.GIANT_ARROW.get(), EntityTypes.GIANT_ARROW.get(), GiantArrow::new),
new ProjectileBuilder(Items.ARROW, EntityType.ARROW, (entitytype, level, pos, entity, item) ->
{
Arrow arrow = new Arrow(level, entity);
arrow.setPos(pos.x, pos.y, pos.z);
return arrow;
})};
public final Item item;
public final Item projectilitem;
public final EntityType<T> entitytype;
public final IProjectileFactory<T> factory;
public ProjectileBuilder(Item item, EntityType<T> entitytype, IProjectileFactory<T> factory)
{
this(item, item, entitytype, factory);
}
public ProjectileBuilder(Item item, Item projectilitem, EntityType<T> entitytype, IProjectileFactory<T> factory)
{
this.item = item;
this.projectilitem = projectilitem;
this.entitytype = entitytype;
this.factory = factory;
}
}

View File

@@ -0,0 +1,22 @@
package ru.magistu.siegemachines.entity.projectile;
import com.mojang.math.Vector3d;
import ru.magistu.siegemachines.item.ModItems;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
public class Stone extends Missile
{
public Stone(EntityType<Stone> entitytype, Level level)
{
super(entitytype, level);
this.item = ModItems.STONE.get();
}
public Stone(EntityType<Stone> entitytype, Level level, Vector3d pos, LivingEntity entity, Item item)
{
super(entitytype, level, pos, entity, MissileType.STONE, item);
}
}