移植Capability,添加弹药物品

This commit is contained in:
Light_Quanta 2025-03-26 04:35:32 +08:00
parent 47896a82fe
commit 66a2c03bf5
No known key found for this signature in database
GPG key ID: 11A39A1B8C890959
33 changed files with 1305 additions and 232 deletions

View file

@ -1,11 +1,11 @@
package com.atsuishio.superbwarfare;
import com.atsuishio.superbwarfare.capability.CapabilityHandler;
import com.atsuishio.superbwarfare.component.ModDataComponents;
import com.atsuishio.superbwarfare.config.ClientConfig;
import com.atsuishio.superbwarfare.config.CommonConfig;
import com.atsuishio.superbwarfare.config.ServerConfig;
import com.atsuishio.superbwarfare.init.*;
import com.atsuishio.superbwarfare.network.NetworkRegistry;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.bus.api.SubscribeEvent;
@ -56,7 +56,7 @@ public class ModUtils {
// bus.addListener(this::onCommonSetup);
// bus.addListener(this::onClientSetup);
CapabilityHandler.register(bus);
bus.addListener(NetworkRegistry::register);
NeoForge.EVENT_BUS.register(this);
}

View file

@ -1,5 +1,6 @@
package com.atsuishio.superbwarfare.block;
import com.atsuishio.superbwarfare.capability.ModCapabilities;
import com.atsuishio.superbwarfare.init.ModSounds;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@ -122,10 +123,10 @@ public class JumpPadBlock extends Block {
level.playLocalSound(pos.getX(), pos.getY(), pos.getZ(), ModSounds.JUMP.get(), SoundSource.BLOCKS, 1, 1, false);
}
// TODO capability
// entity.getCapability(ModVariables.PLAYER_VARIABLES_CAPABILITY, null).ifPresent(capability -> {
// capability.playerDoubleJump = true;
// capability.syncPlayerVariables(entity);
// });
var capability = entity.getCapability(ModCapabilities.PLAYER_VARIABLE);
if (capability != null) {
capability.playerDoubleJump = true;
capability.syncPlayerVariables(entity);
}
}
}

View file

@ -1,29 +0,0 @@
package com.atsuishio.superbwarfare.capability;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
public class CapabilityHandler {
private static final CapabilityHandler INSTANCE = new CapabilityHandler();
public static void register(IEventBus bus) {
bus.addListener(INSTANCE::registerCapabilities);
}
public void registerCapabilities(RegisterCapabilitiesEvent event) {
for (EntityType<?> entityType : BuiltInRegistries.ENTITY_TYPE) {
event.registerEntity(ModCapabilities.LASER_CAPABILITY, entityType,
(entity, ctx) -> {
if (entity instanceof Player) {
return new LaserCapability.LaserCapabilityImpl();
}
return null;
});
}
}
}

View file

@ -1,100 +0,0 @@
package com.atsuishio.superbwarfare.capability;
import com.atsuishio.superbwarfare.ModUtils;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.neoforged.neoforge.capabilities.ICapabilityProvider;
import net.neoforged.neoforge.common.util.INBTSerializable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;
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();
void end();
}
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 void end() {
if (this.laserHandler != null) {
this.laserHandler.end();
}
}
@Override
public @UnknownNullability CompoundTag serializeNBT(HolderLookup.@NotNull Provider provider) {
CompoundTag tag = new CompoundTag();
if (this.laserHandler != null) {
tag.put("Laser", this.laserHandler.writeNBT());
}
return tag;
}
@Override
public void deserializeNBT(HolderLookup.@NotNull Provider provider, @NotNull CompoundTag compoundTag) {
if (compoundTag.contains("Laser") && this.laserHandler != null) {
this.laserHandler.readNBT(compoundTag.getCompound("Laser"));
}
}
}
public static class LaserCapabilityProvider implements ICapabilityProvider<Player, Void, ILaserCapability>, INBTSerializable<CompoundTag> {
private final LaserCapabilityImpl instance = new LaserCapabilityImpl();
@Override
public @Nullable ILaserCapability getCapability(@NotNull Player object, Void context) {
return object.getCapability(ModCapabilities.LASER_CAPABILITY, context);
}
@Override
public @UnknownNullability CompoundTag serializeNBT(HolderLookup.@NotNull Provider provider) {
return instance.serializeNBT(provider);
}
@Override
public void deserializeNBT(HolderLookup.@NotNull Provider provider, @NotNull CompoundTag nbt) {
instance.deserializeNBT(provider, nbt);
}
}
}

View file

@ -1,10 +1,13 @@
package com.atsuishio.superbwarfare.capability;
import com.atsuishio.superbwarfare.ModUtils;
import com.atsuishio.superbwarfare.capability.laser.LaserCapability;
import com.atsuishio.superbwarfare.capability.player.PlayerVariable;
import net.neoforged.neoforge.capabilities.EntityCapability;
public class ModCapabilities {
public static final EntityCapability<LaserCapability.ILaserCapability, Void> LASER_CAPABILITY = EntityCapability.createVoid(ModUtils.loc("laser_capability"), LaserCapability.ILaserCapability.class);
public static final EntityCapability<LaserCapability, Void> LASER_CAPABILITY = EntityCapability.createVoid(ModUtils.loc("laser_capability"), LaserCapability.class);
public static final EntityCapability<PlayerVariable, Void> PLAYER_VARIABLE = EntityCapability.createVoid(ModUtils.loc("player_variable"), PlayerVariable.class);
}

View file

@ -1,18 +1,22 @@
package com.atsuishio.superbwarfare.capability.energy;
import net.minecraft.world.item.ItemStack;
import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.capabilities.ICapabilityProvider;
import net.neoforged.neoforge.energy.EnergyStorage;
import net.neoforged.neoforge.energy.IEnergyStorage;
import org.jetbrains.annotations.NotNull;
public class ItemEnergyProvider implements ICapabilityProvider<ItemStack, Void, IEnergyStorage> {
private final ItemStack stack;
private final EnergyStorage energyStorage;
public ItemEnergyProvider(ItemStack stack, int energyCapacity) {
this.stack = stack;
this.energyStorage = new EnergyStorage(energyCapacity);
}
@Override
public @org.jetbrains.annotations.Nullable IEnergyStorage getCapability(@NotNull ItemStack object, Void context) {
return object.getCapability(Capabilities.EnergyStorage.ITEM);
return energyStorage;
}
}

View file

@ -0,0 +1,51 @@
package com.atsuishio.superbwarfare.capability.laser;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.UnknownNullability;
public class LaserCapability {
public LaserHandler laserHandler;
public void init(LaserHandler handler) {
this.laserHandler = handler;
}
public void start() {
this.laserHandler.start();
}
public void tick() {
}
public void stop() {
if (this.laserHandler != null) {
this.laserHandler.stop();
}
}
public void end() {
if (this.laserHandler != null) {
this.laserHandler.end();
}
}
public @UnknownNullability CompoundTag serializeNBT(HolderLookup.@NotNull Provider provider) {
CompoundTag tag = new CompoundTag();
if (this.laserHandler != null) {
tag.put("Laser", this.laserHandler.writeNBT());
}
return tag;
}
public void deserializeNBT(HolderLookup.@NotNull Provider provider, @NotNull CompoundTag compoundTag) {
if (compoundTag.contains("Laser") && this.laserHandler != null) {
this.laserHandler.readNBT(compoundTag.getCompound("Laser"));
}
}
}

View file

