移植部分激光代码

This commit is contained in:
17146 2024-12-01 23:12:16 +08:00
parent 38cd812f4f
commit a631173551
6 changed files with 557 additions and 0 deletions

View file

@ -0,0 +1,19 @@
package com.atsuishio.superbwarfare.capability;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber()
public class CapabilityHandler {
@SubscribeEvent
public static void registerCapabilities(AttachCapabilitiesEvent<Entity> event) {
if (event.getObject() instanceof Player) {
event.addCapability(LaserCapability.ID, new LaserCapability.LaserCapabilityProvider());
}
}
}

View file

@ -0,0 +1,92 @@
package com.atsuishio.superbwarfare.capability;
import com.atsuishio.superbwarfare.ModUtils;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.common.util.LazyOptional;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class LaserCapability {
public static ResourceLocation ID = ModUtils.loc("laser_capability");
public interface ILaserCapability extends INBTSerializable<CompoundTag> {
void init(LaserHandler handler);
void start();
void tick();
void stop();
}
public static class LaserCapabilityImpl implements ILaserCapability {
public LaserHandler laserHandler;
@Override
public void init(LaserHandler handler) {
this.laserHandler = handler;
}
@Override
public void start() {
this.laserHandler.start();
}
@Override
public void tick() {
}
@Override
public void stop() {
if (this.laserHandler != null) {
this.laserHandler.stop();
}
}
@Override
public CompoundTag serializeNBT() {
CompoundTag tag = new CompoundTag();
if (this.laserHandler != null) {
tag.put("Laser", this.laserHandler.writeNBT());
}
return tag;
}
@Override
public void deserializeNBT(CompoundTag nbt) {
if (nbt.contains("Laser") && this.laserHandler != null) {
this.laserHandler.readNBT(nbt.getCompound("Laser"));
}
}
}
public static class LaserCapabilityProvider implements ICapabilityProvider, ICapabilitySerializable<CompoundTag> {
private final LazyOptional<LaserCapabilityImpl> instance = LazyOptional.of(LaserCapabilityImpl::new);
@Override
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
return ModCapabilities.LASER_CAPABILITY.orEmpty(cap, instance.cast());
}
@Override
public CompoundTag serializeNBT() {
return instance.orElseThrow(NullPointerException::new).serializeNBT();
}
@Override
public void deserializeNBT(CompoundTag nbt) {
instance.orElseThrow(NullPointerException::new).deserializeNBT(nbt);
}
}
}

View file

@ -0,0 +1,78 @@
package com.atsuishio.superbwarfare.capability;
import com.atsuishio.superbwarfare.entity.projectile.AbstractLaserEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.LivingEntity;
public class LaserHandler {
public final int coolingTick;
public boolean isUsing;
public final LivingEntity entity;
public final AbstractLaserEntity laserEntity;
private int tick;
public LaserHandler(LivingEntity entity, AbstractLaserEntity laserEntity, int coolingTick) {
this.coolingTick = coolingTick;
this.entity = entity;
this.laserEntity = laserEntity;
}
public void start() {
this.tick = 0;
this.isUsing = true;
if (this.entity.level() instanceof ServerLevel level) {
level.addFreshEntity(this.laserEntity);
}
this.entity.swing(InteractionHand.MAIN_HAND, true);
}
public void tick() {
if (this.isUsing) {
this.tick++;
if (this.tick > laserEntity.getDuration()) {
this.stop();
}
}
}
public void stop() {
if (!this.isUsing) return;
this.isUsing = false;
this.tick = 0;
if (this.laserEntity != null) {
this.laserEntity.discard();
}
}
public int getTick() {
return this.tick;
}
public CompoundTag writeNBT() {
CompoundTag compoundTag = new CompoundTag();
if (this.isUsing) {
compoundTag.putInt("Tick", this.tick);
}
return compoundTag;
}
public void readNBT(Tag nbt) {
CompoundTag compoundTag = (CompoundTag) nbt;
this.isUsing = compoundTag.contains("Tick");
if (this.isUsing) {
this.tick = compoundTag.getInt("Tick");
}
}
public boolean isUsable() {
return !this.isUsing;
}
}

View file

@ -0,0 +1,12 @@
package com.atsuishio.superbwarfare.capability;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.CapabilityToken;
public class ModCapabilities {
public static final Capability<LaserCapability.ILaserCapability> LASER_CAPABILITY = CapabilityManager.get(new CapabilityToken<>() {
});
}

View file

