diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java index d57244912..c8b0c3c2e 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java @@ -9,6 +9,7 @@ import com.atsuishio.superbwarfare.entity.vehicle.base.ContainerMobileVehicleEnt import com.atsuishio.superbwarfare.entity.vehicle.base.LandArmorEntity; import com.atsuishio.superbwarfare.entity.vehicle.base.WeaponVehicleEntity; import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.VehicleWeapon; import com.atsuishio.superbwarfare.init.*; import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; import com.atsuishio.superbwarfare.tools.AmmoType; @@ -72,8 +73,6 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti public static final EntityDataAccessor AMMO = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); public static final EntityDataAccessor MG_AMMO = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); public static final EntityDataAccessor LOADED_AMMO = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); - public static final EntityDataAccessor WEAPON_TYPE = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); - public static final EntityDataAccessor PASSENGER_WEAPON_TYPE = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); public static final EntityDataAccessor TRACK_L = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.FLOAT); public static final EntityDataAccessor TRACK_R = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.FLOAT); public static final EntityDataAccessor YAW = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.FLOAT); @@ -113,6 +112,20 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti this.setMaxUpStep(1.5f); } + @Override + public VehicleWeapon[][] getAllWeapons() { + // TODO 正确实现武器创建 + return new VehicleWeapon[][]{ + new VehicleWeapon[]{ + new VehicleWeapon().sound(ModSounds.INTO_MISSILE.get()), + new VehicleWeapon().sound(ModSounds.INTO_CANNON.get()), + }, + new VehicleWeapon[]{ + new VehicleWeapon(), + } + }; + } + @Override protected void defineSynchedData() { super.defineSynchedData(); @@ -121,8 +134,6 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti this.entityData.define(LOADED_AMMO, 0); this.entityData.define(FIRE_ANIM, 0); this.entityData.define(DELTA_ROT, 0f); - this.entityData.define(WEAPON_TYPE, 0); - this.entityData.define(PASSENGER_WEAPON_TYPE, 0); this.entityData.define(TRACK_L, 0f); this.entityData.define(TRACK_R, 0f); this.entityData.define(YAW, 0f); @@ -147,7 +158,7 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti } @Override - public Packet getAddEntityPacket() { + public @NotNull Packet getAddEntityPacket() { return NetworkHooks.getEntitySpawningPacket(this); } @@ -173,7 +184,7 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti } @Override - protected void playStepSound(BlockPos pPos, BlockState pState) { + protected void playStepSound(@NotNull BlockPos pPos, @NotNull BlockState pState) { this.playSound(ModSounds.BMP_STEP.get(), Mth.abs(this.entityData.get(POWER)) * 8, random.nextFloat() * 0.15f + 1f); } @@ -929,18 +940,9 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti @Override public void changeWeapon(int index, int value, boolean isScroll) { + WeaponVehicleEntity.super.changeWeapon(index, value, isScroll); if (index != 0) return; - var type = isScroll ? (value + getWeaponType(0) + 2) % 2 : value; - - var sound = switch (type) { - case 0 -> ModSounds.INTO_MISSILE.get(); - case 1 -> ModSounds.INTO_CANNON.get(); - default -> null; - }; - if (sound == null) return; - setWeaponType(0, type); - if (entityData.get(LOADED_AMMO) > 0) { if (this.getFirstPassenger() instanceof Player player && !player.getInventory().hasAnyMatching(s -> s.is(ModItems.CREATIVE_AMMO_BOX.get()))) { this.insertItem(getCurrentAmmoItem(), 1); @@ -954,24 +956,6 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti var clientboundstopsoundpacket = new ClientboundStopSoundPacket(ModSounds.YX_100_RELOAD.get().getLocation(), SoundSource.PLAYERS); player.connection.send(clientboundstopsoundpacket); } - this.level().playSound(null, this, sound, this.getSoundSource(), 1, 1); - } - - @Override - public int getWeaponType(int index) { - return switch (index) { - case 0 -> entityData.get(WEAPON_TYPE); - case 1 -> entityData.get(PASSENGER_WEAPON_TYPE); - default -> -1; - }; - } - - @Override - public void setWeaponType(int index, int type) { - switch (index) { - case 0 -> entityData.set(WEAPON_TYPE, type); - case 1 -> entityData.set(PASSENGER_WEAPON_TYPE, type); - } } @Override diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java index ab2c8f38c..295a85de2 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java @@ -4,10 +4,8 @@ import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.config.server.VehicleConfig; import com.atsuishio.superbwarfare.entity.vehicle.DroneEntity; import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; -import com.atsuishio.superbwarfare.init.ModDamageTypes; -import com.atsuishio.superbwarfare.init.ModItems; -import com.atsuishio.superbwarfare.init.ModParticleTypes; -import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.VehicleWeapon; +import com.atsuishio.superbwarfare.init.*; import com.atsuishio.superbwarfare.item.ContainerBlockItem; import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.EntityFindUtil; @@ -16,6 +14,7 @@ import com.atsuishio.superbwarfare.tools.VectorTool; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.mojang.math.Axis; +import it.unimi.dsi.fastutil.ints.IntList; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.particles.ParticleTypes; @@ -67,6 +66,10 @@ public abstract class VehicleEntity extends Entity { protected static final EntityDataAccessor LAST_ATTACKER_UUID = SynchedEntityData.defineId(VehicleEntity.class, EntityDataSerializers.STRING); protected static final EntityDataAccessor LAST_DRIVER_UUID = SynchedEntityData.defineId(VehicleEntity.class, EntityDataSerializers.STRING); + protected static final EntityDataAccessor SELECTED_WEAPON = SynchedEntityData.defineId(VehicleEntity.class, ModSerializers.INT_LIST_SERIALIZER.get()); + + public VehicleWeapon[][] availableWeapons; + protected int interpolationSteps; protected double x; protected double y; @@ -230,6 +233,21 @@ public abstract class VehicleEntity extends Entity { this.entityData.define(HEALTH, this.getMaxHealth()); this.entityData.define(LAST_ATTACKER_UUID, "undefined"); this.entityData.define(LAST_DRIVER_UUID, "undefined"); + + if (this instanceof WeaponVehicleEntity weaponVehicle) { + this.availableWeapons = new VehicleWeapon[this.getMaxPassengers()][]; + + var weapons = weaponVehicle.getAllWeapons(); + for (int i = 0; i < weapons.length || i < this.getMaxPassengers(); i++) { + this.availableWeapons[i] = weapons[i]; + } + + var selected = new int[this.getMaxPassengers()]; + for (int i = 0; i < this.getMaxPassengers(); i++) { + selected[i] = weaponVehicle.hasWeapon(i) ? 0 : -1; + } + this.entityData.define(SELECTED_WEAPON, IntList.of(selected)); + } } @Override @@ -237,6 +255,11 @@ public abstract class VehicleEntity extends Entity { this.entityData.set(LAST_ATTACKER_UUID, compound.getString("LastAttacker")); this.entityData.set(LAST_DRIVER_UUID, compound.getString("LastDriver")); this.entityData.set(HEALTH, compound.getFloat("Health")); + + if (this instanceof WeaponVehicleEntity) { + var selected = compound.getIntArray("SelectedWeapon"); + this.entityData.set(SELECTED_WEAPON, IntList.of(selected)); + } } @Override @@ -244,6 +267,10 @@ public abstract class VehicleEntity extends Entity { compound.putFloat("Health", this.entityData.get(HEALTH)); compound.putString("LastAttacker", this.entityData.get(LAST_ATTACKER_UUID)); compound.putString("LastDriver", this.entityData.get(LAST_DRIVER_UUID)); + + if (this instanceof WeaponVehicleEntity) { + compound.putIntArray("SelectedWeapon", this.entityData.get(SELECTED_WEAPON).toIntArray()); + } } @Override diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/WeaponVehicleEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/WeaponVehicleEntity.java index eded5a885..9b874f20b 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/WeaponVehicleEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/WeaponVehicleEntity.java @@ -1,5 +1,10 @@ package com.atsuishio.superbwarfare.entity.vehicle.base; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.VehicleWeapon; +import it.unimi.dsi.fastutil.ints.IntList; + +import java.util.List; + /** * 拥有任意武器的载具 */ @@ -11,7 +16,11 @@ public interface WeaponVehicleEntity extends ArmedVehicleEntity { * @return 武器是否可用 */ default boolean hasWeapon(int index) { - return getWeaponType(index) != -1; + if (!(this instanceof VehicleEntity vehicle)) return false; + if (index < 0 || index >= vehicle.getMaxPassengers()) return false; + + var weapons = getAvailableWeapons(index); + return !weapons.isEmpty(); } /** @@ -22,6 +31,73 @@ public interface WeaponVehicleEntity extends ArmedVehicleEntity { * @param isScroll 是否是滚动事件 */ default void changeWeapon(int index, int value, boolean isScroll) { + if (!(this instanceof VehicleEntity vehicle)) return; + if (index < 0 || index >= vehicle.getMaxPassengers()) return; + + var weapons = getAvailableWeapons(index); + if (weapons.isEmpty()) return; + var count = weapons.size(); + + var typeIndex = isScroll ? (value + getWeaponType(index) + count) % count : value; + var weapon = weapons.get(typeIndex); + + // 修改该槽位选择的武器 + setWeaponType(index, typeIndex); + + // 播放武器切换音效 + var sound = weapon.sound; + if (sound != null) { + vehicle.level().playSound(null, vehicle, sound, vehicle.getSoundSource(), 1, 1); + } + } + + /** + * 获取所有可用武器列表 + */ + default VehicleWeapon[][] getAllWeapons() { + return new VehicleWeapon[0][]; + } + + /** + * 获取该槽位可用的武器列表 + * + * @param index 武器槽位 + */ + default List getAvailableWeapons(int index) { + if (!(this instanceof VehicleEntity vehicle)) return List.of(); + if (index < 0 || index >= vehicle.getMaxPassengers()) return List.of(); + + if (vehicle.availableWeapons[index] != null) { + return List.of(vehicle.availableWeapons[index]); + } + return List.of(); + } + + default VehicleWeapon[][] initAvailableWeapons() { + if (!(this instanceof VehicleEntity vehicle)) return null; + if (vehicle.availableWeapons == null) { + vehicle.availableWeapons = new VehicleWeapon[vehicle.getMaxPassengers()][]; + } + + return vehicle.availableWeapons; + } + + /** + * 获取该槽位当前的武器 + * + * @param index 武器槽位 + */ + default VehicleWeapon getWeapon(int index) { + if (!(this instanceof VehicleEntity vehicle)) return null; + if (index < 0 || index >= vehicle.getMaxPassengers()) return null; + + var weapons = getAvailableWeapons(index); + if (weapons.isEmpty()) return null; + + var type = getWeaponType(index); + if (type < 0 || type >= weapons.size()) return null; + + return weapons.get(type); } /** @@ -31,8 +107,12 @@ public interface WeaponVehicleEntity extends ArmedVehicleEntity { * @return 武器类型 */ default int getWeaponType(int index) { - // 默认认为只有第一个位置拥有一个武器 - return index == 0 ? 0 : -1; + if (!(this instanceof VehicleEntity vehicle)) return -1; + + var selectedWeapons = vehicle.getEntityData().get(VehicleEntity.SELECTED_WEAPON); + if (selectedWeapons.size() <= index) return -1; + + return selectedWeapons.getInt(index); } /** @@ -42,5 +122,10 @@ public interface WeaponVehicleEntity extends ArmedVehicleEntity { * @param type 武器类型 */ default void setWeaponType(int index, int type) { + if (!(this instanceof VehicleEntity vehicle)) return; + + var selectedWeapons = vehicle.getEntityData().get(VehicleEntity.SELECTED_WEAPON).toIntArray(); + selectedWeapons[index] = type; + vehicle.getEntityData().set(VehicleEntity.SELECTED_WEAPON, IntList.of(selectedWeapons)); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/VehicleWeapon.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/VehicleWeapon.java index f5028543d..415fb25e4 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/VehicleWeapon.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/VehicleWeapon.java @@ -2,6 +2,7 @@ package com.atsuishio.superbwarfare.entity.vehicle.weapon; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; import net.minecraft.world.item.ItemStack; public class VehicleWeapon { @@ -21,6 +22,8 @@ public class VehicleWeapon { // 备弹量 public int backupAmmo; + public SoundEvent sound; + public VehicleWeapon icon(ResourceLocation icon) { this.icon = icon; return this; @@ -48,6 +51,16 @@ public class VehicleWeapon { return this; } + /** + * 切换到该武器时的音效 + * + * @param sound 音效 + */ + public VehicleWeapon sound(SoundEvent sound) { + this.sound = sound; + return this; + } + /** * 载具武器的装弹类型 * INDIRECT - 需要先进行上弹,再发射 @@ -55,7 +68,7 @@ public class VehicleWeapon { */ public enum AmmoType { INDIRECT, - DIRECT + DIRECT, } public VehicleWeapon maxAmmo(int maxAmmo) {