@ -0,0 +1,42 @@
package com.atsuishio.superbwarfare.capability.laser;
import com.atsuishio.superbwarfare.ModUtils;
import com.atsuishio.superbwarfare.capability.ModCapabilities;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.capabilities.ICapabilityProvider;
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
import net.neoforged.neoforge.common.util.INBTSerializable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;
@EventBusSubscriber(modid = ModUtils.MODID, bus = EventBusSubscriber.Bus.MOD)
public class LaserCapabilityProvider implements ICapabilityProvider<Player, Void, LaserCapability>, INBTSerializable<CompoundTag> {
private final LaserCapability instance = new LaserCapability();
@Override
public @Nullable LaserCapability getCapability(@NotNull Player object, Void context) {
return object.getCapability(ModCapabilities.LASER_CAPABILITY, context);
}
@Override
public @UnknownNullability CompoundTag serializeNBT(HolderLookup.@NotNull Provider provider) {
return instance.serializeNBT(provider);
}
@Override
public void deserializeNBT(HolderLookup.@NotNull Provider provider, @NotNull CompoundTag nbt) {
instance.deserializeNBT(provider, nbt);
}
@SubscribeEvent
public static void registerCapabilities(RegisterCapabilitiesEvent event) {
event.registerEntity(ModCapabilities.LASER_CAPABILITY, EntityType.PLAYER, new LaserCapabilityProvider());
}
}

View file

@ -1,4 +1,4 @@
package com.atsuishio.superbwarfare.capability;
package com.atsuishio.superbwarfare.capability.laser;
import com.atsuishio.superbwarfare.entity.projectile.AbstractLaserEntity;
import net.minecraft.nbt.CompoundTag;

View file

@ -0,0 +1,54 @@
package com.atsuishio.superbwarfare.capability.player;
import com.atsuishio.superbwarfare.ModUtils;
import com.atsuishio.superbwarfare.network.message.SavedDataSyncMessage;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.saveddata.SavedData;
import net.neoforged.neoforge.network.PacketDistributor;
import org.jetbrains.annotations.NotNull;
public class ModVariables {
// 这玩意有用吗
public static class WorldVariables extends SavedData {
public static final String DATA_NAME = ModUtils.MODID + "_world_variables";
public static WorldVariables load(CompoundTag tag, HolderLookup.Provider provider) {
WorldVariables data = new WorldVariables();
data.read(tag);
return data;
}
public void read(CompoundTag nbt) {
}
@Override
public @NotNull CompoundTag save(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
return tag;
}
public void syncData(LevelAccessor world) {
this.setDirty();
if (world instanceof Level level && !level.isClientSide()) {
PacketDistributor.sendToAllPlayers(new SavedDataSyncMessage(1, this, null));
}
}
public static WorldVariables clientSide = new WorldVariables();
public static WorldVariables get(LevelAccessor world) {
if (world instanceof ServerLevel level)
return level.getDataStorage().computeIfAbsent(new Factory<>(
WorldVariables::new, WorldVariables::load, null
), DATA_NAME);
return clientSide;
}
}
}

View file

@ -0,0 +1,167 @@
package com.atsuishio.superbwarfare.capability.player;
import com.atsuishio.superbwarfare.ModUtils;
import com.atsuishio.superbwarfare.capability.ModCapabilities;
import com.atsuishio.superbwarfare.network.message.PlayerVariablesSyncMessage;
import com.atsuishio.superbwarfare.network.message.SavedDataSyncMessage;
import com.atsuishio.superbwarfare.tools.AmmoType;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.saveddata.SavedData;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.network.PacketDistributor;
@EventBusSubscriber(modid = ModUtils.MODID)
public class PlayerVariable {
public boolean zoom = false;
public boolean holdFire = false;
public int rifleAmmo = 0;
public int handgunAmmo = 0;
public int shotgunAmmo = 0;
public int sniperAmmo = 0;
public int heavyAmmo = 0;
public boolean bowPullHold = false;
public boolean bowPull = false;
public boolean playerDoubleJump = false;
public boolean tacticalSprint = false;
public int tacticalSprintTime = 600;
public boolean tacticalSprintExhaustion = false;
public boolean breath = false;
public int breathTime = 160;
public boolean breathExhaustion = false;
public boolean edit = false;
public void syncPlayerVariables(Entity entity) {
if (entity instanceof ServerPlayer) {
PacketDistributor.sendToAllPlayers(new PlayerVariablesSyncMessage(entity.getId(), this.writeToNBT()));
}
}
public CompoundTag writeToNBT() {
CompoundTag nbt = new CompoundTag();
nbt.putBoolean("Zoom", zoom);
nbt.putBoolean("HoldFire", holdFire);
for (var type : AmmoType.values()) {
type.set(nbt, type.get(this));
}
nbt.putBoolean("BowPullHold", bowPullHold);
nbt.putBoolean("BowPull", bowPull);
nbt.putBoolean("DoubleJump", playerDoubleJump);
nbt.putBoolean("TacticalSprint", tacticalSprint);
nbt.putInt("TacticalSprintTime", tacticalSprintTime);
nbt.putBoolean("TacticalSprintExhaustion", tacticalSprintExhaustion);
nbt.putBoolean("Breath", breath);
nbt.putInt("BreathTime", breathTime);
nbt.putBoolean("BreathExhaustion", breathExhaustion);
nbt.putBoolean("EditMode", edit);
return nbt;
}
public PlayerVariable readFromNBT(Tag tag) {
CompoundTag nbt = (CompoundTag) tag;
zoom = nbt.getBoolean("Zoom");
holdFire = nbt.getBoolean("HoldFire");
for (var type : AmmoType.values()) {
type.set(this, type.get(nbt));
}
bowPullHold = nbt.getBoolean("BowPullHold");
bowPull = nbt.getBoolean("BowPull");
playerDoubleJump = nbt.getBoolean("DoubleJump");
tacticalSprint = nbt.getBoolean("TacticalSprint");
tacticalSprintTime = nbt.getInt("TacticalSprintTime");
tacticalSprintExhaustion = nbt.getBoolean("TacticalSprintExhaustion");
breath = nbt.getBoolean("Breath");
breathTime = nbt.getInt("BreathTime");
breathExhaustion = nbt.getBoolean("BreathExhaustion");
edit = nbt.getBoolean("EditMode");
return this;
}
@SubscribeEvent
public static void onPlayerLoggedInSyncPlayerVariables(PlayerEvent.PlayerLoggedInEvent event) {
if (event.getEntity().level().isClientSide()) return;
var player = event.getEntity();
var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE, null);
if (cap != null) cap.syncPlayerVariables(player);
}
@SubscribeEvent
public static void onPlayerRespawnedSyncPlayerVariables(PlayerEvent.PlayerRespawnEvent event) {
if (event.getEntity().level().isClientSide()) return;
var player = event.getEntity();
var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE, null);
if (cap != null) cap.syncPlayerVariables(player);
}
@SubscribeEvent
public static void onPlayerChangedDimensionSyncPlayerVariables(PlayerEvent.PlayerChangedDimensionEvent event) {
if (event.getEntity().level().isClientSide()) return;
var player = event.getEntity();
var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE, null);
if (cap != null) cap.syncPlayerVariables(player);
}
@SubscribeEvent
public static void clonePlayer(PlayerEvent.Clone event) {
event.getOriginal().revive();
var original = event.getOriginal().getCapability(ModCapabilities.PLAYER_VARIABLE, null);
var clone = event.getEntity().getCapability(ModCapabilities.PLAYER_VARIABLE, null);
if (clone == null || original == null) return;
clone.zoom = original.zoom;
clone.holdFire = original.holdFire;
clone.rifleAmmo = original.rifleAmmo;
clone.handgunAmmo = original.handgunAmmo;
clone.shotgunAmmo = original.shotgunAmmo;
clone.sniperAmmo = original.sniperAmmo;
clone.heavyAmmo = original.heavyAmmo;
clone.bowPullHold = original.bowPullHold;
clone.bowPull = original.bowPull;
clone.playerDoubleJump = original.playerDoubleJump;
clone.tacticalSprint = original.tacticalSprint;
clone.tacticalSprintTime = original.tacticalSprintTime;
clone.tacticalSprintExhaustion = original.tacticalSprintExhaustion;
clone.breath = original.breath;
clone.breathTime = original.breathTime;
clone.breathExhaustion = original.breathExhaustion;
clone.edit = original.edit;
if (event.getEntity().level().isClientSide()) return;
var player = event.getEntity();
var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE, null);
if (cap != null) cap.syncPlayerVariables(player);
}
@SubscribeEvent
public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) {
if (event.getEntity().level().isClientSide()) return;
SavedData worldData = ModVariables.WorldVariables.get(event.getEntity().level());
if (worldData != null) {
PacketDistributor.sendToPlayer((ServerPlayer) event.getEntity(), new SavedDataSyncMessage(1, worldData, null));
}
}
@SubscribeEvent
public static void onPlayerChangedDimension(PlayerEvent.PlayerChangedDimensionEvent event) {
if (event.getEntity().level().isClientSide()) return;
SavedData worldData = ModVariables.WorldVariables.get(event.getEntity().level());
if (worldData != null) {
PacketDistributor.sendToPlayer((ServerPlayer) event.getEntity(), new SavedDataSyncMessage(1, worldData, null));
}
}
}