@ -0,0 +1,82 @@
package com.atsuishio.superbwarfare.client;
/**
* Code based on @EEEAB's EEEABsMobs and @Mercurows's DreamaticVoyage
*/
public class AnimationTicker {
private int tick;
private int prevTick;
private int duration;
public AnimationTicker(int duration) {
this.tick = 0;
this.prevTick = 0;
this.duration = duration;
}
public void setDuration(int duration) {
this.tick = 0;
this.prevTick = 0;
this.duration = duration;
}
public int getTick() {
return this.tick;
}
public boolean isStopped() {
return this.tick == 0 && this.prevTick == 0;
}
public boolean isEnded() {
return this.tick == this.duration || this.prevTick == this.duration;
}
public int getPrevTick() {
return this.prevTick;
}
public int getDuration() {
return this.duration;
}
public void changeTimer(boolean flag) {
changeTimer(flag, 1);
}
public void changeTimer(boolean add, int time) {
if (add) {
increaseTimer(time);
} else {
decreaseTimer(time);
}
}
public void increaseTimer(int time) {
int newTime = this.tick + time;
if (newTime <= duration && newTime >= 0) {
this.tick = newTime;
} else {
this.tick = newTime < 0 ? 0 : duration;
}
}
public void decreaseTimer(int time) {
if (this.tick - time > 0.0D) {
this.tick -= time;
} else {
this.tick = 0;
}
}
public void updatePrevTimer() {
this.prevTick = this.tick;
}
public void resetTimer() {
this.tick = 0;
this.prevTick = 0;
}
}

View file

