提取开火事件处理相关代码

This commit is contained in:
Light_Quanta 2025-04-16 22:03:19 +08:00
parent 8000fd40b2
commit c14ab91b83
No known key found for this signature in database
GPG key ID: 11A39A1B8C890959
16 changed files with 330 additions and 393 deletions

View file

@ -1,25 +1,19 @@
package com.atsuishio.superbwarfare.event;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity;
import com.atsuishio.superbwarfare.event.events.ReloadEvent;
import com.atsuishio.superbwarfare.init.*;
import com.atsuishio.superbwarfare.item.gun.GunItem;
import com.atsuishio.superbwarfare.item.gun.PressFireSpecialWeapon;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import com.atsuishio.superbwarfare.item.gun.data.value.AttachmentType;
import com.atsuishio.superbwarfare.item.gun.data.value.ReloadState;
import com.atsuishio.superbwarfare.perk.AmmoPerk;
import com.atsuishio.superbwarfare.perk.Perk;
import com.atsuishio.superbwarfare.tools.Ammo;
import com.atsuishio.superbwarfare.tools.InventoryTool;
import com.atsuishio.superbwarfare.tools.SoundTool;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ClipContext;
@ -30,8 +24,6 @@ import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.tick.PlayerTickEvent;
import java.util.ArrayList;
@EventBusSubscriber(modid = Mod.MODID)
public class GunEventHandler {
@ -171,98 +163,6 @@ public class GunEventHandler {
}
}
public static void gunShoot(Player player, GunData data, double spared, boolean zoom) {
var stack = data.stack();
if (!player.level().isClientSide()) {
if (stack.getItem() instanceof PressFireSpecialWeapon pressFireSpecialWeapon) {
pressFireSpecialWeapon.fireOnPress(player, data, spared, zoom);
} else {
float headshot = (float) data.headshot();
float damage = (float) data.damage();
float velocity = (float) (data.velocity() * perkSpeed(data));
int projectileAmount = data.projectileAmount();
float bypassArmorRate = (float) data.bypassArmor();
var perkInstance = data.perk.getInstance(Perk.Type.AMMO);
var perk = perkInstance != null ? perkInstance.perk() : null;
ProjectileEntity projectile = new ProjectileEntity(player.level())
.shooter(player)
.damage(perk instanceof AmmoPerk ammoPerk && ammoPerk.slug ? projectileAmount * damage : damage)
.damage(damage)
.headShot(headshot)
.zoom(zoom)
.setGunItemId(stack);
if (perk instanceof AmmoPerk ammoPerk) {
int level = data.perk.getLevel(perk);
bypassArmorRate += ammoPerk.bypassArmorRate + (perk == ModPerks.AP_BULLET.get() ? 0.05f * (level - 1) : 0);
projectile.setRGB(ammoPerk.rgb);
if (!ammoPerk.mobEffects.get().isEmpty()) {
int amplifier;
if (perk.descriptionId.equals("blade_bullet")) {
amplifier = level / 3;
} else if (perk.descriptionId.equals("bread_bullet")) {
amplifier = 1;
} else {
amplifier = level - 1;
}
ArrayList<MobEffectInstance> mobEffectInstances = new ArrayList<>();
for (MobEffect effect : ammoPerk.mobEffects.get()) {
mobEffectInstances.add(new MobEffectInstance(Holder.direct(effect), 70 + 30 * level, amplifier));
}
projectile.effect(mobEffectInstances);
}
if (perk.descriptionId.equals("bread_bullet")) {
projectile.knockback(level * 0.3f);
projectile.forceKnockback();
}
}
bypassArmorRate = Math.max(bypassArmorRate, 0);
projectile.bypassArmorRate(bypassArmorRate);
if (perk == ModPerks.SILVER_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.undeadMultiple(1.0f + 0.5f * level);
} else if (perk == ModPerks.BEAST_BULLET.get()) {
projectile.beast();
} else if (perk == ModPerks.JHP_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.jhpBullet(level);
} else if (perk == ModPerks.HE_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.heBullet(level);
} else if (perk == ModPerks.INCENDIARY_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.fireBullet(level, stack.is(ModTags.Items.SHOTGUN));
}
var dmgPerk = data.perk.get(Perk.Type.DAMAGE);
if (dmgPerk == ModPerks.MONSTER_HUNTER.get()) {
int level = data.perk.getLevel(dmgPerk);
projectile.monsterMultiple(0.1f + 0.1f * level);
}
projectile.setPos(player.getX() - 0.1 * player.getLookAngle().x, player.getEyeY() - 0.1 - 0.1 * player.getLookAngle().y, player.getZ() + -0.1 * player.getLookAngle().z);
projectile.shoot(player, player.getLookAngle().x, player.getLookAngle().y + 0.001f, player.getLookAngle().z, stack.is(ModTags.Items.SHOTGUN) && perk == ModPerks.INCENDIARY_BULLET.get() ? 4.5f : velocity, (float) spared);
player.level().addFreshEntity(projectile);
}
}
}
public static double perkSpeed(GunData data) {
var perk = data.perk.get(Perk.Type.AMMO);
if (perk instanceof AmmoPerk ammoPerk) {
return ammoPerk.speedRate;
}
return 1;
}
/**
* 通用的武器换弹流程
*/