View file

@ -0,0 +1,42 @@
package com.atsuishio.superbwarfare.capability.player;
import com.atsuishio.superbwarfare.ModUtils;
import com.atsuishio.superbwarfare.capability.ModCapabilities;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.capabilities.ICapabilityProvider;
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
import net.neoforged.neoforge.common.util.INBTSerializable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;
@EventBusSubscriber(modid = ModUtils.MODID, bus = EventBusSubscriber.Bus.MOD)
public class PlayerVariablesProvider implements ICapabilityProvider<Player, Void, PlayerVariable>, INBTSerializable<CompoundTag> {
private final PlayerVariable playerVariables = new PlayerVariable();
@Override
public @Nullable PlayerVariable getCapability(@NotNull Player object, Void context) {
return playerVariables;
}
@Override
public @UnknownNullability CompoundTag serializeNBT(HolderLookup.@NotNull Provider provider) {
return playerVariables.writeToNBT();
}
@Override
public void deserializeNBT(HolderLookup.@NotNull Provider provider, @NotNull CompoundTag nbt) {
playerVariables.readFromNBT(nbt);
}
@SubscribeEvent
public static void init(RegisterCapabilitiesEvent event) {
event.registerEntity(ModCapabilities.PLAYER_VARIABLE, EntityType.PLAYER, new PlayerVariablesProvider());
}
}

View file

@ -0,0 +1,202 @@
package com.atsuishio.superbwarfare.client.overlay;
import com.atsuishio.superbwarfare.ModUtils;
import com.atsuishio.superbwarfare.capability.ModCapabilities;
import com.atsuishio.superbwarfare.component.ModDataComponents;
import com.atsuishio.superbwarfare.init.ModItems;
import com.atsuishio.superbwarfare.item.common.ammo.AmmoSupplierItem;
import com.atsuishio.superbwarfare.item.common.ammo.box.AmmoBoxInfo;
import com.atsuishio.superbwarfare.tools.AmmoType;
import com.atsuishio.superbwarfare.tools.animation.AnimationCurves;
import com.atsuishio.superbwarfare.tools.animation.AnimationTimer;
import com.atsuishio.superbwarfare.tools.animation.ValueAnimator;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import net.minecraft.util.FastColor;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.event.RenderGuiEvent;
@EventBusSubscriber(modid = ModUtils.MODID, value = Dist.CLIENT)
public class AmmoOverlay {
private static final AnimationTimer ammoInfoTimer = new AnimationTimer(500, 2000)
.forwardAnimation(AnimationCurves.EASE_OUT_EXPO)
.backwardAnimation(AnimationCurves.EASE_IN_EXPO);
private static final AnimationTimer ammoBoxTimer = new AnimationTimer(500)
.forwardAnimation(AnimationCurves.EASE_OUT_EXPO)
.backwardAnimation(AnimationCurves.EASE_IN_EXPO);
private static final ValueAnimator<Integer>[] ammoCountAnimators = ValueAnimator.create(
AmmoType.values().length, 800, 0
);
private static final ValueAnimator<Integer>[] ammoBoxAnimators = ValueAnimator.create(
AmmoType.values().length, 800, 0
);
/**
* 在手持弹药或弹药盒时渲染玩家弹药总量信息
*/
@SubscribeEvent
public static void renderAmmoInfo(RenderGuiEvent.Pre event) {
boolean startRenderingAmmoInfo = false;
Player player = Minecraft.getInstance().player;
if (player == null || player.isSpectator()) return;
boolean isAmmoBox = false;
// 动画计算
var currentTime = System.currentTimeMillis();
ItemStack stack = player.getMainHandItem();
if ((stack.getItem() instanceof AmmoSupplierItem || stack.getItem() == ModItems.AMMO_BOX.get())
// TODO vehicle
// && !(player.getVehicle() instanceof ArmedVehicleEntity vehicle && vehicle.banHand(player))
) {
// 刚拿出弹药物品时视为开始弹药信息渲染
startRenderingAmmoInfo = ammoInfoTimer.getProgress(currentTime) == 0;
ammoInfoTimer.forward(currentTime);
if (stack.getItem() == ModItems.AMMO_BOX.get()) {
isAmmoBox = true;
ammoBoxTimer.forward(currentTime);
} else {
ammoBoxTimer.backward(currentTime);
}
} else {
ammoInfoTimer.backward(currentTime);
ammoBoxTimer.backward(currentTime);
}
if (!ammoInfoTimer.isForward() && ammoInfoTimer.finished(currentTime)) return;
var poseStack = event.getGuiGraphics().pose();
poseStack.pushPose();
int w = event.getGuiGraphics().guiWidth();
int h = event.getGuiGraphics().guiHeight();
var ammoX = ammoInfoTimer.lerp(w + 120, (float) w / 2 + 40, currentTime);
final int fontHeight = 15;
var yOffset = (-h - AmmoType.values().length * fontHeight) / 2f;
// 渲染总弹药数量
var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE, null);
if (cap == null) return;
var font = Minecraft.getInstance().font;
for (var type : AmmoType.values()) {
var index = type.ordinal();
var ammoCount = type.get(cap);
var animator = ammoCountAnimators[index];
var boxAnimator = ammoBoxAnimators[index];
var boxAmmoCount = boxAnimator.newValue();
boolean boxAmmoSelected = false;
if (isAmmoBox) {
var info = stack.get(ModDataComponents.AMMO_BOX_INFO);
if (info == null) info = new AmmoBoxInfo("All", false);
var ammoBoxType = info.type();
boxAmmoCount = type.get(stack);
if (ammoBoxType.equals("All") || ammoBoxType.equals(type.name)) {
boxAnimator.forward(currentTime);
boxAmmoSelected = true;
} else {
boxAnimator.reset(boxAmmoCount);
}
}
// 首次开始渲染弹药信息时记录弹药数量便于后续播放动画
if (startRenderingAmmoInfo) {
animator.reset(ammoCount);
animator.endForward(currentTime);
if (isAmmoBox) {
boxAnimator.reset(type.get(stack));
boxAnimator.endForward(currentTime);
}
}
int ammoAdd = Integer.compare(ammoCount, animator.oldValue());
// 弹药数量变化时更新并开始播放弹药数量更改动画
animator.compareAndUpdate(ammoCount, () -> {
// 弹药数量变化时开始播放弹药数量更改动画
animator.beginForward(currentTime);
});
var progress = animator.getProgress(currentTime);
var ammoCountStr = Integer.toString(
Math.round(animator.lerp(animator.oldValue(), ammoCount, currentTime))
);
// 弹药增加时颜色由绿变白否则由红变白
var fontColor = FastColor.ARGB32.lerp(progress, switch (ammoAdd) {
case 1 -> 0xFF00FF00;
case -1 -> 0xFFFF0000;
default -> 0xFFFFFFFF;
}, 0xFFFFFFFF);
RenderSystem.setShaderColor(1, 1, 1, ammoInfoTimer.lerp(0, 1, currentTime));
// 弹药数量
event.getGuiGraphics().drawString(
font,
ammoCountStr,
ammoX + (30 - font.width(ammoCountStr)),
h + yOffset,
fontColor,
true
);
// 弹药类型
event.getGuiGraphics().drawString(
font,
Component.translatable(type.translatableKey).getString(),
ammoX + 35,
h + yOffset,
fontColor,
true
);
// 弹药盒信息渲染
RenderSystem.setShaderColor(1, 1, 1, ammoBoxTimer.lerp(0, 1, currentTime));
var ammoBoxX = ammoBoxTimer.lerp(-30, (float) w / 2, currentTime);
int ammoBoxAdd = Integer.compare(boxAmmoCount, boxAnimator.oldValue());
boxAnimator.compareAndUpdate(boxAmmoCount, () -> boxAnimator.beginForward(currentTime));
// 选中时显示为黄色否则为白色
var targetColor = boxAmmoSelected ? 0xFFFFFF00 : 0xFFFFFFFF;
var boxFontColor = FastColor.ARGB32.lerp(boxAnimator.getProgress(currentTime),
switch (ammoBoxAdd) {
case 1 -> 0xFF00FF00;
case -1 -> 0xFFFF0000;
default -> targetColor;
},
targetColor
);
// 弹药盒内弹药数量
event.getGuiGraphics().drawString(
Minecraft.getInstance().font,
Integer.toString(
Math.round(boxAnimator.lerp(boxAnimator.oldValue(), boxAmmoCount, currentTime))
),
ammoBoxX - 70,
h + yOffset,
boxFontColor,
true
);
yOffset += fontHeight;
}
RenderSystem.setShaderColor(1, 1, 1, 1);
poseStack.popPose();
}
}