@ -0,0 +1,274 @@
package com.atsuishio.superbwarfare.entity.projectile;
import com.atsuishio.superbwarfare.client.AnimationTicker;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.TraceableEntity;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.phys.*;
import net.minecraftforge.network.NetworkHooks;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* Code based on @BobMowzie's MowziesMobs, @EEEAB's EEEABsMobs and @Mercurows's DreamaticVoyage
*/
public abstract class AbstractLaserEntity extends Entity implements TraceableEntity {
public LivingEntity caster;
public float yaw, pitch;
public float preYaw, prePitch;
public double endPosX, endPosY, endPosZ;
public double collidePosX, collidePosY, collidePosZ;
public double prevCollidePosX, prevCollidePosY, prevCollidePosZ;
public Direction blockSide = null;
public boolean on = true;
public AnimationTicker ticker = new AnimationTicker(3);
private static final EntityDataAccessor<Integer> DATA_CASTER_ID = SynchedEntityData.defineId(AbstractLaserEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Float> DATA_YAW = SynchedEntityData.defineId(AbstractLaserEntity.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Float> DATA_PITCH = SynchedEntityData.defineId(AbstractLaserEntity.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Integer> DATA_DURATION = SynchedEntityData.defineId(AbstractLaserEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Integer> DATA_COUNT_DOWN = SynchedEntityData.defineId(AbstractLaserEntity.class, EntityDataSerializers.INT);
public AbstractLaserEntity(EntityType<?> type, Level level, int countDown) {
super(type, level);
this.setCountDown(countDown);
noCulling = true;
}
@Override
public void tick() {
super.tick();
this.prevCollidePosX = this.collidePosX;
this.prevCollidePosY = this.collidePosY;
this.prevCollidePosZ = this.collidePosZ;
this.preYaw = this.yaw;
this.prePitch = this.pitch;
this.yaw = this.getYaw();
this.pitch = this.getPitch();
this.xo = this.getX();
this.yo = this.getY();
this.zo = this.getZ();
if (this.tickCount == 1 && this.level().isClientSide) {
this.caster = (LivingEntity) this.level().getEntity(getCasterId());
}
this.beamTick();
if ((!this.on && this.ticker.isStopped()) || (this.caster != null && !caster.isAlive())) {
this.discard();
}
this.ticker.changeTimer(this.on && this.isAccumulating());
if (this.tickCount - this.getCountDown() > this.getDuration()) {
this.on = false;
}
}
@Override
public Packet<ClientGamePacketListener> getAddEntityPacket() {
return NetworkHooks.getEntitySpawningPacket(this);
}
@Override
protected void readAdditionalSaveData(CompoundTag pCompound) {
}
@Override
protected void addAdditionalSaveData(CompoundTag pCompound) {
}
protected void beamTick() {
}
@Nullable
public LivingEntity getOwner() {
return caster;
}
@Override
public boolean isPickable() {
return super.isPickable();
}
@Override
public void push(Entity entityIn) {
}
@Override
public PushReaction getPistonPushReaction() {
return PushReaction.IGNORE;
}
@Override
protected void defineSynchedData() {
this.entityData.define(DATA_CASTER_ID, -1);
this.entityData.define(DATA_YAW, 0F);
this.entityData.define(DATA_PITCH, 0F);
this.entityData.define(DATA_DURATION, 0);
this.entityData.define(DATA_COUNT_DOWN, 0);
}
public void setCasterId(int id) {
this.entityData.set(DATA_CASTER_ID, id);
}
public int getCasterId() {
return this.entityData.get(DATA_CASTER_ID);
}
public boolean isAccumulating() {
return this.tickCount > this.getCountDown();
}
public float getYaw() {
return getEntityData().get(DATA_YAW);
}
public void setYaw(float rotAngle) {
getEntityData().set(DATA_YAW, rotAngle);
}
public float getPitch() {
return getEntityData().get(DATA_PITCH);
}
public void setPitch(float rotAngle) {
getEntityData().set(DATA_PITCH, rotAngle);
}
public int getDuration() {
return getEntityData().get(DATA_DURATION);
}
public void setDuration(int duration) {
getEntityData().set(DATA_DURATION, duration);
}
public int getCountDown() {
return getEntityData().get(DATA_COUNT_DOWN);
}
public void setCountDown(int countDown) {
getEntityData().set(DATA_COUNT_DOWN, countDown);
}
protected void calculateEndPos(double radius) {
if (level().isClientSide()) {
endPosX = getX() + radius * Math.cos(yaw) * Math.cos(pitch);
endPosZ = getZ() + radius * Math.sin(yaw) * Math.cos(pitch);
endPosY = getY() + radius * Math.sin(pitch);
} else {
endPosX = getX() + radius * Math.cos(getYaw()) * Math.cos(getPitch());
endPosZ = getZ() + radius * Math.sin(getYaw()) * Math.cos(getPitch());
endPosY = getY() + radius * Math.sin(getPitch());
}
}
public CustomHitResult raytraceEntities(Level world, Vec3 from, Vec3 to) {
CustomHitResult result = new CustomHitResult();
result.setBlockHit(world.clip(new ClipContext(from, to, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)));
if (result.getBlockHit() != null) {
Vec3 hitVec = result.getBlockHit().getLocation();
collidePosX = hitVec.x;
collidePosY = hitVec.y;
collidePosZ = hitVec.z;
blockSide = result.getBlockHit().getDirection();
} else {
collidePosX = endPosX;
collidePosY = endPosY;
collidePosZ = endPosZ;
blockSide = null;
}
List<LivingEntity> entities = world.getEntitiesOfClass(LivingEntity.class, new AABB(Math.min(getX(), collidePosX), Math.min(getY(), collidePosY), Math.min(getZ(), collidePosZ), Math.max(getX(), collidePosX), Math.max(getY(), collidePosY), Math.max(getZ(), collidePosZ)).inflate(1, 1, 1));
for (LivingEntity entity : entities) {
if (entity == this.caster) {
continue;
}
float pad = entity.getPickRadius() + getBaseScale();
AABB aabb = entity.getBoundingBox().inflate(pad, pad, pad);
Optional<Vec3> hit = aabb.clip(from, to);
if (aabb.contains(from)) {
result.addEntityHit(entity);
} else if (hit.isPresent()) {
result.addEntityHit(entity);
}
}
return result;
}
@Override
public boolean isAttackable() {
return false;
}
@Override
public boolean displayFireAnimation() {
return false;
}
protected void onHit(HitResult hitResult) {
HitResult.Type hitresult$type = hitResult.getType();
if (hitresult$type == HitResult.Type.ENTITY) {
this.onHitEntity((EntityHitResult) hitResult);
this.level().gameEvent(GameEvent.PROJECTILE_LAND, hitResult.getLocation(), GameEvent.Context.of(this, null));
} else if (hitresult$type == HitResult.Type.BLOCK) {
BlockHitResult blockhitresult = (BlockHitResult) hitResult;
this.onHitBlock(blockhitresult);
BlockPos blockpos = blockhitresult.getBlockPos();
this.level().gameEvent(GameEvent.PROJECTILE_LAND, blockpos, GameEvent.Context.of(this, this.level().getBlockState(blockpos)));
}
}
protected void onHitEntity(EntityHitResult result) {
}
protected void onHitBlock(BlockHitResult result) {
}
protected float getBaseScale() {
return 0.5F;
}
public static class CustomHitResult {
private BlockHitResult blockHit;
private final List<LivingEntity> entities = new ArrayList<>();
public BlockHitResult getBlockHit() {
return blockHit;
}
public List<LivingEntity> getEntities() {
return entities;
}
public void setBlockHit(HitResult rayTraceResult) {
if (rayTraceResult.getType() == HitResult.Type.BLOCK)
this.blockHit = (BlockHitResult) rayTraceResult;
}
public void addEntityHit(LivingEntity entity) {
entities.add(entity);
}
}
}