View file

@ -3,12 +3,16 @@ package com.atsuishio.superbwarfare.item.gun;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.client.PoseTool;
import com.atsuishio.superbwarfare.client.tooltip.component.GunImageComponent;
import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity;
import com.atsuishio.superbwarfare.event.GunEventHandler;
import com.atsuishio.superbwarfare.init.ModAttachments;
import com.atsuishio.superbwarfare.init.ModItems;
import com.atsuishio.superbwarfare.init.ModPerks;
import com.atsuishio.superbwarfare.init.ModTags;
import com.atsuishio.superbwarfare.item.CustomRendererItem;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import com.atsuishio.superbwarfare.item.gun.data.value.AttachmentType;
import com.atsuishio.superbwarfare.perk.AmmoPerk;
import com.atsuishio.superbwarfare.perk.Perk;
import com.atsuishio.superbwarfare.tools.Ammo;
import net.minecraft.client.model.HumanoidModel;
@ -18,6 +22,8 @@ import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlotGroup;
import net.minecraft.world.entity.LivingEntity;
@ -490,9 +496,161 @@ public abstract class GunItem extends Item implements CustomRendererItem {
}
/**
* 添加服务端在开火时的额外行为
* 服务端在开火前的额外行为
*/
public void onShoot(GunData data, Player player) {
public void beforeShoot(GunData data, Player player, double spread, boolean zoom) {
// 空仓挂机
if (data.ammo.get() == 1) {
data.holdOpen.set(true);
}
// TODO 替换左轮判断方式
if (data.stack.is(ModTags.Items.REVOLVER)) {
data.canImmediatelyShoot.set(true);
}
// TODO 替换左轮判断方式
// 判断是否为栓动武器BoltActionTime > 0并在开火后给一个需要上膛的状态
if (data.defaultActionTime() > 0 && data.ammo.get() > (data.stack.is(ModTags.Items.REVOLVER) ? 0 : 1)) {
data.bolt.needed.set(true);
}
data.ammo.set(data.ammo.get() - 1);
data.isEmpty.set(true);
}
/**
* 服务端处理开火
*/
public void onShoot(GunData data, Player player, double spread, boolean zoom) {
if (data.ammo.get() <= 0) return;
// 开火前事件
data.item.beforeShoot(data, player, spread, zoom);
int projectileAmount = data.projectileAmount();
var perk = data.perk.get(Perk.Type.AMMO);
// 生成所有子弹
for (int index0 = 0; index0 < (perk instanceof AmmoPerk ammoPerk && ammoPerk.slug ? 1 : projectileAmount); index0++) {
shootBullet(player, data, spread, zoom);
}
// TODO 提取对应方法
// 播放音效
GunEventHandler.playGunSounds(player, zoom);
}
/**
* 服务端处理按下开火按键时的额外行为
*/
public void onFireKeyPress(final GunData data, Player player, boolean zoom) {
if (data.reload.prepareTimer.get() == 0 && data.reloading() && data.ammo.get() > 0) {
data.forceStop.set(true);
}
player.getData(ModAttachments.PLAYER_VARIABLE).modify(player, cap -> cap.edit = false);
}
/**
* 服务端处理松开开火按键时的额外行为
*/
public void onFireKeyRelease(final GunData data, Player player, double power, boolean zoom) {
}
public static double perkSpeed(GunData data) {
var perk = data.perk.get(Perk.Type.AMMO);
if (perk instanceof AmmoPerk ammoPerk) {
return ammoPerk.speedRate;
}
return 1;
}
public static double perkDamage(Perk perk) {
if (perk instanceof AmmoPerk ammoPerk) {
return ammoPerk.damageRate;
}
return 1;
}
/**
* 服务端发射单发子弹
*/
public void shootBullet(Player player, GunData data, double spread, boolean zoom) {
var stack = data.stack;
float headshot = (float) data.headshot();
float damage = (float) data.damage();
float velocity = (float) (data.velocity() * perkSpeed(data));
int projectileAmount = data.projectileAmount();
float bypassArmorRate = (float) data.bypassArmor();
var perkInstance = data.perk.getInstance(Perk.Type.AMMO);
var perk = perkInstance != null ? perkInstance.perk() : null;
ProjectileEntity projectile = new ProjectileEntity(player.level())
.shooter(player)
.damage(perk instanceof AmmoPerk ammoPerk && ammoPerk.slug ? projectileAmount * damage : damage)
.headShot(headshot)
.zoom(zoom)
.setGunItemId(stack);
if (perk instanceof AmmoPerk ammoPerk) {
int level = data.perk.getLevel(perk);
bypassArmorRate += ammoPerk.bypassArmorRate + (perk == ModPerks.AP_BULLET.get() ? 0.05f * (level - 1) : 0);
projectile.setRGB(ammoPerk.rgb);
if (!ammoPerk.mobEffects.get().isEmpty()) {
int amplifier;
if (perk.descriptionId.equals("blade_bullet")) {
amplifier = level / 3;
} else if (perk.descriptionId.equals("bread_bullet")) {
amplifier = 1;
} else {
amplifier = level - 1;
}
ArrayList<MobEffectInstance> mobEffectInstances = new ArrayList<>();
for (MobEffect effect : ammoPerk.mobEffects.get()) {
mobEffectInstances.add(new MobEffectInstance(Holder.direct(effect), 70 + 30 * level, amplifier));
}
projectile.effect(mobEffectInstances);
}
if (perk.descriptionId.equals("bread_bullet")) {
projectile.knockback(level * 0.3f);
projectile.forceKnockback();
}
}
bypassArmorRate = Math.max(bypassArmorRate, 0);
projectile.bypassArmorRate(bypassArmorRate);
if (perk == ModPerks.SILVER_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.undeadMultiple(1.0f + 0.5f * level);
} else if (perk == ModPerks.BEAST_BULLET.get()) {
projectile.beast();
} else if (perk == ModPerks.JHP_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.jhpBullet(level);
} else if (perk == ModPerks.HE_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.heBullet(level);
} else if (perk == ModPerks.INCENDIARY_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.fireBullet(level, stack.is(ModTags.Items.SHOTGUN));
}
var dmgPerk = data.perk.get(Perk.Type.DAMAGE);
if (dmgPerk == ModPerks.MONSTER_HUNTER.get()) {
int level = data.perk.getLevel(dmgPerk);
projectile.monsterMultiple(0.1f + 0.1f * level);
}
projectile.setPos(player.getX() - 0.1 * player.getLookAngle().x, player.getEyeY() - 0.1 - 0.1 * player.getLookAngle().y, player.getZ() + -0.1 * player.getLookAngle().z);
projectile.shoot(player, player.getLookAngle().x, player.getLookAngle().y + 0.001f, player.getLookAngle().z, stack.is(ModTags.Items.SHOTGUN) && perk == ModPerks.INCENDIARY_BULLET.get() ? 4.5f : velocity, (float) spread);
player.level().addFreshEntity(projectile);
}
@SubscribeEvent

View file

@ -1,19 +0,0 @@
package com.atsuishio.superbwarfare.item.gun;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import net.minecraft.world.entity.player.Player;
/**
* 不使用普通子弹的按下开火武器的开火处理
*/
public interface PressFireSpecialWeapon {
/**
* 按下按键时武器发射处理
*
* @param player 玩家
*/
default void fireOnPress(Player player, GunData data, double spread, boolean zoom) {
}
}

View file

@ -1,30 +0,0 @@
package com.atsuishio.superbwarfare.item.gun;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import net.minecraft.world.entity.player.Player;
/**
* 拥有特殊开火方式的武器的开火处理
*/
public interface ReleaseSpecialWeapon {
/**
* 按下按键时武器发射处理
*
* @param player 玩家
*/
default void fireOnPress(Player player, final GunData data, boolean zoom) {
}
/**
* 松开按键时武器发射处理
*
* @param player 玩家
*/
default void fireOnRelease(Player player, final GunData data, double power, boolean zoom) {
}
}

View file

@ -11,7 +11,6 @@ import com.atsuishio.superbwarfare.init.ModEnumExtensions;
import com.atsuishio.superbwarfare.init.ModPerks;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.item.gun.GunItem;
import com.atsuishio.superbwarfare.item.gun.ReleaseSpecialWeapon;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import com.atsuishio.superbwarfare.network.message.receive.ShootClientMessage;
import com.atsuishio.superbwarfare.perk.Perk;
@ -55,7 +54,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
public class JavelinItem extends GunItem implements GeoItem, ReleaseSpecialWeapon {
public class JavelinItem extends GunItem implements GeoItem {
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
public static ItemDisplayContext transformType;
@ -270,8 +269,11 @@ public class JavelinItem extends GunItem implements GeoItem, ReleaseSpecialWeapo
}
@Override
public void fireOnRelease(Player player, final GunData data, double power, boolean zoom) {
public void onFireKeyRelease(GunData data, Player player, double power, boolean zoom) {
super.onFireKeyRelease(data, player, power, zoom);
fire(player);
var tag = data.tag();
tag.putBoolean("Seeking", false);
tag.putInt("SeekTime", 0);
@ -283,11 +285,12 @@ public class JavelinItem extends GunItem implements GeoItem, ReleaseSpecialWeapo
}
@Override
public void fireOnPress(Player player, final GunData data, boolean zoom) {
var tag = data.tag();
public void onFireKeyPress(GunData data, Player player, boolean zoom) {
super.onFireKeyPress(data, player, zoom);
if (!zoom || data.ammo.get() <= 0) return;
var tag = data.tag();
Entity seekingEntity = SeekTool.seekEntity(player, player.level(), 512, 8);
if (seekingEntity != null && !player.isCrouching()) {

View file

@ -8,7 +8,6 @@ import com.atsuishio.superbwarfare.event.ClientEventHandler;
import com.atsuishio.superbwarfare.init.ModPerks;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.item.gun.GunItem;
import com.atsuishio.superbwarfare.item.gun.PressFireSpecialWeapon;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import com.atsuishio.superbwarfare.perk.Perk;
import com.atsuishio.superbwarfare.perk.PerkHelper;
@ -36,7 +35,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
public class M79Item extends GunItem implements GeoItem, PressFireSpecialWeapon {
public class M79Item extends GunItem implements GeoItem {
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
public static ItemDisplayContext transformType;
@ -122,7 +121,7 @@ public class M79Item extends GunItem implements GeoItem, PressFireSpecialWeapon
}
@Override
public void fireOnPress(Player player, final GunData data, double spread, boolean zoom) {
public void shootBullet(Player player, GunData data, double spread, boolean zoom) {
if (data.reloading()) return;
if (player.level() instanceof ServerLevel serverLevel) {

View file

@ -8,7 +8,6 @@ import com.atsuishio.superbwarfare.event.ClientEventHandler;
import com.atsuishio.superbwarfare.init.ModPerks;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.item.gun.GunItem;
import com.atsuishio.superbwarfare.item.gun.PressFireSpecialWeapon;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import com.atsuishio.superbwarfare.perk.Perk;
import com.atsuishio.superbwarfare.perk.PerkHelper;
@ -41,7 +40,7 @@ import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class RpgItem extends GunItem implements GeoItem, PressFireSpecialWeapon {
public class RpgItem extends GunItem implements GeoItem {
@Override
public String getAmmoDisplayName(GunData data) {
@ -145,7 +144,7 @@ public class RpgItem extends GunItem implements GeoItem, PressFireSpecialWeapon
}
@Override
public void fireOnPress(Player player, final GunData data, double spread, boolean zoom) {
public void shootBullet(Player player, GunData data, double spread, boolean zoom) {
Level level = player.level();
if (data.reloading()) return;

View file

@ -10,7 +10,6 @@ import com.atsuishio.superbwarfare.init.ModItems;
import com.atsuishio.superbwarfare.init.ModPerks;
import com.atsuishio.superbwarfare.item.EnergyStorageItem;
import com.atsuishio.superbwarfare.item.gun.GunItem;
import com.atsuishio.superbwarfare.item.gun.PressFireSpecialWeapon;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import com.atsuishio.superbwarfare.perk.Perk;
import com.atsuishio.superbwarfare.perk.PerkHelper;
@ -44,7 +43,7 @@ import java.util.ArrayList;
import java.util.Optional;
import java.util.function.Supplier;
public class SecondaryCataclysm extends GunItem implements GeoItem, PressFireSpecialWeapon, EnergyStorageItem {
public class SecondaryCataclysm extends GunItem implements GeoItem, EnergyStorageItem {
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
public static ItemDisplayContext transformType;
@ -232,7 +231,7 @@ public class SecondaryCataclysm extends GunItem implements GeoItem, PressFireSpe
}
@Override
public void fireOnPress(Player player, final GunData data, double spread, boolean zoom) {
public void shootBullet(Player player, GunData data, double spread, boolean zoom) {
if (data.reloading()) return;
ItemStack stack = data.stack();

View file

@ -162,8 +162,8 @@ public class M60Item extends GunItem implements GeoItem {
}
@Override
public void onShoot(GunData data, Player player) {
super.onShoot(data, player);
public void beforeShoot(GunData data, Player player, double spread, boolean zoom) {
super.beforeShoot(data, player, spread, zoom);
if (data.ammo.get() <= 5) {
data.hideBulletChain.set(true);

View file

@ -6,11 +6,13 @@ import com.atsuishio.superbwarfare.event.ClientEventHandler;
import com.atsuishio.superbwarfare.init.ModEnumExtensions;
import com.atsuishio.superbwarfare.init.ModParticleTypes;
import com.atsuishio.superbwarfare.init.ModPerks;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.item.gun.GunItem;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import com.atsuishio.superbwarfare.perk.Perk;
import com.atsuishio.superbwarfare.tools.NBTTool;
import com.atsuishio.superbwarfare.tools.ParticleTool;
import com.atsuishio.superbwarfare.tools.SoundTool;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.particles.ParticleTypes;
@ -19,6 +21,7 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
@ -153,6 +156,41 @@ public class MinigunItem extends GunItem implements GeoItem {
data.save();
}
@Override
public void onShoot(GunData data, Player player, double spread, boolean zoom) {
var tag = data.tag();
if (!data.hasAmmo(player)) return;
// TODO 替换为通用过热处理
tag.putDouble("heat", (tag.getDouble("heat") + 0.1));
if (tag.getDouble("heat") >= 50.5) {
tag.putDouble("overheat", 40);
player.getCooldowns().addCooldown(data.item(), 40);
if (!player.level().isClientSide() && player instanceof ServerPlayer serverPlayer) {
SoundTool.playLocalSound(serverPlayer, ModSounds.MINIGUN_OVERHEAT.get(), 2f, 1f);
}
}
float pitch = tag.getDouble("heat") <= 40 ? 1 : (float) (1 - 0.025 * Math.abs(40 - tag.getDouble("heat")));
var perk = data.perk.get(Perk.Type.AMMO);
if (!player.level().isClientSide() && player instanceof ServerPlayer) {
float soundRadius = (float) data.soundRadius();
player.playSound(ModSounds.MINIGUN_FIRE_3P.get(), soundRadius * 0.2f, pitch);
player.playSound(ModSounds.MINIGUN_FAR.get(), soundRadius * 0.5f, pitch);
player.playSound(ModSounds.MINIGUN_VERYFAR.get(), soundRadius, pitch);
if (perk == ModPerks.BEAST_BULLET.get()) {
player.playSound(ModSounds.HENG.get(), 4f, pitch);
}
}
shootBullet(player, data, spread, zoom);
data.consumeAmmo(player, 1);
}
@Override
public ResourceLocation getGunIcon() {
return Mod.loc("textures/gun_icon/minigun_icon.png");

View file

@ -124,8 +124,8 @@ public class HomemadeShotgunItem extends GunItem implements GeoItem {
}
@Override
public void onShoot(GunData data, Player player) {
super.onShoot(data, player);
public void beforeShoot(GunData data, Player player, double spread, boolean zoom) {
super.beforeShoot(data, player, spread, zoom);
var stack = data.stack();
stack.hurtAndBreak(1, (ServerLevel) player.level(), player, p -> {

View file

@ -191,8 +191,8 @@ public class SentinelItem extends GunItem implements GeoItem, EnergyStorageItem
}
@Override
public void onShoot(GunData data, Player player) {
super.onShoot(data, player);
public void beforeShoot(GunData data, Player player, double spread, boolean zoom) {
super.beforeShoot(data, player, spread, zoom);
var cap = data.stack.getCapability(Capabilities.EnergyStorage.ITEM);
if (cap != null) {

View file

@ -3,11 +3,11 @@ package com.atsuishio.superbwarfare.item.gun.special;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.client.renderer.item.BocekItemRenderer;
import com.atsuishio.superbwarfare.client.tooltip.component.BocekImageComponent;
import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity;
import com.atsuishio.superbwarfare.event.ClientEventHandler;
import com.atsuishio.superbwarfare.init.ModPerks;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.item.gun.GunItem;
import com.atsuishio.superbwarfare.item.gun.ReleaseSpecialWeapon;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import com.atsuishio.superbwarfare.network.message.receive.ShootClientMessage;
import com.atsuishio.superbwarfare.perk.AmmoPerk;
@ -17,9 +17,12 @@ import com.atsuishio.superbwarfare.tools.InventoryTool;
import com.atsuishio.superbwarfare.tools.SoundTool;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.tooltip.TooltipComponent;
@ -37,12 +40,11 @@ import software.bernie.geckolib.renderer.GeoItemRenderer;
import software.bernie.geckolib.util.GeckoLibUtil;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.Optional;
import java.util.function.Supplier;
import static com.atsuishio.superbwarfare.network.message.send.FireKeyMessage.spawnBullet;
public class BocekItem extends GunItem implements GeoItem, ReleaseSpecialWeapon {
public class BocekItem extends GunItem implements GeoItem {
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
public static ItemDisplayContext transformType;
@ -145,14 +147,17 @@ public class BocekItem extends GunItem implements GeoItem, ReleaseSpecialWeapon
}
@Override
public void fireOnRelease(Player player, final GunData data, double power, boolean zoom) {
if (player.level().isClientSide()) return;
public void onShoot(GunData data, Player player, double spread, boolean zoom) {
}
ItemStack stack = player.getMainHandItem();
var perk = data.perk.get(Perk.Type.AMMO);
@Override
public void onFireKeyRelease(GunData data, Player player, double power, boolean zoom) {
super.onFireKeyRelease(data, player, power, zoom);
if (data.ammo.get() == 0) return;
var perk = data.perk.get(Perk.Type.AMMO);
if (player instanceof ServerPlayer serverPlayer) {
SoundTool.stopSound(serverPlayer, ModSounds.BOCEK_PULL_1P.getId(), SoundSource.PLAYERS);
SoundTool.stopSound(serverPlayer, ModSounds.BOCEK_PULL_3P.getId(), SoundSource.PLAYERS);
@ -161,13 +166,13 @@ public class BocekItem extends GunItem implements GeoItem, ReleaseSpecialWeapon
if (power * 12 >= 6) {
if (zoom) {
spawnBullet(player, power, true);
spawnBullet(data, player, power, true);
SoundTool.playLocalSound(player, ModSounds.BOCEK_ZOOM_FIRE_1P.get(), 10, 1);
player.playSound(ModSounds.BOCEK_ZOOM_FIRE_3P.get(), 2, 1);
} else {
for (int i = 0; i < (perk instanceof AmmoPerk ammoPerk && ammoPerk.slug ? 1 : 10); i++) {
spawnBullet(player, power, false);
spawnBullet(data, player, power, false);
}
SoundTool.playLocalSound(player, ModSounds.BOCEK_SHATTER_CAP_FIRE_1P.get(), 10, 1);
@ -182,9 +187,97 @@ public class BocekItem extends GunItem implements GeoItem, ReleaseSpecialWeapon
}
}
GunsTool.setGunIntTag(GunData.from(stack).tag, "ArrowEmpty", 7);
GunsTool.setGunIntTag(data.tag, "ArrowEmpty", 7);
data.ammo.set(data.ammo.get() - 1);
data.save();
}
}
public void spawnBullet(GunData data, Player player, double power, boolean zoom) {
ItemStack stack = data.stack;
var perk = data.perk.get(Perk.Type.AMMO);
float headshot = (float) data.headshot();
float velocity = (float) (24 * power * (float) perkSpeed(data));
float bypassArmorRate = (float) data.bypassArmor();
double damage;
float spread;
if (zoom) {
spread = 0.01f;
damage = 0.08333333 * data.damage() *
12 * power * perkDamage(perk);
} else {
spread = perk instanceof AmmoPerk ammoPerk && ammoPerk.slug ? 0.5f : 2.5f;
damage = (perk instanceof AmmoPerk ammoPerk && ammoPerk.slug ? 0.08333333 : 0.008333333) *
data.damage() * 12 * power * perkDamage(perk);
}
ProjectileEntity projectile = new ProjectileEntity(player.level())
.shooter(player)
.headShot(headshot)
.zoom(zoom)
.setGunItemId(stack);
if (perk instanceof AmmoPerk ammoPerk) {
int level = data.perk.getLevel(perk);
bypassArmorRate += ammoPerk.bypassArmorRate + (perk == ModPerks.AP_BULLET.get() ? 0.05f * (level - 1) : 0);
projectile.setRGB(ammoPerk.rgb);
if (!ammoPerk.mobEffects.get().isEmpty()) {
int amplifier;
if (perk.descriptionId.equals("blade_bullet")) {
amplifier = level / 3;
} else if (perk.descriptionId.equals("bread_bullet")) {
amplifier = 1;
} else {
amplifier = level - 1;
}
ArrayList<MobEffectInstance> mobEffectInstances = new ArrayList<>();
for (MobEffect effect : ammoPerk.mobEffects.get()) {
mobEffectInstances.add(new MobEffectInstance(Holder.direct(effect), 70 + 30 * level, amplifier));
}
projectile.effect(mobEffectInstances);
}
if (perk.descriptionId.equals("bread_bullet")) {
projectile.knockback(level * 0.3f);
projectile.forceKnockback();
}
}
bypassArmorRate = Math.max(bypassArmorRate, 0);
projectile.bypassArmorRate(bypassArmorRate);
if (perk == ModPerks.SILVER_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.undeadMultiple(1.0f + 0.5f * level);
} else if (perk == ModPerks.BEAST_BULLET.get()) {
projectile.beast();
} else if (perk == ModPerks.JHP_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.jhpBullet(level);
} else if (perk == ModPerks.HE_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.heBullet(level);
} else if (perk == ModPerks.INCENDIARY_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.fireBullet(level, !zoom);
}
var dmgPerk = data.perk.get(Perk.Type.DAMAGE);
if (dmgPerk == ModPerks.MONSTER_HUNTER.get()) {
int perkLevel = data.perk.getLevel(dmgPerk);
projectile.monsterMultiple(0.1f + 0.1f * perkLevel);
}
projectile.setPos(player.getX() - 0.1 * player.getLookAngle().x, player.getEyeY() - 0.1 - 0.1 * player.getLookAngle().y, player.getZ() + -0.1 * player.getLookAngle().z);
projectile.shoot(player, player.getLookAngle().x, player.getLookAngle().y, player.getLookAngle().z, (!zoom && perk == ModPerks.INCENDIARY_BULLET.get() ? 0.2f : 1) * velocity, spread);
projectile.damage((float) damage);
player.level().addFreshEntity(projectile);
}
}

View file

@ -10,7 +10,6 @@ import com.atsuishio.superbwarfare.init.ModPerks;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.item.EnergyStorageItem;
import com.atsuishio.superbwarfare.item.gun.GunItem;
import com.atsuishio.superbwarfare.item.gun.PressFireSpecialWeapon;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import com.atsuishio.superbwarfare.perk.Perk;
import net.minecraft.client.Minecraft;
@ -39,7 +38,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
public class TaserItem extends GunItem implements GeoItem, EnergyStorageItem, PressFireSpecialWeapon {
public class TaserItem extends GunItem implements GeoItem, EnergyStorageItem {
public static final int MAX_ENERGY = 6000;
@ -185,7 +184,7 @@ public class TaserItem extends GunItem implements GeoItem, EnergyStorageItem, Pr
}
@Override
public void fireOnPress(Player player, final GunData data, double spread, boolean zoom) {
public void shootBullet(Player player, GunData data, double spread, boolean zoom) {
if (data.reloading()) return;
ItemStack stack = data.stack();

View file

@ -1,30 +1,19 @@
package com.atsuishio.superbwarfare.network.message.send;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity;
import com.atsuishio.superbwarfare.event.GunEventHandler;
import com.atsuishio.superbwarfare.init.ModAttachments;
import com.atsuishio.superbwarfare.init.ModPerks;
import com.atsuishio.superbwarfare.init.ModTags;
import com.atsuishio.superbwarfare.item.gun.GunItem;
import com.atsuishio.superbwarfare.item.gun.ReleaseSpecialWeapon;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import com.atsuishio.superbwarfare.perk.AmmoPerk;
import com.atsuishio.superbwarfare.perk.Perk;
import io.netty.buffer.ByteBuf;
import net.minecraft.core.Holder;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
/**
* 开火按键按下/松开时的处理
*/
@ -54,24 +43,14 @@ public record FireKeyMessage(int msgType, double power, boolean zoom) implements
handleGunBolt(player, stack);
if (type == 0) {
if (data.reload.prepareTimer.get() == 0 && data.reloading() && data.ammo.get() > 0) {
data.forceStop.set(true);
}
player.getData(ModAttachments.PLAYER_VARIABLE).modify(player, cap -> cap.edit = false);
// 按下开火
if (stack.getItem() instanceof ReleaseSpecialWeapon releaseSpecialWeapon) {
releaseSpecialWeapon.fireOnPress(player, data, zoom);
}
data.item.onFireKeyPress(data, player, zoom);
} else if (type == 1) {
// 松开开火
if (stack.getItem() instanceof ReleaseSpecialWeapon releaseSpecialWeapon) {
releaseSpecialWeapon.fireOnRelease(player, data, power, zoom);
}
data.item.onFireKeyRelease(data, player, power, zoom);
}
data.save();
}
@ -93,110 +72,6 @@ public record FireKeyMessage(int msgType, double power, boolean zoom) implements
}
}
public static double perkDamage(Perk perk) {
if (perk instanceof AmmoPerk ammoPerk) {
return ammoPerk.damageRate;
}
return 1;
}
public static double perkSpeed(Perk perk) {
if (perk instanceof AmmoPerk ammoPerk) {
return ammoPerk.speedRate;
}
return 1;
}
public static void spawnBullet(Player player, double power, boolean zoom) {
ItemStack stack = player.getMainHandItem();
if (player.level().isClientSide()) return;
if (!(stack.getItem() instanceof GunItem)) return;
var data = GunData.from(stack);
var perk = data.perk.get(Perk.Type.AMMO);
float headshot = (float) data.headshot();
float velocity = (float) (24 * power * (float) perkSpeed(perk));
float bypassArmorRate = (float) data.bypassArmor();
double damage;
float spread;
if (zoom) {
spread = 0.01f;
damage = 0.08333333 * data.damage() *
12 * power * perkDamage(perk);
} else {
spread = perk instanceof AmmoPerk ammoPerk && ammoPerk.slug ? 0.5f : 2.5f;
damage = (perk instanceof AmmoPerk ammoPerk && ammoPerk.slug ? 0.08333333 : 0.008333333) *
data.damage() * 12 * power * perkDamage(perk);
}
ProjectileEntity projectile = new ProjectileEntity(player.level())
.shooter(player)
.headShot(headshot)
.zoom(zoom)
.setGunItemId(stack);
if (perk instanceof AmmoPerk ammoPerk) {
int level = data.perk.getLevel(perk);
bypassArmorRate += ammoPerk.bypassArmorRate + (perk == ModPerks.AP_BULLET.get() ? 0.05f * (level - 1) : 0);
projectile.setRGB(ammoPerk.rgb);
if (!ammoPerk.mobEffects.get().isEmpty()) {
int amplifier;
if (perk.descriptionId.equals("blade_bullet")) {
amplifier = level / 3;
} else if (perk.descriptionId.equals("bread_bullet")) {
amplifier = 1;
} else {
amplifier = level - 1;
}
ArrayList<MobEffectInstance> mobEffectInstances = new ArrayList<>();
for (MobEffect effect : ammoPerk.mobEffects.get()) {
mobEffectInstances.add(new MobEffectInstance(Holder.direct(effect), 70 + 30 * level, amplifier));
}
projectile.effect(mobEffectInstances);
}
if (perk.descriptionId.equals("bread_bullet")) {
projectile.knockback(level * 0.3f);
projectile.forceKnockback();
}
}
bypassArmorRate = Math.max(bypassArmorRate, 0);
projectile.bypassArmorRate(bypassArmorRate);
if (perk == ModPerks.SILVER_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.undeadMultiple(1.0f + 0.5f * level);
} else if (perk == ModPerks.BEAST_BULLET.get()) {
projectile.beast();
} else if (perk == ModPerks.JHP_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.jhpBullet(level);
} else if (perk == ModPerks.HE_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.heBullet(level);
} else if (perk == ModPerks.INCENDIARY_BULLET.get()) {
int level = data.perk.getLevel(perk);
projectile.fireBullet(level, !zoom);
}
var dmgPerk = data.perk.get(Perk.Type.DAMAGE);
if (dmgPerk == ModPerks.MONSTER_HUNTER.get()) {
int perkLevel = data.perk.getLevel(dmgPerk);
projectile.monsterMultiple(0.1f + 0.1f * perkLevel);
}
projectile.setPos(player.getX() - 0.1 * player.getLookAngle().x, player.getEyeY() - 0.1 - 0.1 * player.getLookAngle().y, player.getZ() + -0.1 * player.getLookAngle().z);
projectile.shoot(player, player.getLookAngle().x, player.getLookAngle().y, player.getLookAngle().z, (!zoom && perk == ModPerks.INCENDIARY_BULLET.get() ? 0.2f : 1) * velocity, spread);
projectile.damage((float) damage);
player.level().addFreshEntity(projectile);
}
@Override
public @NotNull Type<? extends CustomPacketPayload> type() {
return TYPE;

View file

@ -1,24 +1,13 @@
package com.atsuishio.superbwarfare.network.message.send;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.event.GunEventHandler;
import com.atsuishio.superbwarfare.init.ModItems;
import com.atsuishio.superbwarfare.init.ModPerks;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.init.ModTags;
import com.atsuishio.superbwarfare.item.gun.GunItem;
import com.atsuishio.superbwarfare.item.gun.data.GunData;
import com.atsuishio.superbwarfare.perk.AmmoPerk;
import com.atsuishio.superbwarfare.perk.Perk;
import com.atsuishio.superbwarfare.tools.InventoryTool;
import com.atsuishio.superbwarfare.tools.SoundTool;
import io.netty.buffer.ByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import org.jetbrains.annotations.NotNull;
@ -38,79 +27,13 @@ public record ShootMessage(double spread, boolean zoom) implements CustomPacketP
pressAction(context.player(), message.spread, message.zoom);
}
public static void pressAction(Player player, double spared, boolean zoom) {
ItemStack stack = player.getMainHandItem();
public static void pressAction(Player player, double spread, boolean zoom) {
var stack = player.getMainHandItem();
if (!(stack.getItem() instanceof GunItem)) return;
var data = GunData.from(stack);
var tag = data.tag();
if (stack.is(ModTags.Items.NORMAL_GUN)) {
int projectileAmount = data.projectileAmount();
data.item.onShoot(data, player, spread, zoom);
if (data.ammo.get() > 0) {
// 空仓挂机
if (data.ammo.get() == 1) {
data.holdOpen.set(true);
}
// TODO 替换左轮判断方式
if (stack.is(ModTags.Items.REVOLVER)) {
data.canImmediatelyShoot.set(true);
}
// TODO 替换左轮判断方式
// 判断是否为栓动武器BoltActionTime > 0并在开火后给一个需要上膛的状态
if (data.defaultActionTime() > 0 && data.ammo.get() > (stack.is(ModTags.Items.REVOLVER) ? 0 : 1)) {
data.bolt.needed.set(true);
}
// 调用事件
data.item.onShoot(data, player);
data.ammo.set(data.ammo.get() - 1);
data.isEmpty.set(true);
var perk = data.perk.get(Perk.Type.AMMO);
for (int index0 = 0; index0 < (perk instanceof AmmoPerk ammoPerk && ammoPerk.slug ? 1 : projectileAmount); index0++) {
GunEventHandler.gunShoot(player, data, spared, zoom);
}
GunEventHandler.playGunSounds(player, zoom);
}
} else if (stack.is(ModItems.MINIGUN.get())) {
if (data.hasAmmo(player)) {
// TODO 替换为通用过热处理
tag.putDouble("heat", (tag.getDouble("heat") + 0.1));
if (tag.getDouble("heat") >= 50.5) {
tag.putDouble("overheat", 40);
player.getCooldowns().addCooldown(stack.getItem(), 40);
if (!player.level().isClientSide() && player instanceof ServerPlayer serverPlayer) {
SoundTool.playLocalSound(serverPlayer, ModSounds.MINIGUN_OVERHEAT.get(), 2f, 1f);
}
}
float pitch = tag.getDouble("heat") <= 40 ? 1 : (float) (1 - 0.025 * Math.abs(40 - tag.getDouble("heat")));
var perk = data.perk.get(Perk.Type.AMMO);
if (!player.level().isClientSide() && player instanceof ServerPlayer) {
float soundRadius = (float) data.soundRadius();
player.playSound(ModSounds.MINIGUN_FIRE_3P.get(), soundRadius * 0.2f, pitch);
player.playSound(ModSounds.MINIGUN_FAR.get(), soundRadius * 0.5f, pitch);
player.playSound(ModSounds.MINIGUN_VERYFAR.get(), soundRadius, pitch);
if (perk == ModPerks.BEAST_BULLET.get()) {
player.playSound(ModSounds.HENG.get(), 4f, pitch);
}
}
GunEventHandler.gunShoot(player, data, spared, false);
if (!InventoryTool.hasCreativeAmmoBox(player)) {
data.consumeAmmo(player, 1);
}
}
}
data.save();
}