View file

@ -1,6 +1,8 @@
package com.atsuishio.superbwarfare.component;
import com.atsuishio.superbwarfare.ModUtils;
import com.atsuishio.superbwarfare.item.common.ammo.box.AmmoBoxInfo;
import com.atsuishio.superbwarfare.tools.AmmoType;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.component.DataComponentType;
@ -25,11 +27,20 @@ public class ModDataComponents {
builder -> builder.persistent(Codec.INT)
);
public static final DeferredHolder<DataComponentType<?>, DataComponentType<AmmoBoxInfo>> AMMO_BOX_INFO = register(
"ammo_box_type",
builder -> builder.persistent(AmmoBoxInfo.CODEC)
);
private static <T> DeferredHolder<DataComponentType<?>, DataComponentType<T>> register(String name, UnaryOperator<DataComponentType.Builder<T>> builderOperator) {
return DATA_COMPONENT_TYPES.register(name, () -> builderOperator.apply(DataComponentType.builder()).build());
}
public static void register(IEventBus eventBus) {
for (var type : AmmoType.values()) {
type.dataComponent = register("ammo_" + type.name.toLowerCase(), builder -> builder.persistent(Codec.INT));
}
DATA_COMPONENT_TYPES.register(eventBus);
}

View file

@ -5,6 +5,9 @@ import com.atsuishio.superbwarfare.item.*;
import com.atsuishio.superbwarfare.item.common.BlueprintItem;
import com.atsuishio.superbwarfare.item.common.CannonShellItem;
import com.atsuishio.superbwarfare.item.common.MaterialPack;
import com.atsuishio.superbwarfare.item.common.ammo.*;
import com.atsuishio.superbwarfare.item.common.ammo.box.AmmoBox;
import com.atsuishio.superbwarfare.tools.AmmoType;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.BlockItem;
@ -64,23 +67,23 @@ public class ModItems {
*/
public static final DeferredRegister<Item> AMMO = DeferredRegister.create(BuiltInRegistries.ITEM, ModUtils.MODID);
// public static final DeferredHolder<Item, Item> HANDGUN_AMMO = AMMO.register("handgun_ammo", () -> new AmmoSupplierItem(AmmoType.HANDGUN, 1, new Item.Properties()));
// public static final DeferredHolder<Item, Item> RIFLE_AMMO = AMMO.register("rifle_ammo", () -> new AmmoSupplierItem(AmmoType.RIFLE, 1, new Item.Properties()));
// public static final DeferredHolder<Item, Item> SNIPER_AMMO = AMMO.register("sniper_ammo", () -> new AmmoSupplierItem(AmmoType.SNIPER, 1, new Item.Properties()));
// public static final DeferredHolder<Item, Item> SHOTGUN_AMMO = AMMO.register("shotgun_ammo", () -> new AmmoSupplierItem(AmmoType.SHOTGUN, 1, new Item.Properties()));
// public static final DeferredHolder<Item, Item> HEAVY_AMMO = AMMO.register("heavy_ammo", () -> new AmmoSupplierItem(AmmoType.HEAVY, 1, new Item.Properties()));
// public static final DeferredHolder<Item, Item> HANDGUN_AMMO_BOX = AMMO.register("handgun_ammo_box", HandgunAmmoBox::new);
// public static final DeferredHolder<Item, Item> RIFLE_AMMO_BOX = AMMO.register("rifle_ammo_box", RifleAmmoBox::new);
// public static final DeferredHolder<Item, Item> SNIPER_AMMO_BOX = AMMO.register("sniper_ammo_box", SniperAmmoBox::new);
// public static final DeferredHolder<Item, Item> SHOTGUN_AMMO_BOX = AMMO.register("shotgun_ammo_box", ShotgunAmmoBox::new);
// public static final DeferredHolder<Item, Item> CREATIVE_AMMO_BOX = AMMO.register("creative_ammo_box", CreativeAmmoBox::new);
// public static final DeferredHolder<Item, Item> AMMO_BOX = AMMO.register("ammo_box", AmmoBox::new);
public static final DeferredHolder<Item, Item> HANDGUN_AMMO = AMMO.register("handgun_ammo", () -> new AmmoSupplierItem(AmmoType.HANDGUN, 1, new Item.Properties()));
public static final DeferredHolder<Item, Item> RIFLE_AMMO = AMMO.register("rifle_ammo", () -> new AmmoSupplierItem(AmmoType.RIFLE, 1, new Item.Properties()));
public static final DeferredHolder<Item, Item> SNIPER_AMMO = AMMO.register("sniper_ammo", () -> new AmmoSupplierItem(AmmoType.SNIPER, 1, new Item.Properties()));
public static final DeferredHolder<Item, Item> SHOTGUN_AMMO = AMMO.register("shotgun_ammo", () -> new AmmoSupplierItem(AmmoType.SHOTGUN, 1, new Item.Properties()));
public static final DeferredHolder<Item, Item> HEAVY_AMMO = AMMO.register("heavy_ammo", () -> new AmmoSupplierItem(AmmoType.HEAVY, 1, new Item.Properties()));
public static final DeferredHolder<Item, Item> HANDGUN_AMMO_BOX = AMMO.register("handgun_ammo_box", HandgunAmmoBox::new);
public static final DeferredHolder<Item, Item> RIFLE_AMMO_BOX = AMMO.register("rifle_ammo_box", RifleAmmoBox::new);
public static final DeferredHolder<Item, Item> SNIPER_AMMO_BOX = AMMO.register("sniper_ammo_box", SniperAmmoBox::new);
public static final DeferredHolder<Item, Item> SHOTGUN_AMMO_BOX = AMMO.register("shotgun_ammo_box", ShotgunAmmoBox::new);
public static final DeferredHolder<Item, Item> CREATIVE_AMMO_BOX = AMMO.register("creative_ammo_box", CreativeAmmoBox::new);
public static final DeferredHolder<Item, Item> AMMO_BOX = AMMO.register("ammo_box", AmmoBox::new);
public static final DeferredHolder<Item, Item> TASER_ELECTRODE = AMMO.register("taser_electrode", () -> new Item(new Item.Properties()));
public static final DeferredHolder<Item, Item> GRENADE_40MM = AMMO.register("grenade_40mm", () -> new Item(new Item.Properties()));
public static final DeferredHolder<Item, Item> JAVELIN_MISSILE = AMMO.register("javelin_missile", () -> new Item(new Item.Properties()));
// public static final DeferredHolder<Item, Item> MORTAR_SHELL = AMMO.register("mortar_shell", MortarShell::new);
// public static final DeferredHolder<Item, Item> POTION_MORTAR_SHELL = AMMO.register("potion_mortar_shell", PotionMortarShell::new);
// public static final DeferredHolder<Item, Item> ROCKET = AMMO.register("rocket", Rocket::new);
public static final DeferredHolder<Item, Item> MORTAR_SHELL = AMMO.register("mortar_shell", MortarShell::new);
public static final DeferredHolder<Item, Item> POTION_MORTAR_SHELL = AMMO.register("potion_mortar_shell", PotionMortarShell::new);
public static final DeferredHolder<Item, Item> ROCKET = AMMO.register("rocket", Rocket::new);
// public static final DeferredHolder<Item, Item> LUNGE_MINE = AMMO.register("lunge_mine", LungeMine::new);
public static final DeferredHolder<Item, Item> HE_5_INCHES = AMMO.register("he_5_inches", () -> new CannonShellItem(new Item.Properties().rarity(Rarity.RARE)));
public static final DeferredHolder<Item, Item> AP_5_INCHES = AMMO.register("ap_5_inches", () -> new CannonShellItem(new Item.Properties().rarity(Rarity.RARE)));
@ -116,7 +119,7 @@ public class ModItems {
// public static final DeferredHolder<Item, Item> KNIFE = ITEMS.register("knife", Knife::new);
// public static final DeferredHolder<Item, Item> HAMMER = ITEMS.register("hammer", Hammer::new);
public static final DeferredHolder<Item, Item> CROWBAR = ITEMS.register("crowbar", Crowbar::new);
// public static final DeferredHolder<Item, Item> DEFUSER = ITEMS.register("defuser", Defuser::new);
// public static final DeferredHolder<Item, Item> DEFUSER = ITEMS.register("defuser", Defuser::new);
// public static final DeferredHolder<Item, Item> ARMOR_PLATE = ITEMS.register("armor_plate", ArmorPlate::new);
//
// public static final DeferredHolder<Item, Item> RU_HELMET_6B47 = ITEMS.register("ru_helmet_6b47", RuHelmet6b47::new);

View file

@ -16,7 +16,7 @@ public class ModTabs {
public static final DeferredRegister<CreativeModeTab> TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, ModUtils.MODID);
// public static final DeferredHolder<CreativeModeTab, CreativeModeTab> GUN_TAB = TABS.register("guns",
// public static final DeferredHolder<CreativeModeTab, CreativeModeTab> GUN_TAB = TABS.register("guns",
// () -> CreativeModeTab.builder()
// .title(Component.translatable("item_group.superbwarfare.guns"))
// .icon(() -> new ItemStack(ModItems.TASER.get()))
@ -60,28 +60,28 @@ public class ModTabs {
// )
// .build());
//
public static final DeferredHolder<CreativeModeTab, CreativeModeTab> PERK_TAB = TABS.register("perk",
public static final DeferredHolder<CreativeModeTab, CreativeModeTab> PERK_TAB = TABS.register("perk",
() -> CreativeModeTab.builder()
.title(Component.translatable("item_group.superbwarfare.perk"))
.icon(() -> new ItemStack(ModItems.AP_BULLET.get()))
// .withTabsBefore(GUN_TAB.getKey())
.displayItems((param, output) -> ModItems.PERKS.getEntries().forEach(registryObject -> output.accept(registryObject.get())))
.build());
//
public static final DeferredHolder<CreativeModeTab, CreativeModeTab> AMMO_TAB = TABS.register("ammo",
//
public static final DeferredHolder<CreativeModeTab, CreativeModeTab> AMMO_TAB = TABS.register("ammo",
() -> CreativeModeTab.builder()
.title(Component.translatable("item_group.superbwarfare.ammo"))
// .icon(() -> new ItemStack(ModItems.SHOTGUN_AMMO_BOX.get()))
.icon(() -> new ItemStack(ModItems.SHOTGUN_AMMO_BOX.get()))
.withTabsBefore(PERK_TAB.getKey())
.displayItems((param, output) -> {
ModItems.AMMO.getEntries().forEach(registryObject -> {
// if (registryObject.get() != ModItems.POTION_MORTAR_SHELL.get()) {
// output.accept(registryObject.get());
//
if (registryObject.get() != ModItems.POTION_MORTAR_SHELL.get()) {
output.accept(registryObject.get());
// if (registryObject.get() == ModItems.C4_BOMB.get()) {
// output.accept(C4Bomb.makeInstance());
// }
// }
}
});
// param.holders().lookup(Registries.POTION)

View file

@ -1,7 +1,7 @@
package com.atsuishio.superbwarfare.item;
import com.atsuishio.superbwarfare.capability.LaserHandler;
import com.atsuishio.superbwarfare.capability.ModCapabilities;
import com.atsuishio.superbwarfare.capability.laser.LaserHandler;
import com.atsuishio.superbwarfare.entity.projectile.LaserEntity;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.tools.TraceTool;

View file

@ -0,0 +1,66 @@
package com.atsuishio.superbwarfare.item.common.ammo;
import com.atsuishio.superbwarfare.capability.ModCapabilities;
import com.atsuishio.superbwarfare.init.ModItems;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.tools.AmmoType;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class AmmoSupplierItem extends Item {
public final AmmoType type;
public final int ammoToAdd;
public AmmoSupplierItem(AmmoType type, int ammoToAdd, Properties properties) {
super(properties);
this.type = type;
this.ammoToAdd = ammoToAdd;
}
@Override
public void appendHoverText(@NotNull ItemStack stack, @NotNull TooltipContext context, List<Component> tooltipComponents, @NotNull TooltipFlag tooltipFlag) {
tooltipComponents.add(Component.translatable("des.superbwarfare.ammo_supplier").withStyle(ChatFormatting.AQUA));
}
@Override
public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level level, Player player, @NotNull InteractionHand hand) {
ItemStack stack = player.getItemInHand(hand);
int count = stack.getCount();
player.getCooldowns().addCooldown(this, 10);
if (!player.isCreative()) {
stack.shrink(count);
}
ItemStack offhandItem = player.getOffhandItem();
if (offhandItem.is(ModItems.AMMO_BOX.get())) {
this.type.add(offhandItem, ammoToAdd * count);
} else {
var capability = player.getCapability(ModCapabilities.PLAYER_VARIABLE, null);
if (capability != null) {
this.type.add(capability, ammoToAdd * count);
capability.syncPlayerVariables(player);
}
}
if (!level.isClientSide()) {
player.displayClientMessage(Component.translatable("item.superbwarfare.ammo_supplier.supply", Component.translatable(this.type.translatableKey), ammoToAdd * count), true);
level.playSound(null, player.blockPosition(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 1, 1);
}
return InteractionResultHolder.success(stack);
}
}

View file

@ -0,0 +1,10 @@
package com.atsuishio.superbwarfare.item.common.ammo;
import net.minecraft.world.item.Item;
public class CannonShellItem extends Item {
public CannonShellItem(Properties properties) {
super(properties);
}
}

View file

@ -0,0 +1,24 @@
package com.atsuishio.superbwarfare.item.common.ammo;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Rarity;
import net.minecraft.world.item.TooltipFlag;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List;
public class CreativeAmmoBox extends Item {
public CreativeAmmoBox() {
super(new Properties().rarity(Rarity.EPIC).stacksTo(1));
}
@Override
@ParametersAreNonnullByDefault
public void appendHoverText(ItemStack stack, TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
tooltipComponents.add(Component.translatable("des.superbwarfare.creative_ammo_box").withStyle(ChatFormatting.GRAY));
}
}

View file

@ -0,0 +1,24 @@
package com.atsuishio.superbwarfare.item.common.ammo;
import com.atsuishio.superbwarfare.tools.AmmoType;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class HandgunAmmoBox extends AmmoSupplierItem {
public HandgunAmmoBox() {
super(AmmoType.HANDGUN, 30, new Properties());
}
@Override
public void appendHoverText(@NotNull ItemStack stack, @NotNull TooltipContext context, List<Component> tooltipComponents, @NotNull TooltipFlag tooltipFlag) {
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
tooltipComponents.add(Component.translatable("des.superbwarfare.handgun_ammo_box").withStyle(ChatFormatting.GRAY));
}
}

View file

@ -0,0 +1,19 @@
package com.atsuishio.superbwarfare.item.common.ammo;
//import com.atsuishio.superbwarfare.entity.projectile.MortarShellEntity;
import net.minecraft.world.item.Item;
public class MortarShell extends Item {
public MortarShell() {
super(new Properties());
}
// TODO createShell
// public MortarShellEntity createShell(LivingEntity entity, Level level, ItemStack stack) {
// MortarShellEntity shellEntity = new MortarShellEntity(entity, level);
// shellEntity.setEffectsFromItem(stack);
// return shellEntity;
// }
}

View file

@ -0,0 +1,25 @@
package com.atsuishio.superbwarfare.item.common.ammo;
//@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public class PotionMortarShell extends MortarShell {
public PotionMortarShell() {
super();
}
// TODO default instance
// @Override
// public ItemStack getDefaultInstance() {
// return PotionUtils.setPotion(super.getDefaultInstance(), Potions.POISON);
// }
// @Override
// public void appendHoverText(ItemStack pStack, @Nullable Level pLevel, List<Component> pTooltip, TooltipFlag pFlag) {
// PotionUtils.addPotionTooltip(pStack, pTooltip, 0.125F);
// }
// @SubscribeEvent
// public static void onRegisterColorHandlers(final RegisterColorHandlersEvent.Item event) {
// event.register((stack, layer) -> layer == 1 ? PotionUtils.getColor(stack) : -1, ModItems.POTION_MORTAR_SHELL.get());
// }
}

View file

@ -0,0 +1,23 @@
package com.atsuishio.superbwarfare.item.common.ammo;
import com.atsuishio.superbwarfare.tools.AmmoType;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class RifleAmmoBox extends AmmoSupplierItem {
public RifleAmmoBox() {
super(AmmoType.RIFLE, 30, new Properties());
}
@Override
public void appendHoverText(@NotNull ItemStack stack, @NotNull TooltipContext context, List<Component> tooltipComponents, @NotNull TooltipFlag tooltipFlag) {
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
tooltipComponents.add(Component.translatable("des.superbwarfare.rifle_ammo_box").withStyle(ChatFormatting.GRAY));
}
}

View file

@ -0,0 +1,86 @@
package com.atsuishio.superbwarfare.item.common.ammo;
import com.atsuishio.superbwarfare.tools.ParticleTool;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
//public class Rocket extends Item implements GeoItem {
// TODO rewrite
public class Rocket extends Item {
// private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
public static ItemDisplayContext transformType;
public Rocket() {
super(new Properties().stacksTo(16));
}
// @Override
// public void initializeClient(@NotNull Consumer<IClientItemExtensions> consumer) {
// super.initializeClient(consumer);
// consumer.accept(new IClientItemExtensions() {
// private final BlockEntityWithoutLevelRenderer renderer = new RocketItemRenderer();
//
// @Override
// public BlockEntityWithoutLevelRenderer getCustomRenderer() {
// return renderer;
// }
// });
// }
public void getTransformType(ItemDisplayContext type) {
transformType = type;
}
// @Override
// public void registerControllers(AnimatableManager.ControllerRegistrar data) {
// }
// @Override
// public AnimatableInstanceCache getAnimatableInstanceCache() {
// return this.cache;
// }
// @Override
// public Multimap<Attribute, AttributeModifier> getAttributeModifiers(EquipmentSlot slot, ItemStack stack) {
// Multimap<Attribute, AttributeModifier> map = super.getAttributeModifiers(slot, stack);
// if (slot == EquipmentSlot.MAINHAND) {
// map = HashMultimap.create(map);
// map.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(BASE_ATTACK_DAMAGE_UUID, "Item modifier", 6d, AttributeModifier.Operation.ADDITION));
// map.put(Attributes.ATTACK_SPEED, new AttributeModifier(BASE_ATTACK_SPEED_UUID, "Item modifier", -2.4, AttributeModifier.Operation.ADDITION));
// }
// return map;
// }
@Override
public boolean hurtEnemy(@NotNull ItemStack stack, LivingEntity entity, @NotNull LivingEntity source) {
if (entity.level() instanceof ServerLevel level && Math.random() < 0.25) {
level.explode(source, source.getX(), source.getY() + 1, source.getZ(), 6, Level.ExplosionInteraction.NONE);
level.explode(null, source.getX(), source.getY() + 1, source.getZ(), 6, Level.ExplosionInteraction.NONE);
if (!source.level().isClientSide() && source.getServer() != null) {
ParticleTool.spawnMediumExplosionParticles(source.level(), source.getPosition(0));
}
if (source instanceof ServerPlayer player) {
// TODO criteria
// CriteriaRegister.RPG_MELEE_EXPLOSION.trigger(player);
if (!player.isCreative()) {
stack.shrink(1);
}
} else {
stack.shrink(1);
}
}
return super.hurtEnemy(stack, entity, source);
}
}

View file

@ -0,0 +1,23 @@
package com.atsuishio.superbwarfare.item.common.ammo;
import com.atsuishio.superbwarfare.tools.AmmoType;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class ShotgunAmmoBox extends AmmoSupplierItem {
public ShotgunAmmoBox() {
super(AmmoType.SHOTGUN, 12, new Properties());
}
@Override
public void appendHoverText(@NotNull ItemStack stack, @NotNull TooltipContext context, List<Component> tooltipComponents, @NotNull TooltipFlag tooltipFlag) {
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
tooltipComponents.add(Component.translatable("des.superbwarfare.shotgun_ammo_box").withStyle(ChatFormatting.GRAY));
}
}

View file

@ -0,0 +1,23 @@
package com.atsuishio.superbwarfare.item.common.ammo;
import com.atsuishio.superbwarfare.tools.AmmoType;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class SniperAmmoBox extends AmmoSupplierItem {
public SniperAmmoBox() {
super(AmmoType.SNIPER, 12, new Properties());
}
@Override
public void appendHoverText(@NotNull ItemStack stack, @NotNull TooltipContext context, List<Component> tooltipComponents, @NotNull TooltipFlag tooltipFlag) {
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
tooltipComponents.add(Component.translatable("des.superbwarfare.sniper_ammo_box").withStyle(ChatFormatting.GRAY));
}
}

View file

@ -0,0 +1,152 @@
package com.atsuishio.superbwarfare.item.common.ammo.box;
import com.atsuishio.superbwarfare.capability.ModCapabilities;
import com.atsuishio.superbwarfare.component.ModDataComponents;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.tools.AmmoType;
import com.atsuishio.superbwarfare.tools.FormatTool;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.List;
public class AmmoBox extends Item {
public AmmoBox() {
super(new Properties().stacksTo(1));
}
// TODO 修复弹药存储问题
@Override
public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level level, Player player, @NotNull InteractionHand hand) {
ItemStack stack = player.getItemInHand(hand);
if (hand == InteractionHand.OFF_HAND) return InteractionResultHolder.fail(stack);
player.getCooldowns().addCooldown(this, 10);
var info = stack.get(ModDataComponents.AMMO_BOX_INFO);
if (info == null) info = new AmmoBoxInfo("All", false);
String type = info.type();
var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE, null);
if (cap != null) {
var types = type.equals("All") ? AmmoType.values() : new AmmoType[]{AmmoType.getType(type)};
for (var ammoType : types) {
if (ammoType == null) continue;
if (player.isCrouching()) {
// 存入弹药
ammoType.add(stack, ammoType.get(cap));
ammoType.set(cap, 0);
} else {
// 取出弹药
ammoType.add(cap, ammoType.get(stack));
ammoType.set(stack, 0);
}
}
cap.syncPlayerVariables(player);
if (!level.isClientSide()) {
level.playSound(null, player.blockPosition(), SoundEvents.ARROW_HIT_PLAYER, SoundSource.PLAYERS, 1, 1);
}
// 取出弹药时若弹药盒为掉落物版本则移除弹药盒物品
if (!player.isCrouching() && info.isDrop()) {
stack.shrink(1);
}
}
return InteractionResultHolder.consume(stack);
}
private static final List<String> ammoTypeList = generateAmmoTypeList();
private static List<String> generateAmmoTypeList() {
var list = new ArrayList<String>();
list.add("All");
for (var ammoType : AmmoType.values()) {
list.add(ammoType.name);
}
return list;
}
@Override
@ParametersAreNonnullByDefault
public boolean onEntitySwing(ItemStack stack, LivingEntity entity, InteractionHand hand) {
if (entity instanceof Player player && player.isCrouching()) {
var info = stack.get(ModDataComponents.AMMO_BOX_INFO) == null ? new AmmoBoxInfo("All", false) : stack.get(ModDataComponents.AMMO_BOX_INFO);
assert info != null;
var index = Math.max(0, ammoTypeList.indexOf(info.type()));
var typeString = ammoTypeList.get((index + 1) % ammoTypeList.size());
stack.set(ModDataComponents.AMMO_BOX_INFO, new AmmoBoxInfo(typeString, info.isDrop()));
entity.playSound(ModSounds.FIRE_RATE.get(), 1f, 1f);
var type = AmmoType.getType(typeString);
if (type == null) {
player.displayClientMessage(Component.translatable("des.superbwarfare.ammo_box.type.all").withStyle(ChatFormatting.WHITE), true);
return true;
}
switch (type) {
case RIFLE ->
player.displayClientMessage(Component.translatable("des.superbwarfare.ammo_box.type.rifle").withStyle(ChatFormatting.GREEN), true);
case HANDGUN ->
player.displayClientMessage(Component.translatable("des.superbwarfare.ammo_box.type.handgun").withStyle(ChatFormatting.AQUA), true);
case SHOTGUN ->
player.displayClientMessage(Component.translatable("des.superbwarfare.ammo_box.type.shotgun").withStyle(ChatFormatting.RED), true);
case SNIPER ->
player.displayClientMessage(Component.translatable("des.superbwarfare.ammo_box.type.sniper").withStyle(ChatFormatting.GOLD), true);
case HEAVY ->
player.displayClientMessage(Component.translatable("des.superbwarfare.ammo_box.type.heavy").withStyle(ChatFormatting.LIGHT_PURPLE), true);
}
}
return true;
}
@Override
public void appendHoverText(ItemStack stack, @NotNull TooltipContext context, List<Component> tooltipComponents, @NotNull TooltipFlag tooltipFlag) {
var info = stack.get(ModDataComponents.AMMO_BOX_INFO);
if (info == null) info = new AmmoBoxInfo("All", false);
var type = AmmoType.getType(info.type());
tooltipComponents.add(Component.translatable("des.superbwarfare.ammo_box").withStyle(ChatFormatting.GRAY));
tooltipComponents.add(Component.translatable("des.superbwarfare.ammo_box.handgun").withStyle(ChatFormatting.AQUA)
.append(Component.literal("").withStyle(ChatFormatting.RESET))
.append(Component.literal(FormatTool.format0D(AmmoType.HANDGUN.get(stack)) + ((type != AmmoType.HANDGUN) ? " " : " ←-")).withStyle(ChatFormatting.BOLD)));
tooltipComponents.add(Component.translatable("des.superbwarfare.ammo_box.rifle").withStyle(ChatFormatting.GREEN)
.append(Component.literal("").withStyle(ChatFormatting.RESET))
.append(Component.literal(FormatTool.format0D(AmmoType.RIFLE.get(stack)) + ((type != AmmoType.RIFLE) ? " " : " ←-")).withStyle(ChatFormatting.BOLD)));
tooltipComponents.add(Component.translatable("des.superbwarfare.ammo_box.shotgun").withStyle(ChatFormatting.RED)
.append(Component.literal("").withStyle(ChatFormatting.RESET))
.append(Component.literal(FormatTool.format0D(AmmoType.SHOTGUN.get(stack)) + ((type != AmmoType.SHOTGUN) ? " " : " ←-")).withStyle(ChatFormatting.BOLD)));
tooltipComponents.add(Component.translatable("des.superbwarfare.ammo_box.sniper").withStyle(ChatFormatting.GOLD)
.append(Component.literal("").withStyle(ChatFormatting.RESET))
.append(Component.literal(FormatTool.format0D(AmmoType.SNIPER.get(stack)) + ((type != AmmoType.SNIPER) ? " " : " ←-")).withStyle(ChatFormatting.BOLD)));
tooltipComponents.add(Component.translatable("des.superbwarfare.ammo_box.heavy").withStyle(ChatFormatting.LIGHT_PURPLE)
.append(Component.literal("").withStyle(ChatFormatting.RESET))
.append(Component.literal(FormatTool.format0D(AmmoType.HEAVY.get(stack)) + ((type != AmmoType.HEAVY) ? " " : " ←-")).withStyle(ChatFormatting.BOLD)));
}
}

View file

@ -0,0 +1,11 @@
package com.atsuishio.superbwarfare.item.common.ammo.box;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
public record AmmoBoxInfo(String type, boolean isDrop) {
public static final Codec<AmmoBoxInfo> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.STRING.fieldOf("type").forGetter(AmmoBoxInfo::type),
Codec.BOOL.fieldOf("is_drop").forGetter(AmmoBoxInfo::isDrop)
).apply(instance, AmmoBoxInfo::new));
}

View file

@ -0,0 +1,24 @@
package com.atsuishio.superbwarfare.network;
import com.atsuishio.superbwarfare.network.message.PlayerVariablesSyncMessage;
import com.atsuishio.superbwarfare.network.message.SavedDataSyncMessage;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
import net.neoforged.neoforge.network.registration.PayloadRegistrar;
public class NetworkRegistry {
public static void register(final RegisterPayloadHandlersEvent event) {
final PayloadRegistrar registrar = event.registrar("1");
registrar.playToClient(
PlayerVariablesSyncMessage.TYPE,
PlayerVariablesSyncMessage.STREAM_CODEC,
PlayerVariablesSyncMessage::handler
);
registrar.playToClient(
SavedDataSyncMessage.TYPE,
SavedDataSyncMessage.STREAM_CODEC,
SavedDataSyncMessage::handler
);
}
}

View file

@ -0,0 +1,60 @@
package com.atsuishio.superbwarfare.network.message;
import com.atsuishio.superbwarfare.ModUtils;
import com.atsuishio.superbwarfare.capability.ModCapabilities;
import com.atsuishio.superbwarfare.capability.player.PlayerVariable;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.Minecraft;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import org.jetbrains.annotations.NotNull;
public record PlayerVariablesSyncMessage(int target, CompoundTag data) implements CustomPacketPayload {
public static final CustomPacketPayload.Type<PlayerVariablesSyncMessage> TYPE = new CustomPacketPayload.Type<>(ModUtils.loc("player_variable_sync"));
public static final StreamCodec<ByteBuf, PlayerVariablesSyncMessage> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.INT,
PlayerVariablesSyncMessage::target,
ByteBufCodecs.COMPOUND_TAG,
PlayerVariablesSyncMessage::data,
PlayerVariablesSyncMessage::new
);
public static void handler(final PlayerVariablesSyncMessage message, final IPayloadContext context) {
var data = new PlayerVariable().readFromNBT(message.data());
if (Minecraft.getInstance().player == null) return;
var entity = Minecraft.getInstance().player.level().getEntity(message.target());
if (entity == null) return;
var variables = entity.getCapability(ModCapabilities.PLAYER_VARIABLE, null);
if (variables == null) return;
variables.zoom = data.zoom;
variables.holdFire = data.holdFire;
variables.rifleAmmo = data.rifleAmmo;
variables.handgunAmmo = data.handgunAmmo;
variables.shotgunAmmo = data.shotgunAmmo;
variables.sniperAmmo = data.sniperAmmo;
variables.heavyAmmo = data.heavyAmmo;
variables.bowPullHold = data.bowPullHold;
variables.bowPull = data.bowPull;
variables.playerDoubleJump = data.playerDoubleJump;
variables.tacticalSprint = data.tacticalSprint;
variables.tacticalSprintTime = data.tacticalSprintTime;
variables.tacticalSprintExhaustion = data.tacticalSprintExhaustion;
variables.breath = data.breath;
variables.breathTime = data.breathTime;
variables.breathExhaustion = data.breathExhaustion;
variables.edit = data.edit;
}
@Override
public @NotNull Type<? extends CustomPacketPayload> type() {
return TYPE;
}
}

View file

@ -0,0 +1,44 @@
package com.atsuishio.superbwarfare.network.message;
import com.atsuishio.superbwarfare.ModUtils;
import com.atsuishio.superbwarfare.capability.player.ModVariables;
import io.netty.buffer.ByteBuf;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.world.level.saveddata.SavedData;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import org.jetbrains.annotations.NotNull;
public record SavedDataSyncMessage(
int messageType,
SavedData data,
HolderLookup.Provider registries
) implements CustomPacketPayload {
public static final CustomPacketPayload.Type<SavedDataSyncMessage> TYPE = new CustomPacketPayload.Type<>(ModUtils.loc("saved_data_sync"));
public static final StreamCodec<ByteBuf, SavedDataSyncMessage> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.INT,
SavedDataSyncMessage::messageType,
ByteBufCodecs.COMPOUND_TAG,
SavedDataSyncMessage::getNBT,
(type, nbt) -> new SavedDataSyncMessage(type, null, null)
);
public CompoundTag getNBT() {
return this.data.save(new CompoundTag(), registries);
}
public static void handler(final SavedDataSyncMessage message, final IPayloadContext context) {
if (message.data != null && message.messageType != 0) {
ModVariables.WorldVariables.clientSide = (ModVariables.WorldVariables) message.data;
}
}
@Override
public @NotNull Type<? extends CustomPacketPayload> type() {
return TYPE;
}
}

View file

@ -1,6 +1,12 @@
package com.atsuishio.superbwarfare.tools;
import com.atsuishio.superbwarfare.capability.ModCapabilities;
import com.atsuishio.superbwarfare.capability.player.PlayerVariable;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.neoforged.neoforge.registries.DeferredHolder;
public enum AmmoType {
HANDGUN("item.superbwarfare.ammo.handgun", "HandgunAmmo"),
@ -10,6 +16,7 @@ public enum AmmoType {
HEAVY("item.superbwarfare.ammo.heavy", "HeavyAmmo");
public final String translatableKey;
public final String name;
public DeferredHolder<DataComponentType<?>, DataComponentType<Integer>> dataComponent;
AmmoType(String translatableKey, String name) {
this.translatableKey = translatableKey;
@ -26,17 +33,18 @@ public enum AmmoType {
}
// ItemStack
// public int get(ItemStack stack) {
// return get(stack.get(DataComponents.CUSTOM_DATA).getOrCreateTag());
// }
public int get(ItemStack stack) {
var count = stack.get(this.dataComponent);
return count == null ? 0 : count;
}
// public void set(ItemStack stack, int count) {
// set(stack.getOrCreateTag(), count);
// }
public void set(ItemStack stack, int count) {
stack.set(this.dataComponent, count);
}
// public void add(ItemStack stack, int count) {
// add(stack.getOrCreateTag(), count);
// }
public void add(ItemStack stack, int count) {
set(stack, safeAdd(get(stack), count));
}
// NBTTag
public int get(CompoundTag tag) {
@ -53,52 +61,52 @@ public enum AmmoType {
}
// PlayerVariables
// public int get(ModVariables.PlayerVariables variable) {
// return switch (this) {
// case HANDGUN -> variable.handgunAmmo;
// case RIFLE -> variable.rifleAmmo;
// case SHOTGUN -> variable.shotgunAmmo;
// case SNIPER -> variable.sniperAmmo;
// case HEAVY -> variable.heavyAmmo;
// };
// }
//
// public void set(ModVariables.PlayerVariables variable, int count) {
// if (count < 0) count = 0;
//
// switch (this) {
// case HANDGUN -> variable.handgunAmmo = count;
// case RIFLE -> variable.rifleAmmo = count;
// case SHOTGUN -> variable.shotgunAmmo = count;
// case SNIPER -> variable.sniperAmmo = count;
// case HEAVY -> variable.heavyAmmo = count;
// }
// }
//
// public void add(ModVariables.PlayerVariables variable, int count) {
// set(variable, safeAdd(get(variable), count));
// }
//
//
// // Entity
// public int get(Entity entity) {
// var cap = entity.getCapability(ModVariables.PLAYER_VARIABLES_CAPABILITY);
// if (cap == null) return 0;
//
// return get(cap);
// }
//
// public void set(Entity entity, int count) {
// var cap = entity.getCapability(ModVariables.PLAYER_VARIABLES_CAPABILITY);
// if (cap == null) return;
//
// set(cap, count);
// cap.syncPlayerVariables(entity);
// }
public int get(PlayerVariable variable) {
return switch (this) {
case HANDGUN -> variable.handgunAmmo;
case RIFLE -> variable.rifleAmmo;
case SHOTGUN -> variable.shotgunAmmo;
case SNIPER -> variable.sniperAmmo;
case HEAVY -> variable.heavyAmmo;
};
}
// public void add(Entity entity, int count) {
// set(entity, safeAdd(get(entity), count));
// }
public void set(PlayerVariable variable, int count) {
if (count < 0) count = 0;
switch (this) {
case HANDGUN -> variable.handgunAmmo = count;
case RIFLE -> variable.rifleAmmo = count;
case SHOTGUN -> variable.shotgunAmmo = count;
case SNIPER -> variable.sniperAmmo = count;
case HEAVY -> variable.heavyAmmo = count;
}
}
public void add(PlayerVariable variable, int count) {
set(variable, safeAdd(get(variable), count));
}
// Entity
public int get(Entity entity) {
var cap = entity.getCapability(ModCapabilities.PLAYER_VARIABLE);
if (cap == null) return 0;
return get(cap);
}
public void set(Entity entity, int count) {
var cap = entity.getCapability(ModCapabilities.PLAYER_VARIABLE);
if (cap == null) return;
set(cap, count);
cap.syncPlayerVariables(entity);
}
public void add(Entity entity, int count) {
set(entity, safeAdd(get(entity), count));
}
private int safeAdd(int a, int b) {