diff --git a/src/main/java/com/atsuishio/superbwarfare/ModUtils.java b/src/main/java/com/atsuishio/superbwarfare/ModUtils.java index 9a63bc49f..12b7099f1 100644 --- a/src/main/java/com/atsuishio/superbwarfare/ModUtils.java +++ b/src/main/java/com/atsuishio/superbwarfare/ModUtils.java @@ -1,5 +1,6 @@ package com.atsuishio.superbwarfare; +import com.atsuishio.superbwarfare.client.MouseMovementHandler; import com.atsuishio.superbwarfare.component.ModDataComponents; import com.atsuishio.superbwarfare.config.ClientConfig; import com.atsuishio.superbwarfare.config.CommonConfig; @@ -12,6 +13,7 @@ import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; import net.neoforged.fml.config.ModConfig; +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.tick.ServerTickEvent; @@ -56,7 +58,7 @@ public class ModUtils { ModAttributes.ATTRIBUTES.register(bus); // bus.addListener(this::onCommonSetup); -// bus.addListener(this::onClientSetup); + bus.addListener(this::onClientSetup); bus.addListener(ModItems::registerDispenserBehavior); bus.addListener(NetworkRegistry::register); @@ -101,4 +103,8 @@ public class ModUtils { workQueueC.removeAll(actions); } + public void onClientSetup(final FMLClientSetupEvent event) { + MouseMovementHandler.init(); + } + } diff --git a/src/main/java/com/atsuishio/superbwarfare/capability/player/PlayerVariable.java b/src/main/java/com/atsuishio/superbwarfare/capability/player/PlayerVariable.java index 950b0b3de..9a7d0cded 100644 --- a/src/main/java/com/atsuishio/superbwarfare/capability/player/PlayerVariable.java +++ b/src/main/java/com/atsuishio/superbwarfare/capability/player/PlayerVariable.java @@ -2,7 +2,7 @@ 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.receive.PlayerVariablesSyncMessage; import com.atsuishio.superbwarfare.tools.AmmoType; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; diff --git a/src/main/java/com/atsuishio/superbwarfare/client/ClickHandler.java b/src/main/java/com/atsuishio/superbwarfare/client/ClickHandler.java new file mode 100644 index 000000000..7d5bd1d33 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/ClickHandler.java @@ -0,0 +1,416 @@ +package com.atsuishio.superbwarfare.client; + +import com.atsuishio.superbwarfare.capability.ModCapabilities; +import com.atsuishio.superbwarfare.config.client.ReloadConfig; +import com.atsuishio.superbwarfare.entity.MortarEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.CannonEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.WeaponVehicleEntity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.init.*; +import com.atsuishio.superbwarfare.item.gun.GunItem; +import com.atsuishio.superbwarfare.network.ModVariables; +import com.atsuishio.superbwarfare.network.message.send.DoubleJumpMessage; +import com.atsuishio.superbwarfare.perk.PerkHelper; +import com.atsuishio.superbwarfare.tools.GunsTool; +import com.atsuishio.superbwarfare.tools.NBTTool; +import com.atsuishio.superbwarfare.tools.SeekTool; +import com.atsuishio.superbwarfare.tools.TraceTool; +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.settings.KeyConflictContext; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.InputEvent; +import net.neoforged.neoforge.network.PacketDistributor; +import org.lwjgl.glfw.GLFW; + +import static com.atsuishio.superbwarfare.event.ClientEventHandler.cantFireTime; +import static com.atsuishio.superbwarfare.event.ClientEventHandler.drawTime; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) +public class ClickHandler { + + public static boolean switchZoom = false; + + private static boolean notInGame() { + Minecraft mc = Minecraft.getInstance(); + if (mc.player == null) return true; + if (mc.getOverlay() != null) return true; + if (mc.screen != null) return true; + if (!mc.mouseHandler.isMouseGrabbed()) return true; + return !mc.isWindowActive(); + } + + @SubscribeEvent + public static void onButtonReleased(InputEvent.MouseButton.Pre event) { + if (notInGame()) return; + if (event.getAction() != InputConstants.RELEASE) return; + + Player player = Minecraft.getInstance().player; + if (player == null) return; + + if (player.hasEffect(ModMobEffects.SHOCK)) return; + + int button = event.getButton(); + if (button == ModKeyMappings.FIRE.getKey().getValue()) { + handleWeaponFireRelease(); + } + if (button == ModKeyMappings.HOLD_ZOOM.getKey().getValue()) { + handleWeaponZoomRelease(); + return; + } + + if (button == ModKeyMappings.SWITCH_ZOOM.getKey().getValue() && !switchZoom) { + handleWeaponZoomRelease(); + } + } + + @SubscribeEvent + public static void onButtonPressed(InputEvent.MouseButton.Pre event) { + if (notInGame()) return; + if (event.getAction() != InputConstants.PRESS) return; + + Player player = Minecraft.getInstance().player; + if (player == null) return; + if (player.isSpectator()) return; + + ItemStack stack = player.getMainHandItem(); + + int button = event.getButton(); + + if (stack.is(ModTags.Items.GUN) || stack.is(ModItems.MONITOR.get()) || stack.is(ModItems.LUNGE_MINE.get()) || player.hasEffect(ModMobEffects.SHOCK) + || (player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player))) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + event.setCanceled(true); + } + } + + if (player.hasEffect(ModMobEffects.SHOCK)) return; + + if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) { + if (stack.is(ModTags.Items.GUN) + || (player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.isDriver(player) && stack.get(DataComponents.FOOD) != null)) { + event.setCanceled(true); + } + } + + if (button == GLFW.GLFW_MOUSE_BUTTON_MIDDLE) { + if (player.hasEffect(ModMobEffects.SHOCK)) { + event.setCanceled(true); + } + } + + if (stack.is(ModTags.Items.GUN) + || stack.is(ModItems.MONITOR.get()) + || stack.is(ModItems.LUNGE_MINE.get()) + || (player.getVehicle() instanceof ArmedVehicleEntity) + || (stack.is(Items.SPYGLASS) && player.isScoping() && player.getOffhandItem().is(ModItems.FIRING_PARAMETERS.get()))) { + if (button == ModKeyMappings.FIRE.getKey().getValue()) { + handleWeaponFirePress(player, stack); + } + + if (button == ModKeyMappings.HOLD_ZOOM.getKey().getValue()) { + handleWeaponZoomPress(player, stack); + switchZoom = false; + return; + } + + if (button == ModKeyMappings.SWITCH_ZOOM.getKey().getValue()) { + handleWeaponZoomPress(player, stack); + switchZoom = !switchZoom; + } + } + } + + @SubscribeEvent + public static void onMouseScrolling(InputEvent.MouseScrollingEvent event) { + Player player = Minecraft.getInstance().player; + + if (notInGame()) return; + if (player == null) return; + + ItemStack stack = player.getMainHandItem(); + + if (player.hasEffect(ModMobEffects.SHOCK)) return; + + double scroll = event.getScrollDeltaY(); + + // 未按下shift时,为有武器的载具切换武器 + if (!Screen.hasShiftDown() + && player.getVehicle() instanceof VehicleEntity vehicle + && vehicle instanceof WeaponVehicleEntity weaponVehicle + && weaponVehicle.hasWeapon(vehicle.getSeatIndex(player)) + ) { + int index = vehicle.getSeatIndex(player); + PacketDistributor.sendToServer(new SwitchVehicleWeaponMessage(index, -scroll, true)); + event.setCanceled(true); + } + + var tag = NBTTool.getTag(stack); + + if (stack.is(ModTags.Items.GUN) && ClientEventHandler.zoom) { + if (GunsTool.getGunBooleanTag(stack, "CanSwitchScope", false)) { + PacketDistributor.sendToServer(new SwitchScopeMessage(scroll)); + } else if (tag.getBoolean("CanAdjustZoomFov") || stack.is(ModItems.MINIGUN.get())) { + PacketDistributor.sendToServer(new AdjustZoomFovMessage(scroll)); + } + event.setCanceled(true); + } + + if (stack.is(ModItems.MONITOR.get()) && tag.getBoolean("Using") && tag.getBoolean("Linked")) { + ClientEventHandler.droneFov = Mth.clamp(ClientEventHandler.droneFov + 0.4 * scroll, 1, 6); + event.setCanceled(true); + } + + Entity looking = TraceTool.findLookingEntity(player, 6); + if (looking == null) return; + if (looking instanceof MortarEntity && player.isShiftKeyDown()) { + PacketDistributor.sendToServer(new AdjustMortarAngleMessage(scroll)); + event.setCanceled(true); + } + } + + @SubscribeEvent + public static void onKeyPressed(InputEvent.Key event) { + if (notInGame()) return; + + Player player = Minecraft.getInstance().player; + if (player == null) return; + if (player.isSpectator()) return; + + ItemStack stack = player.getMainHandItem(); + + int key = event.getKey(); + if (event.getAction() == GLFW.GLFW_PRESS) { + if (player.hasEffect(ModMobEffects.SHOCK)) return; + + if (key == Minecraft.getInstance().options.keyJump.getKey().getValue()) { + handleDoubleJump(player); + } + if (key == ModKeyMappings.CONFIG.getKey().getValue() && ModKeyMappings.CONFIG.getKeyModifier().isActive(KeyConflictContext.IN_GAME)) { + handleConfigScreen(player); + } + if (key == ModKeyMappings.RELOAD.getKey().getValue()) { + PacketDistributor.sendToServer(new ReloadMessage(0)); + } + if (key == ModKeyMappings.FIRE_MODE.getKey().getValue()) { + PacketDistributor.sendToServer(new FireModeMessage(0)); + } + if (key == ModKeyMappings.INTERACT.getKey().getValue()) { + PacketDistributor.sendToServer(new InteractMessage(0)); + } + if (key == ModKeyMappings.DISMOUNT.getKey().getValue()) { + handleDismountPress(player); + } + if (key == ModKeyMappings.EDIT_MODE.getKey().getValue() && ClientEventHandler.burstFireSize == 0) { + ClientEventHandler.holdFire = false; + PacketDistributor.sendToServer(new EditModeMessage(0)); + } + + if (player.getCapability(ModVariables.PLAYER_VARIABLES_CAPABILITY, null).orElse(new ModVariables.PlayerVariables()).edit) { + if (!(stack.getItem() instanceof GunItem gunItem)) return; + if (ModKeyMappings.EDIT_GRIP.getKeyModifier().isActive(KeyConflictContext.IN_GAME)) { + if (key == ModKeyMappings.EDIT_GRIP.getKey().getValue() && gunItem.hasCustomGrip(stack)) { + PacketDistributor.sendToServer(new EditMessage(4)); + editModelShake(); + } + } else { + if (key == ModKeyMappings.EDIT_SCOPE.getKey().getValue() && gunItem.hasCustomScope(stack)) { + PacketDistributor.sendToServer(new EditMessage(0)); + editModelShake(); + } else if (key == ModKeyMappings.EDIT_BARREL.getKey().getValue() && gunItem.hasCustomBarrel(stack)) { + PacketDistributor.sendToServer(new EditMessage(1)); + editModelShake(); + } else if (key == ModKeyMappings.EDIT_MAGAZINE.getKey().getValue() && gunItem.hasCustomMagazine(stack)) { + PacketDistributor.sendToServer(new EditMessage(2)); + editModelShake(); + } else if (key == ModKeyMappings.EDIT_STOCK.getKey().getValue() && gunItem.hasCustomStock(stack)) { + PacketDistributor.sendToServer(new EditMessage(3)); + editModelShake(); + } + } + } + if (key == ModKeyMappings.SENSITIVITY_INCREASE.getKey().getValue()) { + PacketDistributor.sendToServer(new SensitivityMessage(true)); + } + if (key == ModKeyMappings.SENSITIVITY_REDUCE.getKey().getValue()) { + PacketDistributor.sendToServer(new SensitivityMessage(false)); + } + + if (stack.is(ModTags.Items.GUN) + || stack.is(ModItems.MONITOR.get()) + || (player.getVehicle() instanceof ArmedVehicleEntity iVehicle && iVehicle.isDriver(player)) + || (stack.is(Items.SPYGLASS) && player.isScoping() && player.getOffhandItem().is(ModItems.FIRING_PARAMETERS.get()))) { + if (key == ModKeyMappings.FIRE.getKey().getValue()) { + handleWeaponFirePress(player, stack); + } + + if (key == ModKeyMappings.HOLD_ZOOM.getKey().getValue()) { + handleWeaponZoomPress(player, stack); + switchZoom = false; + return; + } + + if (key == ModKeyMappings.SWITCH_ZOOM.getKey().getValue()) { + handleWeaponZoomPress(player, stack); + switchZoom = !switchZoom; + } + } + } else { + if (player.hasEffect(ModMobEffects.SHOCK)) return; + + if (key == ModKeyMappings.FIRE.getKey().getValue()) { + handleWeaponFireRelease(); + } + if (key == ModKeyMappings.HOLD_ZOOM.getKey().getValue()) { + handleWeaponZoomRelease(); + return; + } + + if (key == ModKeyMappings.SWITCH_ZOOM.getKey().getValue() && !switchZoom) { + handleWeaponZoomRelease(); + } + } + } + + public static void handleWeaponFirePress(Player player, ItemStack stack) { + if (player.hasEffect(ModMobEffects.SHOCK)) return; + + if (stack.is(Items.SPYGLASS) && player.isScoping() && player.getOffhandItem().is(ModItems.FIRING_PARAMETERS.get())) { + PacketDistributor.sendToServer(new SetFiringParametersMessage(0)); + } + + if (stack.is(ModItems.MONITOR.get())) { + PacketDistributor.sendToServer(new DroneFireMessage(0)); + } + + + if (player.getVehicle() instanceof WeaponVehicleEntity iVehicle && iVehicle.banHand(player)) { + if (player.getVehicle() instanceof VehicleEntity pVehicle && iVehicle.hasWeapon(pVehicle.getSeatIndex(player))) { + ClientEventHandler.holdFireVehicle = true; + } + return; + } + + if (stack.is(ModItems.LUNGE_MINE.get())) { + ClientEventHandler.holdFire = true; + } + + if (stack.getItem() instanceof GunItem gunItem && !(player.getVehicle() != null && player.getVehicle() instanceof CannonEntity)) { + var tag = NBTTool.getTag(stack); + if ((!(tag.getBoolean("is_normal_reloading") || tag.getBoolean("is_empty_reloading")) + && !GunsTool.getGunBooleanTag(stack, "Reloading") + && !GunsTool.getGunBooleanTag(stack, "Charging") + && !GunsTool.getGunBooleanTag(stack, "NeedBoltAction", false)) + && cantFireTime == 0 + && drawTime < 0.01 + && !notInGame()) { + player.playSound(ModSounds.TRIGGER_CLICK.get(), 1, 1); + } + + if (!gunItem.useBackpackAmmo(stack) && GunsTool.getGunIntTag(stack, "Ammo", 0) <= 0 && GunsTool.getGunIntTag(stack, "ReloadTime") == 0) { + if (ReloadConfig.LEFT_CLICK_RELOAD.get()) { + PacketDistributor.sendToServer(new ReloadMessage(0)); + } + } else { + PacketDistributor.sendToServer(new FireMessage(0)); + if (!stack.is(ModItems.BOCEK.get())) { + ClientEventHandler.holdFire = true; + } + if (GunsTool.getGunIntTag(stack, "FireMode") == 1 && ClientEventHandler.burstFireSize == 0) { + ClientEventHandler.burstFireSize = GunsTool.getGunIntTag(stack, "BurstSize", 1); + } + } + } + } + + public static void handleWeaponFireRelease() { + PacketDistributor.sendToServer(new FireMessage(1)); + ClientEventHandler.holdFire = false; + ClientEventHandler.holdFireVehicle = false; + ClientEventHandler.customRpm = 0; + } + + public static void handleWeaponZoomPress(Player player, ItemStack stack) { + PacketDistributor.sendToServer(new ZoomMessage(0)); + + if (player.getVehicle() instanceof VehicleEntity pVehicle && player.getVehicle() instanceof WeaponVehicleEntity iVehicle && iVehicle.hasWeapon(pVehicle.getSeatIndex(player))) { + ClientEventHandler.zoomVehicle = true; + return; + } + + ClientEventHandler.zoom = true; + int level = PerkHelper.getItemPerkLevel(ModPerks.INTELLIGENT_CHIP.get(), stack); + if (level > 0) { + if (ClientEventHandler.entity == null) { + ClientEventHandler.entity = SeekTool.seekLivingEntity(player, player.level(), 32 + 8 * (level - 1), 20); + } + } + } + + public static void handleWeaponZoomRelease() { + PacketDistributor.sendToServer(new ZoomMessage(1)); + ClientEventHandler.zoom = false; + ClientEventHandler.zoomVehicle = false; + ClientEventHandler.entity = null; + } + + private static void editModelShake() { + ClientEventHandler.movePosY = -0.8; + ClientEventHandler.fireRotTimer = 0.4; + } + + private static void handleDoubleJump(Player player) { + Level level = player.level(); + double x = player.getX(); + double y = player.getY(); + double z = player.getZ(); + + if (!level.isLoaded(player.blockPosition())) { + return; + } + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap != null && cap.playerDoubleJump) { + player.setDeltaMovement(new Vec3(player.getLookAngle().x, 0.8, player.getLookAngle().z)); + level.playLocalSound(x, y, z, ModSounds.DOUBLE_JUMP.get(), SoundSource.BLOCKS, 1, 1, false); + + PacketDistributor.sendToServer(new DoubleJumpMessage(false)); + } + } + + // TODO do we need cloth config? +// private static void handleConfigScreen(Player player) { +// if (ModList.get().isLoaded(CompatHolder.CLOTH_CONFIG)) { +// CompatHolder.hasMod(CompatHolder.CLOTH_CONFIG, () -> Minecraft.getInstance().setScreen(ClothConfigHelper.getConfigScreen(null))); +// } else { +// player.displayClientMessage(Component.translatable("tips.superbwarfare.no_cloth_config").withStyle(ChatFormatting.RED), true); +// } +// } + + private static void handleDismountPress(Player player) { + var vehicle = player.getVehicle(); + if (!(vehicle instanceof VehicleEntity)) return; + + if ((!vehicle.onGround() || vehicle.getDeltaMovement().length() >= 0.1) && ClientEventHandler.dismountCountdown <= 0) { + player.displayClientMessage(Component.translatable("mount.onboard", ModKeyMappings.DISMOUNT.getTranslatedKeyMessage()), true); + ClientEventHandler.dismountCountdown = 20; + return; + } + PacketDistributor.sendToServer(new PlayerStopRidingMessage(0)); + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/client/ItemModelHelper.java b/src/main/java/com/atsuishio/superbwarfare/client/ItemModelHelper.java new file mode 100644 index 000000000..0281cca5a --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/ItemModelHelper.java @@ -0,0 +1,34 @@ +package com.atsuishio.superbwarfare.client; + +import com.atsuishio.superbwarfare.tools.NBTTool; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.ItemStack; +import software.bernie.geckolib.cache.object.GeoBone; + +public class ItemModelHelper { + + public static void handleGunAttachments(GeoBone bone, ItemStack stack, String name) { + var rootTag = NBTTool.getTag(stack); + CompoundTag tag = rootTag.getCompound("Attachments"); + + splitBoneName(bone, name, "Scope", tag); + splitBoneName(bone, name, "Magazine", tag); + splitBoneName(bone, name, "Barrel", tag); + splitBoneName(bone, name, "Stock", tag); + splitBoneName(bone, name, "Grip", tag); + } + + private static void splitBoneName(GeoBone bone, String boneName, String tagName, CompoundTag tag) { + try { + if (boneName.startsWith(tagName)) { + String[] parts = boneName.split("(?<=\\D)(?=\\d)"); + if (parts.length == 2) { + int index = Integer.parseInt(parts[1]); + bone.setHidden(tag.getInt(tagName) != index); + } + } + } catch (NumberFormatException ignored) { + } + } + +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/MouseMovementHandler.java b/src/main/java/com/atsuishio/superbwarfare/client/MouseMovementHandler.java new file mode 100644 index 000000000..4d999941c --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/MouseMovementHandler.java @@ -0,0 +1,89 @@ +package com.atsuishio.superbwarfare.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.MouseHandler; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.phys.Vec2; +import org.joml.Vector3f; +import org.lwjgl.glfw.GLFW; + +/** + * Codes from @getItemFromBlock's Create-Tweaked-Controllers + */ +public class MouseMovementHandler { + + public static Vec2 delta = null; + public static Vec2 lastPos = null; + public static Vec2 vel = null; + private static MouseHandler mouseHandler = null; + private static boolean mouseLockActive = false; + private static final Vector3f savedRot = new Vector3f(); + + public static Vec2 getMousePos() { + if (mouseHandler.isMouseGrabbed()) { + return new Vec2((float) mouseHandler.xpos(), (float) mouseHandler.ypos()); + } else { + double[] x, y; + x = new double[1]; + y = new double[1]; + GLFW.glfwGetCursorPos(Minecraft.getInstance().getWindow().getWindow(), x, y); + return new Vec2((float) x[0], (float) y[0]); + } + } + + public static void resetCenter() { + delta = new Vec2(0, 0); + vel = new Vec2(0, 0); + lastPos = getMousePos(); + } + + public static void init() { + delta = new Vec2(0, 0); + vel = new Vec2(0, 0); + Minecraft mc = Minecraft.getInstance(); + mouseHandler = mc.mouseHandler; + lastPos = getMousePos(); + } + + public static float getX(boolean useVelocity) { + if (useVelocity) { + return vel.x; + } else { + return delta.x; + } + } + + public static float getY(boolean useVelocity) { + if (useVelocity) { + return vel.y; + } else { + return delta.y; + } + } + + public static void activateMouseLock() { + LocalPlayer player = Minecraft.getInstance().player; + if (player == null) return; + + savedRot.x = player.getXRot(); + savedRot.y = player.getYRot(); + savedRot.z = 0; + mouseLockActive = true; + lastPos = getMousePos(); + } + + public static void deactivateMouseLock() { + mouseLockActive = false; + } + + public static void cancelPlayerTurn() { + if (!mouseLockActive) return; + LocalPlayer player = Minecraft.getInstance().player; + if (player == null) return; + player.turn((savedRot.y - player.getYRot()) / 0.15f, (savedRot.x - player.getXRot()) / 0.15f); + player.xBob = savedRot.x; + player.yBob = savedRot.y; + player.xBobO = savedRot.x; + player.yBobO = savedRot.y; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/RenderHelper.java b/src/main/java/com/atsuishio/superbwarfare/client/RenderHelper.java index e44ed3d7f..09eaaec00 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/RenderHelper.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/RenderHelper.java @@ -2,10 +2,16 @@ package com.atsuishio.superbwarfare.client; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.phys.Vec3; import org.joml.Matrix4f; +import org.joml.Vector3f; + +import javax.annotation.Nullable; public class RenderHelper { // code from GuiGraphics @@ -204,10 +210,7 @@ public class RenderHelper { * @param maxU the maximum horizontal texture coordinate. * @param minV the minimum vertical texture coordinate. * @param maxV the maximum vertical texture coordinate. - * @param red the red component of the color tfloat. - * @param green the green component of the color tfloat. - * @param blue the blue component of the color tfloat. - * @param alpha the alpha component of the color tfloat. + * @param color color */ public static void innerBlit( GuiGraphics gui, @@ -239,4 +242,24 @@ public class RenderHelper { BufferUploader.drawWithShader(bufferbuilder.buildOrThrow()); RenderSystem.disableBlend(); } + + /** + * Codes based on @Xjqsh + */ + @Nullable + public static Vec3 worldToScreen(Vec3 pos, Vec3 cameraPos) { + Minecraft minecraft = Minecraft.getInstance(); + Frustum frustum = minecraft.levelRenderer.getFrustum(); + + Vector3f relativePos = pos.subtract(cameraPos).toVector3f(); + Vector3f transformedPos = frustum.matrix.transformProject(relativePos.x, relativePos.y, relativePos.z, new Vector3f()); + + double scaleFactor = minecraft.getWindow().getGuiScale(); + float guiScaleMul = 0.5f / (float) scaleFactor; + + Vector3f screenPos = transformedPos.mul(1.0f, -1.0f, 1.0f).add(1.0f, 1.0f, 0.0f) + .mul(guiScaleMul * minecraft.getWindow().getWidth(), guiScaleMul * minecraft.getWindow().getHeight(), 1.0f); + + return transformedPos.z < 1.0f ? new Vec3(screenPos.x, screenPos.y, transformedPos.z) : null; + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/AmmoBarOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/AmmoBarOverlay.java new file mode 100644 index 000000000..89562bdbe --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/AmmoBarOverlay.java @@ -0,0 +1,485 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.capability.ModCapabilities; +import com.atsuishio.superbwarfare.capability.player.PlayerVariable; +import com.atsuishio.superbwarfare.config.client.DisplayConfig; +import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModKeyMappings; +import com.atsuishio.superbwarfare.init.ModTags; +import com.atsuishio.superbwarfare.item.common.ammo.AmmoSupplierItem; +import com.atsuishio.superbwarfare.item.gun.GunItem; +import com.atsuishio.superbwarfare.tools.AmmoType; +import com.atsuishio.superbwarfare.tools.GunsTool; +import com.atsuishio.superbwarfare.tools.InventoryTool; +import com.atsuishio.superbwarfare.tools.NBTTool; +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 com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +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(value = Dist.CLIENT) +public class AmmoBarOverlay { + + private static final ResourceLocation LINE = ModUtils.loc("textures/gun_icon/fire_mode/line.png"); + private static final ResourceLocation SEMI = ModUtils.loc("textures/gun_icon/fire_mode/semi.png"); + private static final ResourceLocation BURST = ModUtils.loc("textures/gun_icon/fire_mode/burst.png"); + private static final ResourceLocation AUTO = ModUtils.loc("textures/gun_icon/fire_mode/auto.png"); + private static final ResourceLocation TOP = ModUtils.loc("textures/gun_icon/fire_mode/top.png"); + private static final ResourceLocation DIR = ModUtils.loc("textures/gun_icon/fire_mode/dir.png"); + private static final ResourceLocation MOUSE = ModUtils.loc("textures/gun_icon/fire_mode/mouse.png"); + + private static boolean hasCreativeAmmo() { + Player player = Minecraft.getInstance().player; + if (player == null) return false; + return InventoryTool.hasCreativeAmmoBox(player); + } + + @SubscribeEvent + public static void renderWeaponInfo(RenderGuiEvent.Pre event) { + if (!DisplayConfig.AMMO_HUD.get()) return; + + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + Player player = Minecraft.getInstance().player; + + if (player == null) return; + if (player.isSpectator()) return; + + ItemStack stack = player.getMainHandItem(); + if (stack.getItem() instanceof GunItem gunItem && !(player.getVehicle() instanceof ArmedVehicleEntity vehicle && vehicle.banHand(player))) { + PoseStack poseStack = event.getGuiGraphics().pose(); + + // 渲染图标 + event.getGuiGraphics().blit(gunItem.getGunIcon(), + w - 135, + h - 40, + 0, + 0, + 64, + 16, + 64, + 16); + + // 渲染开火模式切换按键 + if (stack.getItem() != ModItems.MINIGUN.get()) { + event.getGuiGraphics().drawString( + Minecraft.getInstance().font, + "[" + ModKeyMappings.FIRE_MODE.getKey().getDisplayName().getString() + "]", + w - 111.5f, + h - 20, + 0xFFFFFF, + false + ); + } + + // 渲染开火模式 + ResourceLocation fireMode = getFireMode(stack); + + if (stack.getItem() == ModItems.JAVELIN.get()) { + fireMode = NBTTool.getBoolean(stack, "TopMode", false) ? TOP : DIR; + } + + if (stack.getItem() == ModItems.MINIGUN.get()) { + fireMode = MOUSE; + // 渲染加特林射速 + event.getGuiGraphics().drawString( + Minecraft.getInstance().font, + GunsTool.getGunIntTag(stack, "RPM", 0) + " RPM", + w - 111f, + h - 20, + 0xFFFFFF, + false + ); + + event.getGuiGraphics().blit(fireMode, + w - 126, + h - 22, + 0, + 0, + 12, + 12, + 12, + 12); + } else { + if (stack.getItem() != ModItems.TRACHELIUM.get()) { + event.getGuiGraphics().blit(fireMode, + w - 95, + h - 21, + 0, + 0, + 8, + 8, + 8, + 8); + } else { + event.getGuiGraphics().drawString( + Minecraft.getInstance().font, + NBTTool.getBoolean(stack, "DA", false) ? Component.translatable("des.superbwarfare.revolver.sa").withStyle(ChatFormatting.BOLD) : Component.translatable("des.superbwarfare.revolver.da").withStyle(ChatFormatting.BOLD), + w - 96, + h - 20, + 0xFFFFFF, + false + ); + } + } + + if (stack.getItem() != ModItems.MINIGUN.get() && stack.getItem() != ModItems.TRACHELIUM.get()) { + event.getGuiGraphics().blit(LINE, + w - 95, + h - 16, + 0, + 0, + 8, + 8, + 8, + 8); + } + + // 渲染当前弹药量 + poseStack.pushPose(); + poseStack.scale(1.5f, 1.5f, 1f); + + if ((stack.getItem() == ModItems.MINIGUN.get() || stack.getItem() == ModItems.BOCEK.get()) && hasCreativeAmmo()) { + event.getGuiGraphics().drawString( + Minecraft.getInstance().font, + "∞", + w / 1.5f - 64 / 1.5f, + h / 1.5f - 48 / 1.5f, + 0xFFFFFF, + true + ); + } else { + event.getGuiGraphics().drawString( + Minecraft.getInstance().font, + getGunAmmoCount(player) + "", + w / 1.5f - 64 / 1.5f, + h / 1.5f - 48 / 1.5f, + 0xFFFFFF, + true + ); + } + + poseStack.popPose(); + + // 渲染备弹量 + event.getGuiGraphics().drawString( + Minecraft.getInstance().font, + getPlayerAmmoCount(player), + w - 64, + h - 35, + 0xCCCCCC, + true + ); + + poseStack.pushPose(); + poseStack.scale(0.9f, 0.9f, 1f); + + // 渲染物品名称 + String gunName = gunItem.getGunDisplayName(); + event.getGuiGraphics().drawString( + Minecraft.getInstance().font, + gunName, + w / 0.9f - (100 + Minecraft.getInstance().font.width(gunName) / 2f) / 0.9f, + h / 0.9f - 60 / 0.9f, + 0xFFFFFF, + true + ); + + // 渲染弹药类型 + String ammoName = getGunAmmoType(stack); + event.getGuiGraphics().drawString( + Minecraft.getInstance().font, + ammoName, + w / 0.9f - (100 + Minecraft.getInstance().font.width(ammoName) / 2f) / 0.9f, + h / 0.9f - 51 / 0.9f, + 0xC8A679, + true + ); + + poseStack.popPose(); + } + } + + 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[] ammoCountAnimators = ValueAnimator.create( + AmmoType.values().length, 800, 0 + ); + private static final ValueAnimator[] 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()) + && !(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); + if (cap == null) cap = new PlayerVariable(); + 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 tag = NBTTool.getTag(stack); + var ammoBoxType = tag.getString("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(); + } + + private static ResourceLocation getFireMode(ItemStack stack) { + return switch (GunsTool.getGunIntTag(stack, "FireMode")) { + case 1 -> BURST; + case 2 -> AUTO; + default -> SEMI; + }; + } + + private static int getGunAmmoCount(Player player) { + ItemStack stack = player.getMainHandItem(); + + if (stack.getItem() == ModItems.MINIGUN.get()) { + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + return cap != null ? cap.rifleAmmo : 0; + } + + if (stack.getItem() == ModItems.BOCEK.get()) { + return GunsTool.getGunIntTag(stack, "MaxAmmo"); + } + + return GunsTool.getGunIntTag(stack, "Ammo", 0); + } + + private static String getPlayerAmmoCount(Player player) { + ItemStack stack = player.getMainHandItem(); + + if (stack.getItem() == ModItems.MINIGUN.get() || stack.getItem() == ModItems.BOCEK.get()) { + return ""; + } + + if (!hasCreativeAmmo()) { + if (stack.is(ModTags.Items.LAUNCHER) || stack.getItem() == ModItems.TASER.get()) { + return "" + GunsTool.getGunIntTag(stack, "MaxAmmo"); + } + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) return ""; + + if (stack.is(ModTags.Items.USE_RIFLE_AMMO)) { + return "" + cap.rifleAmmo; + } + if (stack.is(ModTags.Items.USE_HANDGUN_AMMO)) { + return "" + cap.handgunAmmo; + } + if (stack.is(ModTags.Items.USE_SHOTGUN_AMMO)) { + return "" + cap.shotgunAmmo; + } + if (stack.is(ModTags.Items.USE_SNIPER_AMMO)) { + return "" + cap.sniperAmmo; + } + if (stack.is(ModTags.Items.USE_HEAVY_AMMO)) { + return "" + cap.heavyAmmo; + } + return ""; + } + + return "∞"; + } + + private static String getGunAmmoType(ItemStack stack) { + if (stack.getItem() == ModItems.BOCEK.get()) { + return "Arrow"; + } + if (stack.getItem() == ModItems.M_79.get() || stack.getItem() == ModItems.SECONDARY_CATACLYSM.get()) { + return "40mm Grenade"; + } + if (stack.getItem() == ModItems.RPG.get()) { + return "Yassin105 TBG"; + } + if (stack.getItem() == ModItems.JAVELIN.get()) { + return "Javelin Missile"; + } + if (stack.getItem() == ModItems.TASER.get()) { + return "Electrode Rod"; + } + if (stack.getItem() == ModItems.MINIGUN.get()) { + return "Rifle Ammo"; + } + if (stack.is(ModTags.Items.USE_RIFLE_AMMO)) { + return "Rifle Ammo"; + } + if (stack.is(ModTags.Items.USE_HANDGUN_AMMO)) { + return "Handgun Ammo"; + } + if (stack.is(ModTags.Items.USE_SHOTGUN_AMMO)) { + return "Shotgun Ammo"; + } + if (stack.is(ModTags.Items.USE_SNIPER_AMMO)) { + return "Sniper Ammo"; + } + if (stack.is(ModTags.Items.USE_HEAVY_AMMO)) { + return "Heavy Ammo"; + } + return ""; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/AmmoOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/AmmoOverlay.java index 5ec43d13a..2e8f981f1 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/overlay/AmmoOverlay.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/AmmoOverlay.java @@ -3,6 +3,7 @@ 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.entity.vehicle.base.ArmedVehicleEntity; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.item.common.ammo.AmmoSupplierItem; import com.atsuishio.superbwarfare.item.common.ammo.box.AmmoBoxInfo; @@ -53,10 +54,7 @@ public class AmmoOverlay { // 动画计算 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)) - ) { + if ((stack.getItem() instanceof AmmoSupplierItem || stack.getItem() == ModItems.AMMO_BOX.get()) && !(player.getVehicle() instanceof ArmedVehicleEntity vehicle && vehicle.banHand(player))) { // 刚拿出弹药物品时,视为开始弹药信息渲染 startRenderingAmmoInfo = ammoInfoTimer.getProgress(currentTime) == 0; ammoInfoTimer.forward(currentTime); diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/ArmRendererFixOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/ArmRendererFixOverlay.java new file mode 100644 index 000000000..1107e29c1 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/ArmRendererFixOverlay.java @@ -0,0 +1,31 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import net.minecraft.client.Minecraft; +import net.minecraft.world.entity.player.Player; +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(value = Dist.CLIENT) +public class ArmRendererFixOverlay { + + @SubscribeEvent + public static void eventHandler(RenderGuiEvent.Pre event) { + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + Player entity = Minecraft.getInstance().player; + if (entity != null) { + // TODO what is this? +// InventoryScreen.renderEntityInInventoryFollowsAngle( +// event.getGuiGraphics(), +// w / 2 - 114514, +// h / 2 + 22, +// 1, +// 0f, +// 0, +// entity +// ); + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/ArmorPlateOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/ArmorPlateOverlay.java new file mode 100644 index 000000000..c0784cc18 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/ArmorPlateOverlay.java @@ -0,0 +1,78 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.client.DisplayConfig; +import com.atsuishio.superbwarfare.init.ModTags; +import com.atsuishio.superbwarfare.tools.NBTTool; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EquipmentSlot; +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(value = Dist.CLIENT) +public class ArmorPlateOverlay { + + private static final ResourceLocation ICON = ModUtils.loc("textures/screens/armor_plate_icon.png"); + private static final ResourceLocation LEVEL1 = ModUtils.loc("textures/screens/armor_plate_level1.png"); + private static final ResourceLocation LEVEL2 = ModUtils.loc("textures/screens/armor_plate_level2.png"); + private static final ResourceLocation LEVEL3 = ModUtils.loc("textures/screens/armor_plate_level3.png"); + private static final ResourceLocation LEVEL1_FRAME = ModUtils.loc("textures/screens/armor_plate_level1_frame.png"); + private static final ResourceLocation LEVEL2_FRAME = ModUtils.loc("textures/screens/armor_plate_level2_frame.png"); + private static final ResourceLocation LEVEL3_FRAME = ModUtils.loc("textures/screens/armor_plate_level3_frame.png"); + + @SubscribeEvent + public static void onRenderGui(RenderGuiEvent.Pre event) { + if (!DisplayConfig.ARMOR_PLATE_HUD.get()) return; + + var gui = event.getGuiGraphics(); + int h = gui.guiHeight(); + + Player player = Minecraft.getInstance().player; + if (player == null) return; + if (player.isSpectator()) return; + + ItemStack stack = player.getItemBySlot(EquipmentSlot.CHEST); + if (stack == ItemStack.EMPTY) return; + var tag = NBTTool.getTag(stack); + if (!tag.contains("ArmorPlate")) return; + + double amount = 2 * tag.getDouble("ArmorPlate"); + + int armorLevel = 1; + if (stack.is(ModTags.Items.MILITARY_ARMOR)) { + armorLevel = 2; + } else if (stack.is(ModTags.Items.MILITARY_ARMOR_HEAVY)) { + armorLevel = 3; + } + + ResourceLocation texture = switch (armorLevel) { + case 2 -> LEVEL2; + case 3 -> LEVEL3; + default -> LEVEL1; + }; + ResourceLocation frame = switch (armorLevel) { + case 2 -> LEVEL2_FRAME; + case 3 -> LEVEL3_FRAME; + default -> LEVEL1_FRAME; + }; + + int length = armorLevel * 30; + + gui.pose().pushPose(); + // 渲染图标 + gui.blit(ICON, 10, h - 13, 0, 0, 8, 8, 8, 8); + + // 渲染框架 + gui.blit(frame, 20, h - 12, 0, 0, length, 6, length, 6); + + // 渲染盔甲值 + gui.blit(texture, 20, h - 12, 0, 0, (int) amount, 6, length, 6); + + gui.pose().popPose(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/CannonHudOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/CannonHudOverlay.java new file mode 100644 index 000000000..a7e791ace --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/CannonHudOverlay.java @@ -0,0 +1,186 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.client.RenderHelper; +import com.atsuishio.superbwarfare.entity.vehicle.AnnihilatorEntity; +import com.atsuishio.superbwarfare.entity.vehicle.Mk42Entity; +import com.atsuishio.superbwarfare.entity.vehicle.Mle1934Entity; +import com.atsuishio.superbwarfare.entity.vehicle.base.CannonEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.tools.FormatTool; +import com.atsuishio.superbwarfare.tools.InventoryTool; +import com.atsuishio.superbwarfare.tools.TraceTool; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Camera; +import net.minecraft.client.CameraType; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +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; +import org.joml.Math; + +import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; +import static com.atsuishio.superbwarfare.client.overlay.VehicleHudOverlay.renderKillIndicator; +import static com.atsuishio.superbwarfare.client.overlay.VehicleHudOverlay.renderKillIndicator3P; + +@EventBusSubscriber(value = Dist.CLIENT) +public class CannonHudOverlay { + + @SubscribeEvent + public static void eventHandler(RenderGuiEvent.Pre event) { + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + Minecraft mc = Minecraft.getInstance(); + Player player = mc.player; + GuiGraphics guiGraphics = event.getGuiGraphics(); + PoseStack poseStack = guiGraphics.pose(); + Camera camera = mc.gameRenderer.getMainCamera(); + Vec3 cameraPos = camera.getPosition(); + + if (!shouldRenderCrossHair(player)) return; + + Entity vehicle = player.getVehicle(); + if (vehicle instanceof CannonEntity cannonEntity && cannonEntity instanceof VehicleEntity cannon) { + poseStack.pushPose(); + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + RenderSystem.setShaderColor(1, 1, 1, 1); + + preciseBlit(event.getGuiGraphics(), ModUtils.loc("textures/screens/compass_white.png"), (float) w / 2 - 128, (float) 10, 128 + ((float) 64 / 45 * (Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), cannon.yRotO, cannon.getYRot()))), 0, 256, 16, 512, 16); + preciseBlit(event.getGuiGraphics(), ModUtils.loc("textures/screens/roll_ind_white.png"), w / 2F - 4, 27, 0, 0.0F, 8, 8, 8, 8); + + String angle = FormatTool.DECIMAL_FORMAT_1ZZ.format(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), cannon.yRotO, cannon.getYRot())); + int width = Minecraft.getInstance().font.width(angle); + event.getGuiGraphics().drawString(Minecraft.getInstance().font, Component.literal(angle), w / 2 - width / 2, 40, -1, false); + + preciseBlit(event.getGuiGraphics(), ModUtils.loc("textures/screens/cannon/cannon_pitch.png"), w / 2F + 166, h / 2F - 64, 0, 0.0F, 8, 128, 8, 128); + + String pitch = FormatTool.DECIMAL_FORMAT_1ZZ.format(-Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), cannon.xRotO, cannon.getXRot())); + int widthP = Minecraft.getInstance().font.width(pitch); + + poseStack.pushPose(); + + event.getGuiGraphics().pose().translate(0, Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), cannon.xRotO, cannon.getXRot()) * 0.7, 0); + preciseBlit(event.getGuiGraphics(), ModUtils.loc("textures/screens/cannon/cannon_pitch_ind.png"), w / 2F + 158, h / 2F - 4, 0, 0.0F, 8, 8, 8, 8); + event.getGuiGraphics().drawString(Minecraft.getInstance().font, Component.literal(pitch), w / 2 + 157 - widthP, h / 2 - 4, -1, false); + poseStack.popPose(); + + if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON || ClientEventHandler.zoomVehicle) { + float fovAdjust = (float) 70 / Minecraft.getInstance().options.fov().get(); + + float f = (float) Math.min(w, h); + float f1 = Math.min((float) w / f, (float) h / f) * fovAdjust; + int i = Mth.floor(f * f1); + int j = Mth.floor(f * f1); + int k = (w - i) / 2; + int l = (h - j) / 2; + if (ClientEventHandler.zoomVehicle) { + Entity lookingEntity = TraceTool.findLookingEntity(player, 512); + boolean lookAtEntity = false; + + BlockHitResult result = player.level().clip(new ClipContext(player.getEyePosition(), player.getEyePosition().add(player.getViewVector(1).scale(512)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)); + Vec3 hitPos = result.getLocation(); + + double blockRange = player.getEyePosition(1).distanceTo(hitPos); + + double entityRange = 0; + if (lookingEntity instanceof LivingEntity living) { + lookAtEntity = true; + entityRange = player.distanceTo(living); + } + if (lookAtEntity) { + event.getGuiGraphics().drawString(Minecraft.getInstance().font, Component.translatable("tips.superbwarfare.drone.range") + .append(Component.literal(FormatTool.format1D(entityRange, "m ") + lookingEntity.getDisplayName())), + w / 2 + 14, h / 2 - 20, -1, false); + } else { + if (blockRange > 511) { + event.getGuiGraphics().drawString(Minecraft.getInstance().font, Component.translatable("tips.superbwarfare.drone.range") + .append(Component.literal("---m")), w / 2 + 14, h / 2 - 20, -1, false); + } else { + event.getGuiGraphics().drawString(Minecraft.getInstance().font, Component.translatable("tips.superbwarfare.drone.range") + .append(Component.literal(FormatTool.format1D(blockRange, "m"))), + w / 2 + 14, h / 2 - 20, -1, false); + } + } + if (cannon instanceof AnnihilatorEntity) { + preciseBlit(event.getGuiGraphics(), ModUtils.loc("textures/screens/cannon/laser_cannon_crosshair.png"), k, l, 0, 0.0F, i, j, i, j); + } else { + preciseBlit(event.getGuiGraphics(), ModUtils.loc("textures/screens/cannon/cannon_crosshair.png"), k, l, 0, 0.0F, i, j, i, j); + } + float diffY = -Mth.wrapDegrees(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.yHeadRotO, player.getYHeadRot()) - Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), cannon.yRotO, cannon.getYRot())); + + preciseBlit(event.getGuiGraphics(), ModUtils.loc("textures/screens/cannon/indicator.png"), w / 2F - 4.3f + 0.45f * diffY, h / 2F - 10, 0, 0.0F, 8, 8, 8, 8); + } else { + preciseBlit(event.getGuiGraphics(), ModUtils.loc("textures/screens/cannon/cannon_crosshair_notzoom.png"), k, l, 0, 0.0F, i, j, i, j); + } + renderKillIndicator(guiGraphics, w, h); + } else if (Minecraft.getInstance().options.getCameraType() == CameraType.THIRD_PERSON_BACK && !ClientEventHandler.zoomVehicle) { + Vec3 p = RenderHelper.worldToScreen(new Vec3(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.xo, player.getX()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.yo, player.getY()), + Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.zo, player.getZ())).add(cannon.getViewVector(event.getPartialTick().getGameTimeDeltaTicks()).scale(128)), cameraPos); + + // 第三人称准星 + if (p != null) { + poseStack.pushPose(); + float x = (float) p.x; + float y = (float) p.y; + + poseStack.pushPose(); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/drone.png"), x - 12, y - 12, 0, 0, 24, 24, 24, 24); + renderKillIndicator3P(guiGraphics, x - 7.5f + (float) (2 * (Math.random() - 0.5f)), y - 7.5f + (float) (2 * (Math.random() - 0.5f))); + + poseStack.pushPose(); + + poseStack.translate(x, y, 0); + poseStack.scale(0.75f, 0.75f, 1); + + if (player.getVehicle() instanceof Mk42Entity || player.getVehicle() instanceof Mle1934Entity) { + if (cannonEntity.getWeaponIndex(0) == 0) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("AP SHELL " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : cannonEntity.getAmmoCount(player))), 30, -9, -1, false); + } else { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("HE SHELL " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : cannonEntity.getAmmoCount(player))), 30, -9, -1, false); + } + } + + // 歼灭者 + if (player.getVehicle() instanceof AnnihilatorEntity annihilatorEntity) { + guiGraphics.drawString(mc.font, Component.literal("LASER " + (FormatTool.format0D((double) (100 * annihilatorEntity.getEnergy()) / annihilatorEntity.getMaxEnergy()) + "%")), 30, -9, -1, false); + } + + double heal = 1 - cannon.getHealth() / cannon.getMaxHealth(); + + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("HP " + + FormatTool.format0D(100 * cannon.getHealth() / cannon.getMaxHealth())), 30, 1, Mth.hsvToRgb(0F, (float) heal, 1.0F), false); + + poseStack.popPose(); + poseStack.popPose(); + poseStack.popPose(); + } + } + poseStack.popPose(); + } + } + + private static boolean shouldRenderCrossHair(Player player) { + if (player == null) return false; + return !player.isSpectator() + && (player.getVehicle() != null && (player.getVehicle() instanceof CannonEntity)); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/DroneUIOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/DroneUIOverlay.java new file mode 100644 index 000000000..546cb85e2 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/DroneUIOverlay.java @@ -0,0 +1,176 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.client.RenderHelper; +import com.atsuishio.superbwarfare.entity.vehicle.DroneEntity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.FormatTool; +import com.atsuishio.superbwarfare.tools.NBTTool; +import com.atsuishio.superbwarfare.tools.SeekTool; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +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; + +import java.util.List; + +import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; +import static com.atsuishio.superbwarfare.entity.vehicle.DroneEntity.AMMO; +import static com.atsuishio.superbwarfare.entity.vehicle.DroneEntity.KAMIKAZE_MODE; + +@EventBusSubscriber(value = Dist.CLIENT) +public class DroneUIOverlay { + + public static int MAX_DISTANCE = 256; + private static final ResourceLocation FRAME = ModUtils.loc("textures/screens/frame/frame.png"); + + @SubscribeEvent + public static void eventHandler(RenderGuiEvent.Pre event) { + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + + Minecraft mc = Minecraft.getInstance(); + Player player = mc.player; + + if (player == null) return; + + GuiGraphics guiGraphics = event.getGuiGraphics(); + PoseStack poseStack = guiGraphics.pose(); + + ItemStack stack = player.getMainHandItem(); + + poseStack.pushPose(); + + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + RenderSystem.setShaderColor(1, 1, 1, 1); + + var tag = NBTTool.getTag(stack); + if (stack.is(ModItems.MONITOR.get()) && tag.getBoolean("Using") && tag.getBoolean("Linked")) { + guiGraphics.blit(ModUtils.loc("textures/screens/drone.png"), w / 2 - 16, h / 2 - 16, 0, 0, 32, 32, 32, 32); + guiGraphics.blit(ModUtils.loc("textures/screens/drone_fov.png"), w / 2 + 100, h / 2 - 64, 0, 0, 64, 129, 64, 129); + + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/drone_fov_move.png"), (float) w / 2 + 100, (float) (h / 2 - 64 - ((ClientEventHandler.droneFovLerp - 1) * 23.8)), 0, 0, 64, 129, 64, 129); + guiGraphics.drawString(mc.font, Component.literal(FormatTool.format1D(ClientEventHandler.droneFovLerp, "x")), + w / 2 + 144, h / 2 + 56 - (int) ((ClientEventHandler.droneFovLerp - 1) * 23.8), -1, false); + + DroneEntity entity = EntityFindUtil.findDrone(player.level(), tag.getString("LinkedDrone")); + + if (entity != null) { + boolean lookAtEntity = false; + double distance = player.distanceTo(entity); + + BlockHitResult result = entity.level().clip(new ClipContext(entity.getEyePosition(), entity.getEyePosition().add(player.getViewVector(1).scale(512)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, entity)); + Vec3 hitPos = result.getLocation(); + + double blockRange = player.getEyePosition(1).distanceTo(hitPos); + + double entityRange = 0; + + Entity lookingEntity = SeekTool.seekLivingEntity(entity, entity.level(), 512, 2); + if (lookingEntity != null) { + lookAtEntity = true; + entityRange = entity.distanceTo(lookingEntity); + } + + int color = -1; + + // 超出距离警告 + if (distance > MAX_DISTANCE - 48) { + guiGraphics.drawString(mc.font, Component.translatable("tips.superbwarfare.drone.warning"), + w / 2 - 18, h / 2 - 47, -65536, false); + color = -65536; + } + + // 距离 + guiGraphics.drawString(mc.font, Component.translatable("tips.superbwarfare.drone.distance") + .append(Component.literal(FormatTool.format1D(distance, "m"))), + w / 2 + 10, h / 2 + 33, color, false); + + // 血量 + guiGraphics.drawString(mc.font, Component.translatable("tips.superbwarfare.drone.health") + .append(Component.literal(FormatTool.format1D(entity.getHealth()) + " / " + FormatTool.format1D(entity.getMaxHealth()))), + w / 2 - 77, h / 2 + 33, -1, false); + if (entity.getEntityData().get(KAMIKAZE_MODE) == 0) { + // 弹药 + guiGraphics.drawString(mc.font, Component.translatable("tips.superbwarfare.drone.ammo") + .append(Component.literal(FormatTool.format1D(entity.getEntityData().get(AMMO), " / 6"))), + w / 2 + 12, h / 2 - 37, -1, false); + } else { + // 神风 + guiGraphics.drawString(mc.font, Component.translatable("tips.superbwarfare.drone.kamikaze"), + w / 2 + 12, h / 2 - 37, -65536, false); + } + + if (lookAtEntity) { + // 实体距离 + guiGraphics.drawString(mc.font, Component.translatable("tips.superbwarfare.drone.range") + .append(Component.literal(FormatTool.format1D(entityRange, "m ") + lookingEntity.getDisplayName().getString())), + w / 2 + 12, h / 2 - 28, color, false); + } else { + // 方块距离 + if (blockRange > 500) { + guiGraphics.drawString(mc.font, Component.translatable("tips.superbwarfare.drone.range") + .append(Component.literal("---m")), w / 2 + 12, h / 2 - 28, color, false); + } else { + guiGraphics.drawString(mc.font, Component.translatable("tips.superbwarfare.drone.range") + .append(Component.literal(FormatTool.format1D(blockRange, "m"))), + w / 2 + 12, h / 2 - 28, color, false); + } + } + + + List entities = SeekTool.seekLivingEntities(entity, entity.level(), 256, 30); + float fovAdjust2 = (float) (mc.options.fov().get() / 30) - 1; + double zoom = 0.975 * ClientEventHandler.droneFovLerp + 0.06 * fovAdjust2; + + for (var e : entities) { + Vec3 droneVec = new Vec3(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), entity.xo, entity.getX()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), entity.yo + entity.getEyeHeight(), entity.getEyeY()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), entity.zo, entity.getZ())); + Vec3 pos = new Vec3(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), e.xo, e.getX()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), e.yo + e.getEyeHeight(), e.getEyeY()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), e.zo, e.getZ())); + + Vec3 lookAngle = entity.getLookAngle().normalize().scale(pos.distanceTo(droneVec) * (1 - 1.0 / zoom)); + + var cPos = droneVec.add(lookAngle); + Vec3 point = RenderHelper.worldToScreen(pos, cPos); + if (point != null) { + poseStack.pushPose(); + float x = (float) point.x; + float y = (float) point.y; + + RenderHelper.preciseBlit(guiGraphics, FRAME, x - 12, y - 12, 0, 0, 24, 24, 24, 24, 1f); + poseStack.popPose(); + } + } + } + } + + RenderSystem.depthMask(true); + RenderSystem.defaultBlendFunc(); + RenderSystem.enableDepthTest(); + RenderSystem.disableBlend(); + RenderSystem.setShaderColor(1, 1, 1, 1); + + poseStack.popPose(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/GrenadeLauncherOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/GrenadeLauncherOverlay.java new file mode 100644 index 000000000..1f45e01ef --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/GrenadeLauncherOverlay.java @@ -0,0 +1,67 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.capability.ModCapabilities; +import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.CannonEntity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.init.ModItems; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.CameraType; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.world.entity.player.Player; +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(value = Dist.CLIENT) +public class GrenadeLauncherOverlay { + + @SubscribeEvent + public static void eventHandler(RenderGuiEvent.Pre event) { + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + Player player = Minecraft.getInstance().player; + if (player == null) return; + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null || cap.edit) return; + + if (player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) + return; + if (!shouldRenderCrossHair(player)) return; + + GuiGraphics guiGraphics = event.getGuiGraphics(); + + guiGraphics.pose().pushPose(); + + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + RenderSystem.setShaderColor(1, 1, 1, 1); + + guiGraphics.blit(ModUtils.loc("textures/screens/rex.png"), w / 2 - 16, h / 2 - 16, 0, 0, 32, 32, 32, 32); + + RenderSystem.depthMask(true); + RenderSystem.defaultBlendFunc(); + RenderSystem.enableDepthTest(); + RenderSystem.disableBlend(); + RenderSystem.setShaderColor(1, 1, 1, 1); + + guiGraphics.pose().popPose(); + } + + private static boolean shouldRenderCrossHair(Player player) { + if (player == null) return false; + return !player.isSpectator() + && (player.getMainHandItem().getItem() == ModItems.M_79.get() || player.getMainHandItem().getItem() == ModItems.SECONDARY_CATACLYSM.get()) + && (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON || (player.isPassenger() && player.getVehicle() instanceof CannonEntity)) + && !ClientEventHandler.zoom; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/HandsomeFrameOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/HandsomeFrameOverlay.java new file mode 100644 index 000000000..c73f6a2b5 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/HandsomeFrameOverlay.java @@ -0,0 +1,115 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.capability.ModCapabilities; +import com.atsuishio.superbwarfare.client.RenderHelper; +import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.item.gun.GunItem; +import com.atsuishio.superbwarfare.tools.SeekTool; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RenderGuiEvent; + +import java.util.List; + +@EventBusSubscriber(value = Dist.CLIENT) +public class HandsomeFrameOverlay { + + private static final ResourceLocation FRAME = ModUtils.loc("textures/screens/frame/frame.png"); + private static final ResourceLocation FRAME_WEAK = ModUtils.loc("textures/screens/frame/frame_weak.png"); + private static final ResourceLocation FRAME_TARGET = ModUtils.loc("textures/screens/frame/frame_target.png"); + private static final ResourceLocation FRAME_LOCK = ModUtils.loc("textures/screens/frame/frame_lock.png"); + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void eventHandler(RenderGuiEvent.Pre event) { + Player player = Minecraft.getInstance().player; + PoseStack poseStack = event.getGuiGraphics().pose(); + + if (player != null) { + ItemStack stack = player.getMainHandItem(); + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null || cap.edit) return; + if (player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) + return; + + if (stack.getItem() instanceof GunItem && Minecraft.getInstance().options.getCameraType().isFirstPerson()) { + + // TODO intelligent chip perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.INTELLIGENT_CHIP.get(), stack); + int level = 0; + if (level == 0) return; + + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + RenderSystem.setShaderColor(1, 1, 1, 1); + + List allEntities = SeekTool.seekLivingEntitiesThroughWall(player, player.level(), 32 + 8 * (level - 1), 30); + List visibleEntities = SeekTool.seekLivingEntities(player, player.level(), 32 + 8 * (level - 1), 30); + + Entity naerestEntity = SeekTool.seekLivingEntity(player, player.level(), 32 + 8 * (level - 1), 30); + Entity targetEntity = ClientEventHandler.entity; + + + float fovAdjust2 = (float) (Minecraft.getInstance().options.fov().get() / 30) - 1; + + double zoom = 1; + + if (ClientEventHandler.zoom) { + zoom = Minecraft.getInstance().options.fov().get() / ClientEventHandler.fov + 0.05 * fovAdjust2; + } + + for (var e : allEntities) { + Vec3 playerVec = new Vec3(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.xo, player.getX()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.yo + player.getEyeHeight(), player.getEyeY()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.zo, player.getZ())); + Vec3 pos = new Vec3(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), e.xo, e.getX()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), e.yo + e.getEyeHeight(), e.getEyeY()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), e.zo, e.getZ())); + Vec3 lookAngle = player.getLookAngle().normalize().scale(pos.distanceTo(playerVec) * (1 - 1.0 / zoom)); + + var cPos = playerVec.add(lookAngle); + Vec3 point = RenderHelper.worldToScreen(pos, cPos); + if (point == null) return; + + boolean lockOn = e == targetEntity; + boolean isNearestEntity = e == naerestEntity; + + poseStack.pushPose(); + float x = (float) point.x; + float y = (float) point.y; + + var canBeSeen = visibleEntities.contains(e); + + ResourceLocation icon; + if (lockOn) { + icon = FRAME_LOCK; + } else if (canBeSeen) { + if (isNearestEntity) { + icon = FRAME_TARGET; + } else { + icon = FRAME; + } + } else { + icon = FRAME_WEAK; + } + + RenderHelper.preciseBlit(event.getGuiGraphics(), icon, x - 12, y - 12, 0, 0, 24, 24, 24, 24, 1f); + poseStack.popPose(); + } + } + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/HelicopterHudOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/HelicopterHudOverlay.java new file mode 100644 index 000000000..1795b3397 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/HelicopterHudOverlay.java @@ -0,0 +1,239 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.capability.ModCapabilities; +import com.atsuishio.superbwarfare.client.RenderHelper; +import com.atsuishio.superbwarfare.entity.vehicle.Ah6Entity; +import com.atsuishio.superbwarfare.entity.vehicle.base.HelicopterEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.WeaponVehicleEntity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.tools.FormatTool; +import com.atsuishio.superbwarfare.tools.InventoryTool; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import net.minecraft.client.Camera; +import net.minecraft.client.CameraType; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RenderGuiEvent; +import org.joml.Math; +import org.joml.Matrix4f; +import org.joml.Vector4f; + +import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.HEAT; + +@EventBusSubscriber(value = Dist.CLIENT) +public class HelicopterHudOverlay { + + private static float scopeScale = 1; + private static float lerpVy = 1; + private static float lerpPower = 1; + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void eventHandler(RenderGuiEvent.Pre event) { + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + + Minecraft mc = Minecraft.getInstance(); + Player player = mc.player; + Camera camera = mc.gameRenderer.getMainCamera(); + Vec3 cameraPos = camera.getPosition(); + GuiGraphics guiGraphics = event.getGuiGraphics(); + PoseStack poseStack = guiGraphics.pose(); + + if (player == null) return; + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null || cap.edit) return; + + if (player.getVehicle() instanceof HelicopterEntity iHelicopterEntity && player.getVehicle() instanceof MobileVehicleEntity mobileVehicle && iHelicopterEntity.isDriver(player) && player.getVehicle() instanceof WeaponVehicleEntity weaponVehicle) { + poseStack.pushPose(); + + poseStack.translate(-6 * ClientEventHandler.turnRot[1], -6 * ClientEventHandler.turnRot[0], 0); + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + RenderSystem.setShaderColor(1, 1, 1, 1); + + scopeScale = Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), scopeScale, 1F); + float f = (float) Math.min(w, h); + float f1 = Math.min((float) w / f, (float) h / f) * scopeScale; + float i = Mth.floor(f * f1); + float j = Mth.floor(f * f1); + float k = ((w - i) / 2); + float l = ((h - j) / 2); + + if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/helicopter/heli_base.png"), k, l, 0, 0.0F, i, j, i, j); + renderDriverAngle(guiGraphics, player, mobileVehicle, k, l, i, j, event.getPartialTick().getGameTimeDeltaTicks()); + + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/compass.png"), (float) w / 2 - 128, (float) 6, 128 + ((float) 64 / 45 * mobileVehicle.getYRot()), 0, 256, 16, 512, 16); + + poseStack.pushPose(); + poseStack.rotateAround(Axis.ZP.rotationDegrees(-iHelicopterEntity.getRotZ(event.getPartialTick().getGameTimeDeltaTicks())), w / 2f, h / 2f, 0); + float pitch = iHelicopterEntity.getRotX(event.getPartialTick().getGameTimeDeltaTicks()); + + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/helicopter/heli_line.png"), (float) w / 2 - 128, (float) h / 2 - 512 - 5.475f * pitch, 0, 0, 256, 1024, 256, 1024); + poseStack.popPose(); + poseStack.pushPose(); + poseStack.rotateAround(Axis.ZP.rotationDegrees(iHelicopterEntity.getRotZ(event.getPartialTick().getGameTimeDeltaTicks())), w / 2f, h / 2f - 56, 0); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/helicopter/roll_ind.png"), (float) w / 2 - 8, (float) h / 2 - 88, 0, 0, 16, 16, 16, 16); + poseStack.popPose(); + + guiGraphics.blit(ModUtils.loc("textures/screens/helicopter/heli_power_ruler.png"), w / 2 + 100, h / 2 - 64, 0, 0, 64, 128, 64, 128); + + double height = mobileVehicle.position().distanceTo((Vec3.atLowerCornerOf(mobileVehicle.level().clip(new ClipContext(mobileVehicle.position(), mobileVehicle.position().add(new Vec3(0, -1, 0).scale(100)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.ANY, mobileVehicle)).getBlockPos()))); + double blockInWay = mobileVehicle.position().distanceTo((Vec3.atLowerCornerOf(mobileVehicle.level().clip(new ClipContext(mobileVehicle.position(), mobileVehicle.position().add(new Vec3(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y + 0.06, mobileVehicle.getDeltaMovement().z).normalize().scale(100)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.ANY, mobileVehicle)).getBlockPos()))); + + float power = iHelicopterEntity.getPower(); + lerpPower = Mth.lerp(0.001f * event.getPartialTick().getGameTimeDeltaTicks(), lerpPower, power); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/helicopter/heli_power.png"), (float) w / 2 + 130f, ((float) h / 2 - 64 + 124 - power * 980), 0, 0, 4, power * 980, 4, power * 980); + lerpVy = (float) Mth.lerp(0.021f * event.getPartialTick().getGameTimeDeltaTicks(), lerpVy, mobileVehicle.getDeltaMovement().y()); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/helicopter/heli_vy_move.png"), (float) w / 2 + 138, ((float) h / 2 - 3 - Math.max(lerpVy * 20, -24) * 2.5f), 0, 0, 8, 8, 8, 8); + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal(FormatTool.format0D(lerpVy * 20, "m/s")), + w / 2 + 146, (int) (h / 2 - 3 - Math.max(lerpVy * 20, -24) * 2.5), (lerpVy * 20 < -24 || ((lerpVy * 20 < -10 || (lerpVy * 20 < -1 && length(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y, mobileVehicle.getDeltaMovement().z) * 72 > 100)) && height < 36) || (length(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y, mobileVehicle.getDeltaMovement().z) * 72 > 40 && blockInWay < 72) ? -65536 : 0x66FF00), false); + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal(FormatTool.format0D(mobileVehicle.getY())), + w / 2 + 104, h / 2, 0x66FF00, false); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/helicopter/speed_frame.png"), (float) w / 2 - 144, (float) h / 2 - 6, 0, 0, 50, 18, 50, 18); + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal(FormatTool.format0D(length(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y, mobileVehicle.getDeltaMovement().z) * 72, "km/h")), + w / 2 - 140, h / 2, 0x66FF00, false); + + if (mobileVehicle instanceof Ah6Entity ah6Entity) { + if (weaponVehicle.getWeaponIndex(0) == 0) { + double heat = 1 - ah6Entity.getEntityData().get(HEAT) / 100.0F; + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("20MM CANNON " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : iHelicopterEntity.getAmmoCount(player))), w / 2 - 160, h / 2 - 60, Mth.hsvToRgb((float) heat / 3.745318352059925F, 1.0F, 1.0F), false); + } else { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("70MM ROCKET " + iHelicopterEntity.getAmmoCount(player)), w / 2 - 160, h / 2 - 60, 0x66FF00, false); + } + } + + + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("FLARE " + iHelicopterEntity.getDecoy()), w / 2 - 160, h / 2 - 50, 0x66FF00, false); + + if (lerpVy * 20 < -24) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("SINK RATE,PULL UP!"), + w / 2 - 53, h / 2 + 24, -65536, false); + } else if (((lerpVy * 20 < -10 || (lerpVy * 20 < -1 && length(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y, mobileVehicle.getDeltaMovement().z) * 72 > 100)) && height < 36) + || (length(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y, mobileVehicle.getDeltaMovement().z) * 72 > 40 && blockInWay < 72)) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("TERRAIN TERRAIN"), + w / 2 - 42, h / 2 + 24, -65536, false); + } + + if (mobileVehicle.getEnergy() < 0.02 * mobileVehicle.getMaxEnergy()) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("NO POWER!"), + w / 2 - 144, h / 2 + 14, -65536, false); + } else if (mobileVehicle.getEnergy() < 0.2 * mobileVehicle.getMaxEnergy()) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("LOW POWER"), + w / 2 - 144, h / 2 + 14, 0xFF6B00, false); + } + + } + + Matrix4f transform = getVehicleTransform(mobileVehicle, event.getPartialTick().getGameTimeDeltaTicks()); + float x0 = 0f; + float y0 = 0.65f; + float z0 = 0.8f; + + Vector4f worldPosition = transformPosition(transform, x0, y0, z0); + + float fovAdjust2 = (float) (Minecraft.getInstance().options.fov().get() / 30) - 1; + double zoom = 0.96 * 3 + 0.06 * fovAdjust2; + + Vec3 pos = new Vec3(worldPosition.x, worldPosition.y, worldPosition.z).add(mobileVehicle.getViewVector(event.getPartialTick().getGameTimeDeltaTicks()).scale(192)); + Vec3 lookAngle = player.getLookAngle().normalize().scale(pos.distanceTo(cameraPos) * (1 - 1.0 / zoom)); + + var cPos = cameraPos.add(lookAngle); + + Vec3 p = RenderHelper.worldToScreen(new Vec3(worldPosition.x, worldPosition.y, worldPosition.z).add(mobileVehicle.getViewVector(event.getPartialTick().getGameTimeDeltaTicks()).scale(192)), ClientEventHandler.zoomVehicle ? cPos : cameraPos); + + if (p != null) { + poseStack.pushPose(); + float x = (float) p.x; + float y = (float) p.y; + + + if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/helicopter/crosshair_ind.png"), x - 8, y - 8, 0, 0, 16, 16, 16, 16); + renderKillIndicator(guiGraphics, x - 7.5f + (float) (2 * (Math.random() - 0.5f)), y - 7.5f + (float) (2 * (Math.random() - 0.5f))); + } else if (Minecraft.getInstance().options.getCameraType() == CameraType.THIRD_PERSON_BACK) { + poseStack.pushPose(); + poseStack.rotateAround(Axis.ZP.rotationDegrees(iHelicopterEntity.getRotZ(event.getPartialTick().getGameTimeDeltaTicks())), x, y, 0); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/drone.png"), x - 8, y - 8, 0, 0, 16, 16, 16, 16); + renderKillIndicator(guiGraphics, x - 7.5f + (float) (2 * (Math.random() - 0.5f)), y - 7.5f + (float) (2 * (Math.random() - 0.5f))); + + poseStack.pushPose(); + + poseStack.translate(x, y, 0); + poseStack.scale(0.75f, 0.75f, 1); + + if (mobileVehicle instanceof Ah6Entity ah6Entity) { + if (weaponVehicle.getWeaponIndex(0) == 0) { + double heat = ah6Entity.getEntityData().get(HEAT) / 100.0F; + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("20MM CANNON " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : iHelicopterEntity.getAmmoCount(player))), 25, -9, Mth.hsvToRgb(0F, (float) heat, 1.0F), false); + } else { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("70MM ROCKET " + iHelicopterEntity.getAmmoCount(player)), 25, -9, -1, false); + } + } + + + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("FLARE " + iHelicopterEntity.getDecoy()), 25, 1, -1, false); + poseStack.popPose(); + poseStack.popPose(); + } + poseStack.popPose(); + } + + poseStack.popPose(); + } else { + scopeScale = 0.7f; + } + } + + private static void renderKillIndicator(GuiGraphics guiGraphics, float posX, float posY) { + VehicleHudOverlay.renderKillIndicator3P(guiGraphics, posX, posY); + } + + private static void renderDriverAngle(GuiGraphics guiGraphics, Player player, Entity heli, float k, float l, float i, float j, float ticks) { + float diffY = Mth.wrapDegrees(Mth.lerp(ticks, player.yHeadRotO, player.getYHeadRot()) - Mth.lerp(ticks, heli.yRotO, heli.getYRot())) * 0.35f; + float diffX = Mth.wrapDegrees(Mth.lerp(ticks, player.xRotO, player.getXRot()) - Mth.lerp(ticks, heli.xRotO, heli.getXRot())) * 0.072f; + + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/helicopter/heli_driver_angle.png"), k + diffY, l + diffX, 0, 0.0F, i, j, i, j); + } + + public static Matrix4f getVehicleTransform(VehicleEntity vehicle, float partialTicks) { + Matrix4f transform = new Matrix4f(); + transform.translate((float) Mth.lerp(partialTicks, vehicle.xo, vehicle.getX()), (float) Mth.lerp(partialTicks, vehicle.yo + 1.45, vehicle.getY() + 1.45), (float) Mth.lerp(partialTicks, vehicle.zo, vehicle.getZ())); + transform.rotate(Axis.YP.rotationDegrees(-vehicle.getYRot())); + transform.rotate(Axis.XP.rotationDegrees(vehicle.getXRot())); + transform.rotate(Axis.ZP.rotationDegrees(vehicle.getRoll())); + return transform; + } + + public static Vector4f transformPosition(Matrix4f transform, float x, float y, float z) { + return transform.transform(new Vector4f(x, y, z, 1)); + } + + public static double length(double x, double y, double z) { + return Math.sqrt(x * x + y * y + z * z); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/JavelinHudOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/JavelinHudOverlay.java new file mode 100644 index 000000000..7352ec89e --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/JavelinHudOverlay.java @@ -0,0 +1,148 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.capability.ModCapabilities; +import com.atsuishio.superbwarfare.client.RenderHelper; +import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.GunsTool; +import com.atsuishio.superbwarfare.tools.NBTTool; +import com.atsuishio.superbwarfare.tools.SeekTool; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RenderGuiEvent; + +import java.util.List; + +import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; + +@EventBusSubscriber(value = Dist.CLIENT) +public class JavelinHudOverlay { + + private static final ResourceLocation FRAME = ModUtils.loc("textures/screens/frame/frame.png"); + private static final ResourceLocation FRAME_TARGET = ModUtils.loc("textures/screens/frame/frame_target.png"); + private static final ResourceLocation FRAME_LOCK = ModUtils.loc("textures/screens/frame/frame_lock.png"); + private static float scopeScale = 1; + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void eventHandler(RenderGuiEvent.Pre event) { + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + Player player = Minecraft.getInstance().player; + PoseStack poseStack = event.getGuiGraphics().pose(); + + if (player != null) { + ItemStack stack = player.getMainHandItem(); + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null || cap.edit) return; + + if (player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) + return; + var tag = NBTTool.getTag(stack); + + if ((stack.getItem() == ModItems.JAVELIN.get() && !tag.getBoolean("HoloHidden")) && Minecraft.getInstance().options.getCameraType().isFirstPerson() && ClientEventHandler.zoom) { + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + RenderSystem.setShaderColor(1, 1, 1, 1); + float deltaFrame = Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(); + float moveX = (float) (-32 * ClientEventHandler.turnRot[1] - (player.isSprinting() ? 100 : 67) * ClientEventHandler.movePosX + 3 * ClientEventHandler.cameraRot[2]); + float moveY = (float) (-32 * ClientEventHandler.turnRot[0] + 100 * (float) ClientEventHandler.velocityY - (player.isSprinting() ? 100 : 67) * ClientEventHandler.movePosY - 12 * ClientEventHandler.firePos + 3 * ClientEventHandler.cameraRot[1]); + scopeScale = (float) Mth.lerp(0.5F * deltaFrame, scopeScale, 1.35F + (0.2f * ClientEventHandler.firePos)); + float f = (float) Math.min(w, h); + float f1 = Math.min((float) w / f, (float) h / f) * scopeScale; + float i = Mth.floor(f * f1); + float j = Mth.floor(f * f1); + float k = ((w - i) / 2) + moveX; + float l = ((h - j) / 2) + moveY; + float i1 = k + i; + float j1 = l + j; + preciseBlit(event.getGuiGraphics(), ModUtils.loc("textures/screens/javelin/javelin_hud.png"), k, l, 0, 0.0F, i, j, i, j); + preciseBlit(event.getGuiGraphics(), ModUtils.loc(tag.getBoolean("TopMode") ? "textures/screens/javelin/top.png" : "textures/screens/javelin/dir.png"), k, l, 0, 0.0F, i, j, i, j); + preciseBlit(event.getGuiGraphics(), ModUtils.loc(GunsTool.getGunIntTag(stack, "Ammo", 0) > 0 ? "textures/screens/javelin/missile_green.png" : "textures/screens/javelin/missile_red.png"), k, l, 0, 0.0F, i, j, i, j); + if (tag.getInt("SeekTime") > 1 && tag.getInt("SeekTime") < 20) { + preciseBlit(event.getGuiGraphics(), ModUtils.loc("textures/screens/javelin/seek.png"), k, l, 0, 0.0F, i, j, i, j); + } + + event.getGuiGraphics().fill(RenderType.guiOverlay(), 0, (int) l, (int) k + 3, (int) j1, -90, -16777216); + event.getGuiGraphics().fill(RenderType.guiOverlay(), (int) i1, (int) l, w, (int) j1, -90, -16777216); + RenderSystem.depthMask(true); + RenderSystem.defaultBlendFunc(); + RenderSystem.enableDepthTest(); + RenderSystem.disableBlend(); + RenderSystem.setShaderColor(1, 1, 1, 1); + + float fovAdjust = (float) Minecraft.getInstance().options.fov().get() / 80; + + Entity targetEntity = EntityFindUtil.findEntity(player.level(), tag.getString("TargetEntity")); + List entities = SeekTool.seekLivingEntities(player, player.level(), 512, 8 * fovAdjust); + Entity naerestEntity = SeekTool.seekLivingEntity(player, player.level(), 512, 6); + + float fovAdjust2 = (float) (Minecraft.getInstance().options.fov().get() / 30) - 1; + + double zoom = Minecraft.getInstance().options.fov().get() / ClientEventHandler.fov + 0.5 * fovAdjust2; + + Vec3 playerVec = new Vec3(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.xo, player.getX()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.yo + player.getEyeHeight(), player.getEyeY()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.zo, player.getZ())); + + if (tag.getInt("GuideType") == 0) { + for (var e : entities) { + Vec3 pos = new Vec3(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), e.xo, e.getX()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), e.yo + e.getEyeHeight(), e.getEyeY()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), e.zo, e.getZ())); + Vec3 lookAngle = player.getLookAngle().normalize().scale(pos.distanceTo(playerVec) * (1 - 1.0 / zoom)); + + var cPos = playerVec.add(lookAngle); + Vec3 point = RenderHelper.worldToScreen(pos, cPos); + if (point == null) return; + + boolean lockOn = tag.getInt("SeekTime") > 20 && e == targetEntity; + boolean nearest = e == naerestEntity; + + poseStack.pushPose(); + float x = (float) point.x; + float y = (float) point.y; + + RenderHelper.preciseBlit(event.getGuiGraphics(), lockOn ? FRAME_LOCK : nearest ? FRAME_TARGET : FRAME, x - 12, y - 12, 0, 0, 24, 24, 24, 24, 1f); + poseStack.popPose(); + } + } else { + Vec3 pos = new Vec3(tag.getDouble("TargetPosX"), tag.getDouble("TargetPosY"), tag.getDouble("TargetPosZ")); + Vec3 lookAngle = player.getLookAngle().normalize().scale(pos.distanceTo(playerVec) * (1 - 1.0 / zoom)); + + boolean lockOn = tag.getInt("SeekTime") > 20; + + var cPos = playerVec.add(lookAngle); + Vec3 point = RenderHelper.worldToScreen(pos, cPos); + if (point == null) return; + + poseStack.pushPose(); + float x = (float) point.x; + float y = (float) point.y; + + RenderHelper.preciseBlit(event.getGuiGraphics(), lockOn ? FRAME_LOCK : FRAME_TARGET, x - 12, y - 12, 0, 0, 24, 24, 24, 24, 1f); + poseStack.popPose(); + } + + } else { + scopeScale = 1; + } + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/KillMessageOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/KillMessageOverlay.java new file mode 100644 index 000000000..4b64f4481 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/KillMessageOverlay.java @@ -0,0 +1,322 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.client.KillMessageConfig; +import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.event.KillMessageHandler; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.item.gun.GunItem; +import com.atsuishio.superbwarfare.tools.DamageTypeTool; +import com.atsuishio.superbwarfare.tools.PlayerKillRecord; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.player.Player; +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; +import org.jetbrains.annotations.Nullable; +import top.theillusivec4.curios.api.CuriosApi; + +import java.util.concurrent.atomic.AtomicReference; + +import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; + +@EventBusSubscriber(value = Dist.CLIENT) +public class KillMessageOverlay { + + private static final ResourceLocation HEADSHOT = ModUtils.loc("textures/screens/damage_types/headshot.png"); + + private static final ResourceLocation KNIFE = ModUtils.loc("textures/screens/damage_types/knife.png"); + private static final ResourceLocation EXPLOSION = ModUtils.loc("textures/screens/damage_types/explosion.png"); + private static final ResourceLocation CLAYMORE = ModUtils.loc("textures/screens/damage_types/claymore.png"); + private static final ResourceLocation GENERIC = ModUtils.loc("textures/screens/damage_types/generic.png"); + private static final ResourceLocation BEAST = ModUtils.loc("textures/screens/damage_types/beast.png"); + private static final ResourceLocation BLEEDING = ModUtils.loc("textures/screens/damage_types/bleeding.png"); + private static final ResourceLocation SHOCK = ModUtils.loc("textures/screens/damage_types/shock.png"); + private static final ResourceLocation BLOOD_CRYSTAL = ModUtils.loc("textures/screens/damage_types/blood_crystal.png"); + private static final ResourceLocation BURN = ModUtils.loc("textures/screens/damage_types/burn.png"); + private static final ResourceLocation DRONE = ModUtils.loc("textures/screens/damage_types/drone.png"); + private static final ResourceLocation LASER = ModUtils.loc("textures/screens/damage_types/laser.png"); + private static final ResourceLocation VEHICLE = ModUtils.loc("textures/screens/damage_types/vehicle_strike.png"); + + private static final ResourceLocation WORLD_PEACE_STAFF = ModUtils.loc("textures/gun_icon/compat/world_peace_staff.png"); + + @SubscribeEvent + public static void onRenderGui(RenderGuiEvent.Pre event) { + if (!KillMessageConfig.SHOW_KILL_MESSAGE.get()) { + return; + } + + Player player = Minecraft.getInstance().player; + + if (player == null) { + return; + } + + if (KillMessageHandler.QUEUE.isEmpty()) { + return; + } + + float totalTop = 5; + + var arr = KillMessageHandler.QUEUE.toArray(new PlayerKillRecord[0]); + var record = arr[0]; + + if (record.freeze) { + for (var playerKillRecord : arr) { + playerKillRecord.freeze = false; + } + } + + if (record.tick >= 80) { + if (arr.length > 1 && record.tick - arr[1].tick < (record.fastRemove ? 2 : 20)) { + arr[1].fastRemove = true; + record.fastRemove = true; + for (int j = 1; j < arr.length; j++) { + arr[j].freeze = true; + } + } + } + + for (PlayerKillRecord r : KillMessageHandler.QUEUE) { + totalTop = renderKillMessages(r, event, totalTop); + } + } + + private static float renderKillMessages(PlayerKillRecord record, RenderGuiEvent.Pre event, float baseTop) { + int w = event.getGuiGraphics().guiWidth(); + float top = baseTop; + + Font font = Minecraft.getInstance().font; + + AtomicReference targetName = new AtomicReference<>(record.target.getDisplayName().getString()); + if (record.target instanceof Player targetPlayer) { + CuriosApi.getCuriosInventory(targetPlayer) + .flatMap(c -> c.findFirstCurio(ModItems.DOG_TAG.get())) + .ifPresent(s -> targetName.set(s.stack().getHoverName().getString())); + } + + int targetNameWidth = font.width(targetName.get()); + + var gui = event.getGuiGraphics(); + gui.pose().pushPose(); + + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate( + GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE, + GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE + ); + + // 入场效果 + if (record.tick < 3) { + gui.pose().translate((3 - record.tick - event.getPartialTick().getGameTimeDeltaTicks()) * 33, 0, 0); + } + + // 4s后开始消失 + if (record.tick >= 80) { + int animationTickCount = record.fastRemove ? 2 : 20; + float rate = (float) Math.pow((record.tick + event.getPartialTick().getGameTimeDeltaTicks() - 80) / animationTickCount, 5); + gui.pose().translate(rate * 100, 0, 0); + gui.setColor(1, 1, 1, 1 - rate); + baseTop += 10 * (1 - rate); + } else { + baseTop += 10; + } + + // 击杀提示是右对齐的,这里从右向左渲染 + + // 渲染被击杀者名称 + gui.drawString( + Minecraft.getInstance().font, + targetName.get(), + w - targetNameWidth - 10f, + top, + record.target.getTeamColor(), + false + ); + + // 第一个图标:爆头/爆炸/近战等图标 + int damageTypeIconW = w - targetNameWidth - 28; + + ResourceLocation damageTypeIcon = getDamageTypeIcon(record); + + if (damageTypeIcon != null) { + preciseBlit(gui, + damageTypeIcon, + damageTypeIconW, + top - 2, + 0, + 0, + 12, + 12, + 12, + 12 + ); + } + + Player player = record.attacker; + boolean renderItem = false; + int itemIconW = damageTypeIcon != null ? w - targetNameWidth - 64 : w - targetNameWidth - 46; + + if (player != null && player.getVehicle() instanceof VehicleEntity vehicleEntity) { + // 载具图标 + if ((vehicleEntity instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) || record.damageType == ModDamageTypes.VEHICLE_STRIKE) { + renderItem = true; + + ResourceLocation resourceLocation = vehicleEntity.getVehicleIcon(); + + preciseBlit(gui, + resourceLocation, + itemIconW, + top, + 0, + 0, + 32, + 8, + -32, + 8 + ); + } else { + if (record.stack.getItem() instanceof GunItem gunItem) { + renderItem = true; + + ResourceLocation resourceLocation = gunItem.getGunIcon(); + + preciseBlit(gui, + resourceLocation, + itemIconW, + top, + 0, + 0, + 32, + 8, + -32, + 8 + ); + } + } + } else { + // 如果是枪械击杀,则渲染枪械图标 + if (record.stack.getItem() instanceof GunItem gunItem) { + renderItem = true; + + ResourceLocation resourceLocation = gunItem.getGunIcon(); + + preciseBlit(gui, + resourceLocation, + itemIconW, + top, + 0, + 0, + 32, + 8, + -32, + 8 + ); + } + + // TODO 如果是特殊武器击杀,则渲染对应图标 + if (record.stack.getItem().getDescriptionId().equals("item.dreamaticvoyage.world_peace_staff")) { + renderItem = true; + + preciseBlit(gui, + WORLD_PEACE_STAFF, + itemIconW, + top, + 0, + 0, + 32, + 8, + 32, + 8 + ); + } + } + + // 渲染击杀者名称 + AtomicReference attackerName = new AtomicReference<>(record.attacker.getDisplayName().getString()); + CuriosApi.getCuriosInventory(record.attacker) + .flatMap(c -> c.findFirstCurio(ModItems.DOG_TAG.get())) + .ifPresent(s -> attackerName.set(s.stack().getHoverName().getString())); + + int attackerNameWidth = font.width(attackerName.get()); + int nameW = w - targetNameWidth - 16 - attackerNameWidth; + if (renderItem) { + nameW -= 32; + } + if (damageTypeIcon != null) { + nameW -= 18; + } + + gui.drawString( + Minecraft.getInstance().font, + attackerName.get(), + nameW, + top, + record.attacker.getTeamColor(), + false + ); + + RenderSystem.defaultBlendFunc(); + RenderSystem.disableBlend(); + RenderSystem.depthMask(true); + RenderSystem.enableDepthTest(); + + gui.setColor(1, 1, 1, 1); + gui.pose().popPose(); + + return baseTop; + } + + @Nullable + private static ResourceLocation getDamageTypeIcon(PlayerKillRecord record) { + ResourceLocation icon; + // 渲染爆头图标 + if (record.headshot) { + icon = HEADSHOT; + } else { + if (DamageTypeTool.isGunDamage(record.damageType)) { + icon = null; + } else { + // 如果是其他伤害,则渲染对应图标 + if (record.damageType == DamageTypes.EXPLOSION || record.damageType == DamageTypes.PLAYER_EXPLOSION || record.damageType == ModDamageTypes.PROJECTILE_BOOM || record.damageType == DamageTypes.FIREWORKS) { + icon = EXPLOSION; + } else if (record.damageType == DamageTypes.PLAYER_ATTACK) { + icon = KNIFE; + } else if (record.damageType == ModDamageTypes.BEAST) { + icon = BEAST; + } else if (record.damageType == ModDamageTypes.MINE) { + icon = CLAYMORE; + } else if (record.damageType == ResourceKey.create(Registries.DAMAGE_TYPE, ResourceLocation.fromNamespaceAndPath("dreamaticvoyage", "bleeding"))) { + icon = BLEEDING; + } else if (record.damageType == ResourceKey.create(Registries.DAMAGE_TYPE, ResourceLocation.fromNamespaceAndPath("dreamaticvoyage", "blood_crystal"))) { + icon = BLOOD_CRYSTAL; + } else if (record.damageType == ModDamageTypes.SHOCK) { + icon = SHOCK; + } else if (record.damageType == ModDamageTypes.BURN || record.damageType == DamageTypes.IN_FIRE || record.damageType == DamageTypes.ON_FIRE || record.damageType == DamageTypes.LAVA) { + icon = BURN; + } else if (record.damageType == ModDamageTypes.DRONE_HIT) { + icon = DRONE; + } else if (record.damageType == ModDamageTypes.LASER || record.damageType == ModDamageTypes.LASER_HEADSHOT || record.damageType == ModDamageTypes.LASER_STATIC) { + icon = LASER; + } else if (record.damageType == ModDamageTypes.VEHICLE_STRIKE) { + icon = VEHICLE; + } else { + icon = GENERIC; + } + } + } + return icon; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/MortarInfoOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/MortarInfoOverlay.java new file mode 100644 index 000000000..82e22d1db --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/MortarInfoOverlay.java @@ -0,0 +1,40 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.client.gui.RangeHelper; +import com.atsuishio.superbwarfare.entity.MortarEntity; +import com.atsuishio.superbwarfare.tools.FormatTool; +import com.atsuishio.superbwarfare.tools.TraceTool; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +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(value = Dist.CLIENT) +public class MortarInfoOverlay { + + @SubscribeEvent + public static void eventHandler(RenderGuiEvent.Pre event) { + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + Player player = Minecraft.getInstance().player; + Entity lookingEntity = null; + if (player != null) { + lookingEntity = TraceTool.findLookingEntity(player, 6); + } + if (lookingEntity instanceof MortarEntity mortar) { + event.getGuiGraphics().drawString(Minecraft.getInstance().font, Component.translatable("tips.superbwarfare.mortar.pitch") + .append(Component.literal(FormatTool.format1D(-mortar.getXRot(), "°"))), + w / 2 - 90, h / 2 - 26, -1, false); + event.getGuiGraphics().drawString(Minecraft.getInstance().font, Component.translatable("tips.superbwarfare.mortar.yaw") + .append(Component.literal(FormatTool.format1D(mortar.getYRot(), "°"))), + w / 2 - 90, h / 2 - 16, -1, false); + event.getGuiGraphics().drawString(Minecraft.getInstance().font, Component.translatable("tips.superbwarfare.mortar.range") + .append(Component.literal(FormatTool.format1D((int) RangeHelper.getRange(-mortar.getXRot()), "m"))), + w / 2 - 90, h / 2 - 6, -1, false); + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/RedTriangleOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/RedTriangleOverlay.java new file mode 100644 index 000000000..3c3acbbeb --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/RedTriangleOverlay.java @@ -0,0 +1,62 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.client.RenderHelper; +import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.tools.SeekTool; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; +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(value = Dist.CLIENT) +public class RedTriangleOverlay { + + private static final ResourceLocation TRIANGLE = ModUtils.loc("textures/screens/red_triangle.png"); + + @SubscribeEvent + public static void eventHandler(RenderGuiEvent.Pre event) { + Minecraft mc = Minecraft.getInstance(); + PoseStack poseStack = event.getGuiGraphics().pose(); + + Player player = mc.player; + if (player == null) return; + + ItemStack stack = player.getMainHandItem(); + if (!stack.is(ModItems.RPG.get())) return; + if (player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) + return; + + Entity idf = SeekTool.seekLivingEntity(player, player.level(), 128, 6); + if (idf == null) return; + Vec3 playerVec = new Vec3(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.xo, player.getX()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.yo + player.getEyeHeight(), player.getEyeY()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.zo, player.getZ())); + double distance = idf.position().distanceTo(playerVec); + Vec3 pos = new Vec3(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), idf.xo, idf.getX()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), idf.yo + idf.getEyeHeight() + 0.5 + 0.07 * distance, idf.getEyeY() + 0.5 + 0.07 * distance), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), idf.zo, idf.getZ())); + Vec3 point = RenderHelper.worldToScreen(pos, playerVec); + if (point == null) return; + + poseStack.pushPose(); + float x = (float) point.x; + float y = (float) point.y; + + RenderHelper.preciseBlit(event.getGuiGraphics(), TRIANGLE, x - 4, y - 4, 0, 0, 8, 8, 8, 8, -65536); + + RenderSystem.depthMask(true); + RenderSystem.defaultBlendFunc(); + RenderSystem.enableDepthTest(); + RenderSystem.disableBlend(); + RenderSystem.setShaderColor(1, 1, 1, 1); + + poseStack.popPose(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/SpyglassRangeOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/SpyglassRangeOverlay.java new file mode 100644 index 000000000..d68dc3362 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/SpyglassRangeOverlay.java @@ -0,0 +1,59 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.tools.FormatTool; +import com.atsuishio.superbwarfare.tools.TraceTool; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +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(value = Dist.CLIENT) +public class SpyglassRangeOverlay { + + @SubscribeEvent + public static void eventHandler(RenderGuiEvent.Pre event) { + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + Player player = Minecraft.getInstance().player; + if (player != null && (player.getMainHandItem().getItem() == Items.SPYGLASS || player.getOffhandItem().getItem() == Items.SPYGLASS) && player.isUsingItem()) { + boolean lookAtEntity = false; + + BlockHitResult result = player.level().clip(new ClipContext(player.getEyePosition(), player.getEyePosition().add(player.getViewVector(1).scale(512)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)); + Vec3 hitPos = result.getLocation(); + + double blockRange = player.getEyePosition(1).distanceTo(hitPos); + + double entityRange = 0; + Entity lookingEntity = TraceTool.findLookingEntity(player, 520); + + if (lookingEntity != null) { + lookAtEntity = true; + entityRange = player.distanceTo(lookingEntity); + } + + if (lookAtEntity) { + event.getGuiGraphics().drawString(Minecraft.getInstance().font, Component.translatable("tips.superbwarfare.drone.range") + .append(Component.literal(FormatTool.format1D(entityRange, "M ") + lookingEntity.getDisplayName().getString())), + w / 2 + 12, h / 2 - 28, -1, false); + } else { + if (blockRange > 500) { + event.getGuiGraphics().drawString(Minecraft.getInstance().font, Component.translatable("tips.superbwarfare.drone.range") + .append(Component.literal("---M")), w / 2 + 12, h / 2 - 28, -1, false); + } else { + event.getGuiGraphics().drawString(Minecraft.getInstance().font, Component.translatable("tips.superbwarfare.drone.range") + .append(Component.literal(FormatTool.format1D(blockRange, "M"))), + w / 2 + 12, h / 2 - 28, -1, false); + } + } + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleHudOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleHudOverlay.java new file mode 100644 index 000000000..58fc35ebc --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleHudOverlay.java @@ -0,0 +1,584 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.client.RenderHelper; +import com.atsuishio.superbwarfare.config.client.DisplayConfig; +import com.atsuishio.superbwarfare.entity.vehicle.Bmp2Entity; +import com.atsuishio.superbwarfare.entity.vehicle.Lav150Entity; +import com.atsuishio.superbwarfare.entity.vehicle.SpeedboatEntity; +import com.atsuishio.superbwarfare.entity.vehicle.Yx100Entity; +import com.atsuishio.superbwarfare.entity.vehicle.base.*; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.HeliRocketWeapon; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.LaserWeapon; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.tools.FormatTool; +import com.atsuishio.superbwarfare.tools.InventoryTool; +import com.atsuishio.superbwarfare.tools.NBTTool; +import com.atsuishio.superbwarfare.tools.SeekTool; +import com.atsuishio.superbwarfare.tools.animation.AnimationCurves; +import com.atsuishio.superbwarfare.tools.animation.AnimationTimer; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import net.minecraft.client.Camera; +import net.minecraft.client.CameraType; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RenderGuiEvent; +import org.joml.Math; +import top.theillusivec4.curios.api.CuriosApi; + +import java.util.concurrent.atomic.AtomicReference; + +import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; +import static com.atsuishio.superbwarfare.client.overlay.CrossHairOverlay.*; +import static com.atsuishio.superbwarfare.entity.vehicle.Bmp2Entity.LOADED_MISSILE; +import static com.atsuishio.superbwarfare.entity.vehicle.Bmp2Entity.MISSILE_COUNT; +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.*; + +@EventBusSubscriber(value = Dist.CLIENT) +public class VehicleHudOverlay { + + private static float scopeScale = 1; + private static final ResourceLocation FRAME = ModUtils.loc("textures/screens/land/tv_frame.png"); + private static final ResourceLocation ARMOR = ModUtils.loc("textures/screens/armor.png"); + private static final ResourceLocation ENERGY = ModUtils.loc("textures/screens/energy.png"); + private static final ResourceLocation HEALTH = ModUtils.loc("textures/screens/armor_value.png"); + private static final ResourceLocation HEALTH_FRAME = ModUtils.loc("textures/screens/armor_value_frame.png"); + private static final ResourceLocation DRIVER = ModUtils.loc("textures/screens/driver.png"); + private static final ResourceLocation PASSENGER = ModUtils.loc("textures/screens/passenger.png"); + private static final ResourceLocation SELECTED = ModUtils.loc("textures/screens/vehicle_weapon/selected.png"); + private static final ResourceLocation NUMBER = ModUtils.loc("textures/screens/vehicle_weapon/number.png"); + + public static final int ANIMATION_TIME = 300; + private static final AnimationTimer[] weaponSlotsTimer = AnimationTimer.createTimers(9, ANIMATION_TIME, AnimationCurves.EASE_OUT_CIRC); + private static boolean wasRenderingWeapons = false; + private static int oldWeaponIndex = 0; + private static int oldRenderWeaponIndex = 0; + private static final AnimationTimer weaponIndexUpdateTimer = new AnimationTimer(ANIMATION_TIME).animation(AnimationCurves.EASE_OUT_CIRC); + + + @SubscribeEvent(priority = EventPriority.HIGH) + public static void eventHandler(RenderGuiEvent.Pre event) { + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + Player player = Minecraft.getInstance().player; + + if (!shouldRenderHud(player)) { + wasRenderingWeapons = false; + return; + } + + Entity vehicle = player.getVehicle(); + + GuiGraphics guiGraphics = event.getGuiGraphics(); + PoseStack poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + RenderSystem.setShaderColor(1, 1, 1, 1); + + // 渲染地面武装HUD + renderLandArmorHud(event, w, h); + + int compatHeight = getArmorPlateCompatHeight(player); + + if (vehicle instanceof EnergyVehicleEntity energyVehicleEntity) { + float energy = energyVehicleEntity.getEnergy(); + float maxEnergy = energyVehicleEntity.getMaxEnergy(); + preciseBlit(guiGraphics, ENERGY, 10, h - 22 - compatHeight, 100, 0, 0, 8, 8, 8, 8); + preciseBlit(guiGraphics, HEALTH_FRAME, 20, h - 21 - compatHeight, 100, 0, 0, 60, 6, 60, 6); + preciseBlit(guiGraphics, HEALTH, 20, h - 21 - compatHeight, 100, 0, 0, (int) (60 * energy / maxEnergy), 6, 60, 6); + } + + if (vehicle instanceof VehicleEntity pVehicle) { + float health = pVehicle.getHealth(); + float maxHealth = pVehicle.getMaxHealth(); + preciseBlit(guiGraphics, ARMOR, 10, h - 13 - compatHeight, 100, 0, 0, 8, 8, 8, 8); + preciseBlit(guiGraphics, HEALTH_FRAME, 20, h - 12 - compatHeight, 100, 0, 0, 60, 6, 60, 6); + preciseBlit(guiGraphics, HEALTH, 20, h - 12 - compatHeight, 100, 0, 0, (int) (60 * health / maxHealth), 6, 60, 6); + + renderWeaponInfo(guiGraphics, pVehicle, w, h); + renderPassengerInfo(guiGraphics, pVehicle, w, h); + } + + poseStack.popPose(); + } + + private static boolean shouldRenderHud(Player player) { + if (player == null) return false; + return !player.isSpectator() && (player.getVehicle() != null && player.getVehicle() instanceof VehicleEntity); + } + + private static int getArmorPlateCompatHeight(Player player) { + ItemStack stack = player.getItemBySlot(EquipmentSlot.CHEST); + if (stack == ItemStack.EMPTY) return 0; + if (!NBTTool.getTag(stack).contains("ArmorPlate")) return 0; + if (!DisplayConfig.ARMOR_PLATE_HUD.get()) return 0; + return 9; + } + + public static void renderLandArmorHud(RenderGuiEvent.Pre event, int w, int h) { + Minecraft mc = Minecraft.getInstance(); + Player player = mc.player; + GuiGraphics guiGraphics = event.getGuiGraphics(); + PoseStack poseStack = guiGraphics.pose(); + Camera camera = mc.gameRenderer.getMainCamera(); + Vec3 cameraPos = camera.getPosition(); + + assert player != null; + + if (player.getVehicle() instanceof LandArmorEntity iLand && iLand.isDriver(player) + && iLand instanceof WeaponVehicleEntity weaponVehicle + && iLand instanceof MobileVehicleEntity mobileVehicle + && !(player.getVehicle() instanceof SpeedboatEntity)) { + poseStack.pushPose(); + + poseStack.translate(0.2 * ClientEventHandler.shakeTime + 5 * ClientEventHandler.cameraRoll, 0 - 0.3 * ClientEventHandler.shakeTime + 5 * ClientEventHandler.cameraRoll, 0); + poseStack.rotateAround(Axis.ZP.rotationDegrees(-0.5f * ClientEventHandler.cameraRoll), w / 2f, h / 2f, 0); + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + RenderSystem.setShaderColor(1, 1, 1, 1); + + scopeScale = Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), scopeScale, 1F); + float f = (float) Math.min(w, h); + float f1 = Math.min((float) w / f, (float) h / f) * scopeScale; + float i = Mth.floor(f * f1); + float j = Mth.floor(f * f1); + float k = ((w - i) / 2); + float l = ((h - j) / 2); + + if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON || ClientEventHandler.zoomVehicle) { + int addW = (w / h) * 48; + int addH = (w / h) * 27; + preciseBlit(guiGraphics, FRAME, (float) -addW / 2, (float) -addH / 2, 10, 0, 0.0F, w + addW, h + addH, w + addW, h + addH); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/land/line.png"), w / 2f - 64, h - 56, 0, 0.0F, 128, 1, 128, 1); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/land/line.png"), w / 2f + 112, h - 71, 0, 0.0F, 1, 16, 1, 16); + + // 不同武器种类的准星 + if (weaponVehicle instanceof Yx100Entity) { + if (weaponVehicle.getWeaponIndex(0) == 0) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/land/tank_cannon_cross_ap.png"), k, l, 0, 0.0F, i, j, i, j); + } else if (weaponVehicle.getWeaponIndex(0) == 1) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/land/tank_cannon_cross_he.png"), k, l, 0, 0.0F, i, j, i, j); + } + + } else { + if (weaponVehicle.getWeaponIndex(0) == 0) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/land/lav_cannon_cross.png"), k, l, 0, 0.0F, i, j, i, j); + } else if (weaponVehicle.getWeaponIndex(0) == 1) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/land/lav_gun_cross.png"), k, l, 0, 0.0F, i, j, i, j); + } else if (weaponVehicle.getWeaponIndex(0) == 2) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/land/lav_missile_cross.png"), k, l, 0, 0.0F, i, j, i, j); + } + } + + // 指南针 + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/compass.png"), (float) w / 2 - 128, (float) 10, 128 + ((float) 64 / 45 * player.getYRot()), 0, 256, 16, 512, 16); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/helicopter/roll_ind.png"), w / 2f - 8, 30, 0, 0.0F, 16, 16, 16, 16); + + // 炮塔方向 + poseStack.pushPose(); + poseStack.rotateAround(Axis.ZP.rotationDegrees(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), iLand.turretYRotO(), iLand.turretYRot())), w / 2f + 112, h - 56, 0); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/land/body.png"), w / 2f + 96, h - 72, 0, 0.0F, 32, 32, 32, 32); + poseStack.popPose(); + + // 时速 + guiGraphics.drawString(mc.font, Component.literal(FormatTool.format0D(mobileVehicle.getDeltaMovement().length() * 72, " km/h")), + w / 2 + 160, h / 2 - 48, 0x66FF00, false); + + // 低电量警告 + if (mobileVehicle.getEnergy() < 0.02 * mobileVehicle.getMaxEnergy()) { + guiGraphics.drawString(mc.font, Component.literal("NO POWER!"), + w / 2 - 144, h / 2 + 14, -65536, false); + } else if (mobileVehicle.getEnergy() < 0.2 * mobileVehicle.getMaxEnergy()) { + guiGraphics.drawString(mc.font, Component.literal("LOW POWER"), + w / 2 - 144, h / 2 + 14, 0xFF6B00, false); + } + + // 测距 + boolean lookAtEntity = false; + + BlockHitResult result = player.level().clip(new ClipContext(player.getEyePosition(), player.getEyePosition().add(player.getViewVector(1).scale(512)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)); + Vec3 hitPos = result.getLocation(); + + double blockRange = player.getEyePosition(1).distanceTo(hitPos); + + double entityRange = 0; + + Entity lookingEntity = SeekTool.seekLivingEntity(player, player.level(), 512, 1); + if (lookingEntity != null) { + lookAtEntity = true; + entityRange = player.distanceTo(lookingEntity); + } + + if (lookAtEntity) { + guiGraphics.drawString(mc.font, Component.literal(FormatTool.format1D(entityRange, "m")), + w / 2 - 6, h - 53, 0x66FF00, false); + } else { + if (blockRange > 500) { + guiGraphics.drawString(mc.font, Component.literal("---m"), w / 2 - 6, h - 53, 0x66FF00, false); + } else { + guiGraphics.drawString(mc.font, Component.literal(FormatTool.format1D(blockRange, "m")), + w / 2 - 6, h - 53, 0x66FF00, false); + } + } + + // 武器名称 + // LAV-150 + if (player.getVehicle() instanceof Lav150Entity lav) { + if (weaponVehicle.getWeaponIndex(0) == 0) { + double heat = 1 - lav.getEntityData().get(HEAT) / 100.0F; + guiGraphics.drawString(mc.font, Component.literal("20MM CANNON " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : lav.getAmmoCount(player))), w / 2 - 33, h - 65, Mth.hsvToRgb((float) heat / 3.745318352059925F, 1.0F, 1.0F), false); + } else { + double heat = 1 - lav.getEntityData().get(COAX_HEAT) / 100.0F; + guiGraphics.drawString(mc.font, Component.literal("7.62MM COAX " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : lav.getAmmoCount(player))), w / 2 - 33, h - 65, Mth.hsvToRgb((float) heat / 3.745318352059925F, 1.0F, 1.0F), false); + } + } + + // BMP-2 + if (player.getVehicle() instanceof Bmp2Entity bmp2) { + if (weaponVehicle.getWeaponIndex(0) == 0) { + double heat = 1 - bmp2.getEntityData().get(HEAT) / 100.0F; + guiGraphics.drawString(mc.font, Component.literal(" 30MM 2A42 " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : bmp2.getAmmoCount(player))), w / 2 - 33, h - 65, Mth.hsvToRgb((float) heat / 3.745318352059925F, 1.0F, 1.0F), false); + } else if (weaponVehicle.getWeaponIndex(0) == 1) { + double heat = 1 - bmp2.getEntityData().get(COAX_HEAT) / 100.0F; + guiGraphics.drawString(mc.font, Component.literal(" 7.62MM ПКТ " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : bmp2.getAmmoCount(player))), w / 2 - 33, h - 65, Mth.hsvToRgb((float) heat / 3.745318352059925F, 1.0F, 1.0F), false); + } else { + guiGraphics.drawString(mc.font, Component.literal(" 9M113 " + bmp2.getEntityData().get(LOADED_MISSILE) + " " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : bmp2.getEntityData().get(MISSILE_COUNT))), w / 2 - 33, h - 65, 0x66FF00, false); + } + + } + + // YX-100 + if (player.getVehicle() instanceof Yx100Entity yx100) { + if (weaponVehicle.getWeaponIndex(0) == 0) { + guiGraphics.drawString(mc.font, Component.literal("AP SHELL " + yx100.getAmmoCount(player) + " " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getEntityData().get(AMMO))), w / 2 - 33, h - 65, 0x66FF00, false); + } else if (weaponVehicle.getWeaponIndex(0) == 1) { + guiGraphics.drawString(mc.font, Component.literal("HE SHELL " + yx100.getAmmoCount(player) + " " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getEntityData().get(AMMO))), w / 2 - 33, h - 65, 0x66FF00, false); + } else if (weaponVehicle.getWeaponIndex(0) == 2) { + double heat = 1 - yx100.getEntityData().get(COAX_HEAT) / 100.0F; + guiGraphics.drawString(mc.font, Component.literal(" 12.7MM HMG " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getAmmoCount(player))), w / 2 - 33, h - 65, Mth.hsvToRgb((float) heat / 3.745318352059925F, 1.0F, 1.0F), false); + } + } + + // 血量 + double heal = mobileVehicle.getHealth() / mobileVehicle.getMaxHealth(); + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal(FormatTool.format0D(100 * heal)), w / 2 - 165, h / 2 - 46, Mth.hsvToRgb((float) heal / 3.745318352059925F, 1.0F, 1.0F), false); + + renderKillIndicator(guiGraphics, w, h); + } else if (Minecraft.getInstance().options.getCameraType() == CameraType.THIRD_PERSON_BACK && !ClientEventHandler.zoomVehicle) { + Vec3 p = RenderHelper.worldToScreen(new Vec3(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.xo, player.getX()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.yo + player.getEyeHeight(), player.getEyeY()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.zo, player.getZ())).add(iLand.getBarrelVec(event.getPartialTick().getGameTimeDeltaTicks()).scale(192)), cameraPos); + // 第三人称准星 + if (p != null) { + poseStack.pushPose(); + float x = (float) p.x; + float y = (float) p.y; + + poseStack.pushPose(); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/drone.png"), x - 12, y - 12, 0, 0, 24, 24, 24, 24); + renderKillIndicator3P(guiGraphics, x - 7.5f + (float) (2 * (Math.random() - 0.5f)), y - 7.5f + (float) (2 * (Math.random() - 0.5f))); + + poseStack.pushPose(); + + poseStack.translate(x, y, 0); + poseStack.scale(0.75f, 0.75f, 1); + + // LAV-150 + if (weaponVehicle instanceof Lav150Entity lav1501) { + if (weaponVehicle.getWeaponIndex(0) == 0) { + double heat = lav1501.getEntityData().get(HEAT) / 100.0F; + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("20MM CANNON " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : lav1501.getAmmoCount(player))), 30, -9, Mth.hsvToRgb(0F, (float) heat, 1.0F), false); + } else { + double heat2 = lav1501.getEntityData().get(COAX_HEAT) / 100.0F; + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("7.62MM COAX " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : lav1501.getAmmoCount(player))), 30, -9, Mth.hsvToRgb(0F, (float) heat2, 1.0F), false); + } + } + // BMP-2 + if (weaponVehicle instanceof Bmp2Entity bmp201) { + if (weaponVehicle.getWeaponIndex(0) == 0) { + double heat = bmp201.getEntityData().get(HEAT) / 100.0F; + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("30MM 2A42 " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : bmp201.getAmmoCount(player))), 30, -9, Mth.hsvToRgb(0F, (float) heat, 1.0F), false); + } else if (weaponVehicle.getWeaponIndex(0) == 1) { + double heat2 = bmp201.getEntityData().get(COAX_HEAT) / 100.0F; + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("7.62MM ПКТ " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : bmp201.getAmmoCount(player))), 30, -9, Mth.hsvToRgb(0F, (float) heat2, 1.0F), false); + } else { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("9M113 " + bmp201.getEntityData().get(LOADED_MISSILE) + " " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : bmp201.getEntityData().get(MISSILE_COUNT))), 30, -9, -1, false); + } + } + // YX-100 + if (weaponVehicle instanceof Yx100Entity yx100) { + if (weaponVehicle.getWeaponIndex(0) == 0) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("AP SHELL " + yx100.getAmmoCount(player) + " " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getEntityData().get(AMMO))), 30, -9, -1, false); + } else if (weaponVehicle.getWeaponIndex(0) == 1) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("HE SHELL " + yx100.getAmmoCount(player) + " " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getEntityData().get(AMMO))), 30, -9, -1, false); + } else if (weaponVehicle.getWeaponIndex(0) == 2) { + double heat2 = yx100.getEntityData().get(COAX_HEAT) / 100.0F; + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("7.62MM ПКТ " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getAmmoCount(player))), 30, -9, Mth.hsvToRgb(0F, (float) heat2, 1.0F), false); + } + } + + double heal = 1 - mobileVehicle.getHealth() / mobileVehicle.getMaxHealth(); + + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("HP " + + FormatTool.format0D(100 * mobileVehicle.getHealth() / mobileVehicle.getMaxHealth())), 30, 1, Mth.hsvToRgb(0F, (float) heal, 1.0F), false); + + poseStack.popPose(); + poseStack.popPose(); + poseStack.popPose(); + } + } + poseStack.popPose(); + } else { + scopeScale = 0.7f; + } + } + + public static void renderKillIndicator(GuiGraphics guiGraphics, float w, float h) { + float posX = w / 2f - 7.5f + (float) (2 * (Math.random() - 0.5f)); + float posY = h / 2f - 7.5f + (float) (2 * (Math.random() - 0.5f)); + float rate = (40 - KILL_INDICATOR * 5) / 5.5f; + + if (HIT_INDICATOR > 0) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/hit_marker.png"), posX, posY, 0, 0, 16, 16, 16, 16); + } + + if (VEHICLE_INDICATOR > 0) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/hit_marker_vehicle.png"), posX, posY, 0, 0, 16, 16, 16, 16); + } + + if (HEAD_INDICATOR > 0) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/headshot_mark.png"), posX, posY, 0, 0, 16, 16, 16, 16); + } + + if (KILL_INDICATOR > 0) { + float posX1 = w / 2f - 7.5f - 2 + rate; + float posY1 = h / 2f - 7.5f - 2 + rate; + float posX2 = w / 2f - 7.5f + 2 - rate; + float posY2 = h / 2f - 7.5f + 2 - rate; + + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/kill_mark1.png"), posX1, posY1, 0, 0, 16, 16, 16, 16); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/kill_mark2.png"), posX2, posY1, 0, 0, 16, 16, 16, 16); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/kill_mark3.png"), posX1, posY2, 0, 0, 16, 16, 16, 16); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/kill_mark4.png"), posX2, posY2, 0, 0, 16, 16, 16, 16); + } + } + + public static void renderKillIndicator3P(GuiGraphics guiGraphics, float posX, float posY) { + float rate = (40 - KILL_INDICATOR * 5) / 5.5f; + + if (HIT_INDICATOR > 0) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/hit_marker.png"), posX, posY, 0, 0, 16, 16, 16, 16); + } + + if (VEHICLE_INDICATOR > 0) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/hit_marker_vehicle.png"), posX, posY, 0, 0, 16, 16, 16, 16); + } + + if (HEAD_INDICATOR > 0) { + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/headshot_mark.png"), posX, posY, 0, 0, 16, 16, 16, 16); + } + + if (KILL_INDICATOR > 0) { + float posX1 = posX - 2 + rate; + float posY1 = posY - 2 + rate; + float posX2 = posX + 2 - rate; + float posY2 = posY + 2 - rate; + + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/kill_mark1.png"), posX1, posY1, 0, 0, 16, 16, 16, 16); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/kill_mark2.png"), posX2, posY1, 0, 0, 16, 16, 16, 16); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/kill_mark3.png"), posX1, posY2, 0, 0, 16, 16, 16, 16); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/kill_mark4.png"), posX2, posY2, 0, 0, 16, 16, 16, 16); + } + } + + private static void renderPassengerInfo(GuiGraphics guiGraphics, VehicleEntity vehicle, int w, int h) { + var passengers = vehicle.getOrderedPassengers(); + + int index = 0; + for (int i = passengers.size() - 1; i >= 0; i--) { + var passenger = passengers.get(i); + + int y = h - 35 - index * 12; + AtomicReference name = new AtomicReference<>("---"); + + if (passenger != null) { + name.set(passenger.getName().getString()); + } + + if (passenger instanceof Player player) { + CuriosApi.getCuriosInventory(player) + .flatMap(c -> c.findFirstCurio(ModItems.DOG_TAG.get())) + .ifPresent(s -> name.set(s.stack().getHoverName().getString())); + } + + guiGraphics.drawString(Minecraft.getInstance().font, name.get(), 42, y, 0x66ff00, true); + + String num = "[" + (i + 1) + "]"; + guiGraphics.drawString(Minecraft.getInstance().font, num, 25 - Minecraft.getInstance().font.width(num), y, 0x66ff00, true); + + preciseBlit(guiGraphics, index == passengers.size() - 1 ? DRIVER : PASSENGER, 30, y, 100, 0, 0, 8, 8, 8, 8); + index++; + } + } + + private static void renderWeaponInfo(GuiGraphics guiGraphics, VehicleEntity vehicle, int w, int h) { + if (!(vehicle instanceof WeaponVehicleEntity weaponVehicle)) return; + + var temp = wasRenderingWeapons; + wasRenderingWeapons = false; + + Player player = Minecraft.getInstance().player; + assert player != null; + + int index = vehicle.getSeatIndex(player); + if (index == -1) return; + + var weapons = weaponVehicle.getAvailableWeapons(index); + if (weapons.isEmpty()) return; + + int weaponIndex = weaponVehicle.getWeaponIndex(index); + if (weaponIndex == -1) return; + + wasRenderingWeapons = temp; + + var currentTime = System.currentTimeMillis(); + + // 若上一帧未在渲染武器信息,则初始化动画相关变量 + if (!wasRenderingWeapons) { + weaponSlotsTimer[weaponIndex].beginForward(currentTime); + + if (oldWeaponIndex != weaponIndex) { + weaponSlotsTimer[oldWeaponIndex].endBackward(currentTime); + + oldWeaponIndex = weaponIndex; + oldRenderWeaponIndex = weaponIndex; + } + + weaponIndexUpdateTimer.beginForward(currentTime); + } + + // 切换武器时,更新上一个武器槽位和当前武器槽位的动画信息 + if (weaponIndex != oldWeaponIndex) { + weaponSlotsTimer[weaponIndex].forward(currentTime); + weaponSlotsTimer[oldWeaponIndex].backward(currentTime); + + oldRenderWeaponIndex = oldWeaponIndex; + oldWeaponIndex = weaponIndex; + + weaponIndexUpdateTimer.beginForward(currentTime); + } + + var pose = guiGraphics.pose(); + + pose.pushPose(); + + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + RenderSystem.setShaderColor(1, 1, 1, 1); + + int frameIndex = 0; + + for (int i = weapons.size() - 1; i >= 0 && i < 9; i--) { + var weapon = weapons.get(i); + + ResourceLocation frame = ModUtils.loc("textures/screens/vehicle_weapon/frame_" + (i + 1) + ".png"); + pose.pushPose(); + + // 相对于最左边的偏移量 + float xOffset; + // 向右偏移的最长长度 + var maxXOffset = 35; + + var currentSlotTimer = weaponSlotsTimer[i]; + var progress = currentSlotTimer.getProgress(currentTime); + + RenderSystem.setShaderColor(1, 1, 1, Mth.lerp(progress, 0.2f, 1)); + xOffset = Mth.lerp(progress, maxXOffset, 0); + + // 当前选中武器 + if (weaponIndex == i) { + var startY = Mth.lerp(progress, + h - (weapons.size() - 1 - oldRenderWeaponIndex) * 18 - 16, + h - (weapons.size() - 1 - weaponIndex) * 18 - 16 + ); + + preciseBlit(guiGraphics, SELECTED, w - 95, startY, 100, 0, 0, 8, 8, 8, 8); + if (InventoryTool.hasCreativeAmmoBox(player) && !(weapon instanceof LaserWeapon) && !(weapon instanceof HeliRocketWeapon)) { + preciseBlit(guiGraphics, NUMBER, w - 28 + xOffset, h - frameIndex * 18 - 15, 100, 58, 0, 10, 7.5f, 75, 7.5f); + } else { + renderNumber(guiGraphics, weaponVehicle.getAmmoCount(player), weapon instanceof LaserWeapon, + w - 20 + xOffset, h - frameIndex * 18 - 15.5f, 0.25f); + } + } + + preciseBlit(guiGraphics, frame, w - 85 + xOffset, h - frameIndex * 18 - 20, 100, 0, 0, 75, 16, 75, 16); + preciseBlit(guiGraphics, weapon.icon, w - 85 + xOffset, h - frameIndex * 18 - 20, 100, 0, 0, 75, 16, 75, 16); + + pose.popPose(); + + frameIndex++; + } + + RenderSystem.setShaderColor(1, 1, 1, 1); + pose.popPose(); + + // 切换武器光标动画播放结束后,更新上次选择槽位 + if (oldWeaponIndex != oldRenderWeaponIndex && weaponIndexUpdateTimer.finished(currentTime)) { + oldRenderWeaponIndex = oldWeaponIndex; + } + wasRenderingWeapons = true; + } + + private static void renderNumber(GuiGraphics guiGraphics, int number, boolean percent, float x, float y, float scale) { + float pX = x; + if (percent) { + pX -= 32 * scale; + preciseBlit(guiGraphics, NUMBER, pX + 20 * scale, y, 100, + 200 * scale, 0, 32 * scale, 30 * scale, 300 * scale, 30 * scale); + } + + int index = 0; + if (number == 0) { + preciseBlit(guiGraphics, NUMBER, pX, y, 100, + 0, 0, 20 * scale, 30 * scale, 300 * scale, 30 * scale); + } + + while (number > 0) { + int digit = number % 10; + preciseBlit(guiGraphics, NUMBER, pX - index * 20 * scale, y, 100, + digit * 20 * scale, 0, 20 * scale, 30 * scale, 300 * scale, 30 * scale); + number /= 10; + index++; + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleMgHudOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleMgHudOverlay.java new file mode 100644 index 000000000..fd54dae68 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleMgHudOverlay.java @@ -0,0 +1,125 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.client.RenderHelper; +import com.atsuishio.superbwarfare.entity.vehicle.SpeedboatEntity; +import com.atsuishio.superbwarfare.entity.vehicle.Yx100Entity; +import com.atsuishio.superbwarfare.entity.vehicle.base.LandArmorEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.WeaponVehicleEntity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.tools.FormatTool; +import com.atsuishio.superbwarfare.tools.InventoryTool; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Camera; +import net.minecraft.client.CameraType; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; +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; +import org.joml.Math; + +import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; +import static com.atsuishio.superbwarfare.client.overlay.VehicleHudOverlay.renderKillIndicator3P; +import static com.atsuishio.superbwarfare.entity.vehicle.Yx100Entity.MG_AMMO; +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.AMMO; +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.HEAT; + +@EventBusSubscriber(value = Dist.CLIENT) +public class VehicleMgHudOverlay { + + @SubscribeEvent + public static void eventHandler(RenderGuiEvent.Pre event) { + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + Minecraft mc = Minecraft.getInstance(); + Player player = mc.player; + GuiGraphics guiGraphics = event.getGuiGraphics(); + PoseStack poseStack = guiGraphics.pose(); + Camera camera = mc.gameRenderer.getMainCamera(); + Vec3 cameraPos = camera.getPosition(); + + if (!shouldRenderCrossHair(player)) return; + + Entity cannon = player.getVehicle(); + if (cannon == null) return; + + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + RenderSystem.setShaderColor(1, 1, 1, 1); + + if (player.getVehicle() instanceof LandArmorEntity iLand && iLand instanceof WeaponVehicleEntity weaponVehicle && iLand instanceof MobileVehicleEntity mobileVehicle && weaponVehicle.hasWeapon(mobileVehicle.getSeatIndex(player))) { + if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON || ClientEventHandler.zoomVehicle) { + float fovAdjust = (float) 70 / Minecraft.getInstance().options.fov().get(); + + float f = (float) Math.min(w, h); + float f1 = Math.min((float) w / f, (float) h / f) * fovAdjust; + int i = Mth.floor(f * f1); + int j = Mth.floor(f * f1); + int k = (w - i) / 2; + int l = (h - j) / 2; + RenderHelper.preciseBlit(guiGraphics, ModUtils.loc("textures/screens/cannon/cannon_crosshair_notzoom.png"), k, l, 0, 0.0F, i, j, i, j); + VehicleHudOverlay.renderKillIndicator(guiGraphics, w, h); + } else if (Minecraft.getInstance().options.getCameraType() == CameraType.THIRD_PERSON_BACK && !ClientEventHandler.zoomVehicle) { + Vec3 p = RenderHelper.worldToScreen(new Vec3(Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.xo, player.getX()), Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.yo + player.getEyeHeight(), player.getEyeY()), + Mth.lerp(event.getPartialTick().getGameTimeDeltaTicks(), player.zo, player.getZ())).add(iLand.getGunVec(event.getPartialTick().getGameTimeDeltaTicks()).scale(192)), cameraPos); + + // 第三人称准星 + if (p != null) { + poseStack.pushPose(); + float x = (float) p.x; + float y = (float) p.y; + + poseStack.pushPose(); + preciseBlit(guiGraphics, ModUtils.loc("textures/screens/drone.png"), x - 12, y - 12, 0, 0, 24, 24, 24, 24); + renderKillIndicator3P(guiGraphics, x - 7.5f + (float) (2 * (Math.random() - 0.5f)), y - 7.5f + (float) (2 * (Math.random() - 0.5f))); + + poseStack.pushPose(); + + poseStack.translate(x, y, 0); + poseStack.scale(0.75f, 0.75f, 1); + + // YX-100 + if (player.getVehicle() instanceof Yx100Entity yx100) { + double heat = yx100.getEntityData().get(HEAT) / 100.0F; + guiGraphics.drawString(mc.font, Component.literal(".50 HMG " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getEntityData().get(MG_AMMO))), 30, -9, Mth.hsvToRgb(0F, (float) heat, 1.0F), false); + } + + // 快艇 + if (player.getVehicle() instanceof SpeedboatEntity speedboat) { + double heat = speedboat.getEntityData().get(HEAT) / 100.0F; + guiGraphics.drawString(mc.font, Component.literal(".50 HMG " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : speedboat.getEntityData().get(AMMO))), 30, -9, Mth.hsvToRgb(0F, (float) heat, 1.0F), false); + } + + double heal = 1 - mobileVehicle.getHealth() / mobileVehicle.getMaxHealth(); + + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("HP " + + FormatTool.format0D(100 * mobileVehicle.getHealth() / mobileVehicle.getMaxHealth())), 30, 1, Mth.hsvToRgb(0F, (float) heal, 1.0F), false); + + poseStack.popPose(); + poseStack.popPose(); + poseStack.popPose(); + } + } + } + } + + private static boolean shouldRenderCrossHair(Player player) { + if (player == null) return false; + return !player.isSpectator() + && (player.getVehicle() instanceof SpeedboatEntity || (player.getVehicle() instanceof Yx100Entity yx100 && yx100.getNthEntity(1) == player)); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleTeamOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleTeamOverlay.java new file mode 100644 index 000000000..89b37329f --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleTeamOverlay.java @@ -0,0 +1,55 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.tools.FormatTool; +import com.atsuishio.superbwarfare.tools.TraceTool; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +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(value = Dist.CLIENT) +public class VehicleTeamOverlay { + + @SubscribeEvent + public static void eventHandler(RenderGuiEvent.Pre event) { + int w = event.getGuiGraphics().guiWidth(); + int h = event.getGuiGraphics().guiHeight(); + Player player = Minecraft.getInstance().player; + PoseStack poseStack = event.getGuiGraphics().pose(); + if (player == null) return; + + boolean lookAtEntity = false; + + double entityRange = 0; + Entity lookingEntity = TraceTool.findLookingEntity(player, 520); + + if (lookingEntity instanceof VehicleEntity) { + lookAtEntity = true; + entityRange = player.distanceTo(lookingEntity); + } + + if (lookAtEntity) { + poseStack.pushPose(); + poseStack.scale(0.8f, 0.8f, 1); + if (lookingEntity.getFirstPassenger() instanceof Player passenger) { + event.getGuiGraphics().drawString(Minecraft.getInstance().font, + Component.literal(passenger.getDisplayName().getString() + (passenger.getTeam() == null ? "" : " <" + (passenger.getTeam().getName()) + ">")), + w / 2 + 90, h / 2 - 4, passenger.getTeamColor(), false); + event.getGuiGraphics().drawString(Minecraft.getInstance().font, + Component.literal(lookingEntity.getDisplayName().getString() + " " + FormatTool.format1D(entityRange, "m")), + w / 2 + 90, h / 2 + 5, passenger.getTeamColor(), false); + } else { + event.getGuiGraphics().drawString(Minecraft.getInstance().font, + Component.literal(lookingEntity.getDisplayName().getString() + " " + FormatTool.format1D(entityRange, "M")), + w / 2 + 90, h / 2 + 5, -1, false); + } + poseStack.popPose(); + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/special/ContainerBlockPreview.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/special/ContainerBlockPreview.java new file mode 100644 index 000000000..96634a7a6 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/special/ContainerBlockPreview.java @@ -0,0 +1,129 @@ +package com.atsuishio.superbwarfare.client.renderer.special; + +import com.atsuishio.superbwarfare.block.ContainerBlock; +import com.atsuishio.superbwarfare.block.entity.ContainerBlockEntity; +import com.atsuishio.superbwarfare.client.renderer.CustomRenderType; +import com.atsuishio.superbwarfare.item.Crowbar; +import net.minecraft.client.Minecraft; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RenderLevelStageEvent; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) +public class ContainerBlockPreview { + @SubscribeEvent + public static void render(RenderLevelStageEvent event) { + if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_TRANSLUCENT_BLOCKS) { + return; + } + + var player = Minecraft.getInstance().player; + assert player != null; + + // 仅在手持撬棍时检测 + var item = player.getMainHandItem(); + if (!(item.getItem() instanceof Crowbar)) return; + + var level = player.level(); + var look = player.getLookAngle(); + + // 查找玩家看向方块 + int distance = 32; + var start = player.position().add(0, player.getEyeHeight(), 0); + var end = player.position().add(look.x * distance, look.y * distance + player.getEyeHeight(), look.z * distance); + var context = new ClipContext(start, end, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player); + var result = player.level().clip(context); + + if (result.getType().equals(BlockHitResult.Type.MISS)) return; + + // 获取集装箱 + var blockEntity = level.getBlockEntity(result.getBlockPos()); + if (!(blockEntity instanceof ContainerBlockEntity container)) return; + + // 获取实体信息 + var entityType = container.entityType; + var entity = container.entity; + + int w = 0, h = 0; + if (entityType != null) { + w = (int) (entityType.getDimensions().width() / 2 + 1); + h = (int) (entityType.getDimensions().height() + 1); + } + if (entity != null) { + w = (int) (entity.getType().getDimensions().width() / 2 + 1); + h = (int) (entity.getType().getDimensions().height() + 1); + } + if (w == 0 || h == 0) return; + + var poseStack = event.getPoseStack(); + poseStack.pushPose(); + var pos = container.getBlockPos(); + var view = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition(); + poseStack.translate(pos.getX() - view.x, pos.getY() - view.y + 1, pos.getZ() - view.z); + + // 什么b位置 + var aabb = new AABB(pos) + .inflate(w, 0, w) + .expandTowards(0, h - 1, 0) + .move(0, -1, 0); + + float startX = (float) aabb.minX - 0.001f - pos.getX(); + float startY = (float) aabb.minY - 0.001f - pos.getY(); + float startZ = (float) aabb.minZ - 0.001f - pos.getZ(); + float endX = (float) aabb.maxX + 0.001f - pos.getX(); + float endY = (float) aabb.maxY + 0.001f - pos.getY(); + float endZ = (float) aabb.maxZ + 0.001f - pos.getZ(); + + var hasEnoughSpace = ContainerBlock.canOpen(level, pos, entityType, entity); + + var red = hasEnoughSpace ? 0 : 1; + var green = 1 - red; + var blue = 0.0f; + var alpha = 0.2f; + + var builder = Minecraft.getInstance().renderBuffers().bufferSource().getBuffer(CustomRenderType.BLOCK_OVERLAY); + var m4f = poseStack.last().pose(); + + // east + builder.addVertex(m4f, startX, startY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, startX, endY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, endX, endY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, endX, startY, startZ).setColor(red, green, blue, alpha); + + // west + builder.addVertex(m4f, startX, startY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, endX, startY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, endX, endY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, startX, endY, endZ).setColor(red, green, blue, alpha); + + // south + builder.addVertex(m4f, endX, startY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, endX, endY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, endX, endY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, endX, startY, endZ).setColor(red, green, blue, alpha); + + // north + builder.addVertex(m4f, startX, startY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, startX, startY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, startX, endY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, startX, endY, startZ).setColor(red, green, blue, alpha); + + // top + builder.addVertex(m4f, startX, endY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, endX, endY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, endX, endY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, startX, endY, endZ).setColor(red, green, blue, alpha); + + // bottom + builder.addVertex(m4f, startX, startY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, endX, startY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, endX, startY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(m4f, startX, startY, endZ).setColor(red, green, blue, alpha); + + poseStack.popPose(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java index 169915b9a..f0f7b4bc4 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java @@ -3,8 +3,8 @@ package com.atsuishio.superbwarfare.entity.projectile; import com.atsuishio.superbwarfare.config.server.ExplosionConfig; import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; import com.atsuishio.superbwarfare.init.*; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; -import com.atsuishio.superbwarfare.network.message.ClientMotionSyncMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientMotionSyncMessage; import com.atsuishio.superbwarfare.tools.ChunkLoadTool; import com.atsuishio.superbwarfare.tools.CustomExplosion; import com.atsuishio.superbwarfare.tools.ParticleTool; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FastThrowableProjectile.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FastThrowableProjectile.java index 6daf5c7e4..911807664 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FastThrowableProjectile.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FastThrowableProjectile.java @@ -1,6 +1,6 @@ package com.atsuishio.superbwarfare.entity.projectile; -import com.atsuishio.superbwarfare.network.message.ClientMotionSyncMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientMotionSyncMessage; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/GunGrenadeEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/GunGrenadeEntity.java index 909c5035a..f29caa8cc 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/GunGrenadeEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/GunGrenadeEntity.java @@ -4,7 +4,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.ParticleTool; import com.atsuishio.superbwarfare.tools.ProjectileTool; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HandGrenadeEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HandGrenadeEntity.java index 5fdc04d08..159d3b98a 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HandGrenadeEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HandGrenadeEntity.java @@ -4,7 +4,7 @@ import com.atsuishio.superbwarfare.config.server.ExplosionConfig; import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.ParticleTool; import com.atsuishio.superbwarfare.tools.ProjectileTool; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HeliRocketEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HeliRocketEntity.java index 8e9223975..1c68a6a89 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HeliRocketEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HeliRocketEntity.java @@ -5,7 +5,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.CustomExplosion; import com.atsuishio.superbwarfare.tools.ParticleTool; import net.minecraft.core.particles.ParticleTypes; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java index 99fde47dd..bcb3d37ce 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java @@ -6,7 +6,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.*; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java index 20ab60f39..8f90d0483 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java @@ -8,9 +8,9 @@ import com.atsuishio.superbwarfare.entity.ICustomKnockback; import com.atsuishio.superbwarfare.entity.TargetEntity; import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; import com.atsuishio.superbwarfare.init.*; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; -import com.atsuishio.superbwarfare.network.message.ClientMotionSyncMessage; -import com.atsuishio.superbwarfare.network.message.PlayerGunKillMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientMotionSyncMessage; +import com.atsuishio.superbwarfare.network.message.receive.PlayerGunKillMessage; import com.atsuishio.superbwarfare.tools.*; import com.mojang.datafixers.util.Pair; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RgoGrenadeEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RgoGrenadeEntity.java index 3221ccd98..03430a42e 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RgoGrenadeEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RgoGrenadeEntity.java @@ -5,7 +5,7 @@ import com.atsuishio.superbwarfare.entity.vehicle.DroneEntity; import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.ParticleTool; import com.atsuishio.superbwarfare.tools.ProjectileTool; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RpgRocketEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RpgRocketEntity.java index 9bb11df28..348eafd22 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RpgRocketEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RpgRocketEntity.java @@ -5,7 +5,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.ParticleTool; import com.atsuishio.superbwarfare.tools.ProjectileTool; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmallCannonShellEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmallCannonShellEntity.java index 01c880a65..06cc92662 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmallCannonShellEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmallCannonShellEntity.java @@ -5,7 +5,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.CustomExplosion; import com.atsuishio.superbwarfare.tools.ParticleTool; import com.atsuishio.superbwarfare.tools.ProjectileTool; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/TaserBulletEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/TaserBulletEntity.java index 64a30571d..63677d2bf 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/TaserBulletEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/TaserBulletEntity.java @@ -4,7 +4,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModMobEffects; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java index f114f721e..275a4112b 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java @@ -6,7 +6,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.CustomExplosion; import com.atsuishio.superbwarfare.tools.ParticleTool; import com.atsuishio.superbwarfare.tools.VectorTool; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java index 3b72a511e..4615244bb 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java @@ -16,7 +16,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.init.ModTags; -import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; import com.atsuishio.superbwarfare.tools.AmmoType; import com.atsuishio.superbwarfare.tools.CustomExplosion; import com.atsuishio.superbwarfare.tools.InventoryTool; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/AnnihilatorEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/AnnihilatorEntity.java index 03c051ea1..83ef83eec 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/AnnihilatorEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/AnnihilatorEntity.java @@ -15,7 +15,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.init.ModTags; -import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; import com.atsuishio.superbwarfare.tools.*; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java index 06b712790..2aac61653 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java @@ -18,7 +18,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.init.ModTags; -import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; import com.atsuishio.superbwarfare.tools.AmmoType; import com.atsuishio.superbwarfare.tools.CustomExplosion; import com.atsuishio.superbwarfare.tools.InventoryTool; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java index 6fdb784d8..6efa54cfc 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java @@ -17,7 +17,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.init.ModTags; -import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; import com.atsuishio.superbwarfare.tools.AmmoType; import com.atsuishio.superbwarfare.tools.CustomExplosion; import com.atsuishio.superbwarfare.tools.InventoryTool; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java index 4538c15d4..0badf8101 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java @@ -14,7 +14,7 @@ import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.init.ModTags; import com.atsuishio.superbwarfare.item.common.ammo.CannonShellItem; -import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; import com.atsuishio.superbwarfare.tools.*; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java index e48ffef50..4dcf0869f 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java @@ -14,7 +14,7 @@ import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.init.ModTags; import com.atsuishio.superbwarfare.item.common.ammo.CannonShellItem; -import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; import com.atsuishio.superbwarfare.tools.*; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java index 03e92099a..35b00cb94 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java @@ -11,7 +11,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.init.ModTags; -import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; import com.atsuishio.superbwarfare.tools.AmmoType; import com.atsuishio.superbwarfare.tools.CustomExplosion; import com.atsuishio.superbwarfare.tools.InventoryTool; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java index b89ca1fd1..52cda5290 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java @@ -19,7 +19,7 @@ import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.init.ModTags; -import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; import com.atsuishio.superbwarfare.tools.*; import com.mojang.math.Axis; import net.minecraft.ChatFormatting; diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/ControllableVehicle.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/ControllableVehicle.java new file mode 100644 index 000000000..c87864b4f --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/ControllableVehicle.java @@ -0,0 +1,5 @@ +package com.atsuishio.superbwarfare.entity.vehicle.base; + +public interface ControllableVehicle { + void processInput(short keys); +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/MobileVehicleEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/MobileVehicleEntity.java index 75e0f7090..f9194e58a 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/MobileVehicleEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/MobileVehicleEntity.java @@ -40,7 +40,7 @@ import org.joml.Matrix4f; import org.joml.Vector3f; import org.joml.Vector4f; -public abstract class MobileVehicleEntity extends EnergyVehicleEntity { +public abstract class MobileVehicleEntity extends EnergyVehicleEntity implements ControllableVehicle { public static final EntityDataAccessor CANNON_RECOIL_TIME = SynchedEntityData.defineId(MobileVehicleEntity.class, EntityDataSerializers.INT); public static final EntityDataAccessor POWER = SynchedEntityData.defineId(MobileVehicleEntity.class, EntityDataSerializers.FLOAT); @@ -108,6 +108,24 @@ public abstract class MobileVehicleEntity extends EnergyVehicleEntity { } } + @Override + public void processInput(short keys) { + leftInputDown + = (keys & 0b0000001) > 0; + rightInputDown + = (keys & 0b0000010) > 0; + forwardInputDown + = (keys & 0b0000100) > 0; + backInputDown + = (keys & 0b0001000) > 0; + upInputDown + = (keys & 0b0010000) > 0; + downInputDown + = (keys & 0b0100000) > 0; + decoyInputDown + = (keys & 0b1000000) > 0; + } + @Override public void baseTick() { turretYRotO = this.getTurretYRot(); diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java index c2f6f21b8..14272e735 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java @@ -6,7 +6,7 @@ import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; import com.atsuishio.superbwarfare.entity.vehicle.weapon.VehicleWeapon; import com.atsuishio.superbwarfare.init.*; import com.atsuishio.superbwarfare.item.ContainerBlockItem; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.EntityFindUtil; import com.atsuishio.superbwarfare.tools.ParticleTool; import com.atsuishio.superbwarfare.tools.VectorTool; diff --git a/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java index 155e51ee3..8822ca160 100644 --- a/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java +++ b/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java @@ -2,11 +2,18 @@ package com.atsuishio.superbwarfare.event; import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.capability.ModCapabilities; +import com.atsuishio.superbwarfare.client.ClickHandler; import com.atsuishio.superbwarfare.config.client.DisplayConfig; +import com.atsuishio.superbwarfare.entity.vehicle.*; +import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.WeaponVehicleEntity; import com.atsuishio.superbwarfare.init.*; import com.atsuishio.superbwarfare.item.gun.GunItem; -import com.atsuishio.superbwarfare.network.message.LaserShootMessage; -import com.atsuishio.superbwarfare.network.message.ShootMessage; +import com.atsuishio.superbwarfare.network.message.send.LaserShootMessage; +import com.atsuishio.superbwarfare.network.message.send.ShootMessage; +import com.atsuishio.superbwarfare.network.message.send.VehicleMovementMessage; import com.atsuishio.superbwarfare.tools.*; import com.atsuishio.superbwarfare.tools.animation.AnimationCurves; import net.minecraft.client.CameraType; @@ -15,6 +22,8 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.LocalPlayer; import net.minecraft.commands.arguments.EntityAnchorArgument; import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; @@ -27,11 +36,18 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BellBlock; +import net.minecraft.world.level.block.CrossCollisionBlock; +import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.capabilities.Capabilities; import net.neoforged.neoforge.client.event.*; +import net.neoforged.neoforge.client.gui.VanillaGuiLayers; import net.neoforged.neoforge.network.PacketDistributor; import net.neoforged.neoforge.network.handling.IPayloadContext; import org.lwjgl.glfw.GLFW; @@ -39,6 +55,9 @@ import software.bernie.geckolib.cache.object.GeoBone; import java.util.List; +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.COAX_HEAT; +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.HEAT; + @EventBusSubscriber(modid = ModUtils.MODID, bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) public class ClientEventHandler { @@ -162,9 +181,7 @@ public class ClientEventHandler { } public static boolean isFreeCam(Player player) { - // TODO Vehicle -// return player.getVehicle() instanceof VehicleEntity vehicle && vehicle.allowFreeCam() && Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON && ModKeyMappings.FREE_CAMERA.isDown(); - return Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON && ModKeyMappings.FREE_CAMERA.isDown(); + return player.getVehicle() instanceof VehicleEntity vehicle && vehicle.allowFreeCam() && Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON && ModKeyMappings.FREE_CAMERA.isDown(); } private static boolean revolverPre() { @@ -189,39 +206,69 @@ public class ClientEventHandler { || (player != null && player.isSprinting()); } + static short keysCache = 0; + @SubscribeEvent - public static void handleClientTick(ClientTickEvent.Post event) { + public static void handleClientTick(ClientTickEvent.Pre event) { LocalPlayer player = Minecraft.getInstance().player; if (player == null) { return; } ItemStack stack = player.getMainHandItem(); -// if (stack.is(ModItems.MINIGUN.get())) { -// if (holdFire || zoom) { -// miniGunRot = Math.min(miniGunRot + 5, 21); -// float rpm = (float) GunsTool.getGunIntTag(stack, "RPM", 0) / 3600; -// player.playSound(ModSounds.MINIGUN_ROT.get(), 1, 0.7f + rpm); -// } -// } + if (stack.is(ModItems.MINIGUN.get())) { + if (holdFire || zoom) { + miniGunRot = Math.min(miniGunRot + 5, 21); + float rpm = (float) GunsTool.getGunIntTag(stack, "RPM", 0) / 3600; + player.playSound(ModSounds.MINIGUN_ROT.get(), 1, 0.7f + rpm); + } + } -// if (notInGame() && !ClickHandler.switchZoom) { -// zoom = false; -// } + if (notInGame() && !ClickHandler.switchZoom) { + zoom = false; + } isProne(player); beamShoot(player, stack); handleLungeAttack(player, stack); handleGunMelee(player, stack); -// if (player.getVehicle() instanceof MobileVehicleEntity mobileVehicle && mobileVehicle.getFirstPassenger() == player && notInGame()) { -// ModUtils.PACKET_HANDLER.sendToServer(new VehicleMovementMessage(0, false)); -// ModUtils.PACKET_HANDLER.sendToServer(new VehicleMovementMessage(1, false)); -// ModUtils.PACKET_HANDLER.sendToServer(new VehicleMovementMessage(2, false)); -// ModUtils.PACKET_HANDLER.sendToServer(new VehicleMovementMessage(3, false)); -// ModUtils.PACKET_HANDLER.sendToServer(new VehicleMovementMessage(4, false)); -// ModUtils.PACKET_HANDLER.sendToServer(new VehicleMovementMessage(5, false)); -// ModUtils.PACKET_HANDLER.sendToServer(new VehicleMovementMessage(6, false)); -// } + var options = Minecraft.getInstance().options; + short keys = 0; + + // 正在游戏内控制载具或无人机 + if (!notInGame() && (player.getVehicle() instanceof MobileVehicleEntity mobileVehicle + && mobileVehicle.getFirstPassenger() == player + || stack.is(ModItems.MONITOR.get()) + && NBTTool.getBoolean(stack, "Using", false) + && NBTTool.getBoolean(stack, "Linked", false)) + ) { + if (options.keyLeft.isDown()) { + keys |= 0b0000001; + } + if (options.keyRight.isDown()) { + keys |= 0b0000010; + } + if (options.keyUp.isDown()) { + keys |= 0b0000100; + } + if (options.keyDown.isDown()) { + keys |= 0b0001000; + } + if (options.keyJump.isDown()) { + keys |= 0b0010000; + } + if (options.keyShift.isDown()) { + keys |= 0b0100000; + } + if (ModKeyMappings.RELEASE_DECOY.isDown()) { + keys |= 0b1000000; + } + } + + if (keys != keysCache) { + PacketDistributor.sendToServer(new VehicleMovementMessage(keys)); + keysCache = keys; + } handleVariableDecrease(); aimAtVillager(player); @@ -251,12 +298,13 @@ public class ClientEventHandler { public static void handleGunMelee(Player player, ItemStack stack) { if (stack.getItem() instanceof GunItem gunItem) { + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); if (gunItem.hasMeleeAttack(stack) && gunMelee == 0 && drawTime < 0.01 && ModKeyMappings.MELEE.isDown() -// && !(player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) + && !(player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) && !holdFireVehicle && !notInGame() -// && !cap != null && cap.edit + && cap != null && !cap.edit && !(NBTTool.getTag(stack).getBoolean("is_normal_reloading") || NBTTool.getTag(stack).getBoolean("is_empty_reloading")) && !GunsTool.getGunBooleanTag(stack, "Reloading") && !player.getCooldowns().isOnCooldown(stack.getItem()) @@ -266,10 +314,12 @@ public class ClientEventHandler { player.playSound(SoundEvents.PLAYER_ATTACK_SWEEP, 1f, 1); } if (gunMelee == 22) { -// Entity lookingEntity = TraceTool.findMeleeEntity(player, player.getEntityReach()); -// if (lookingEntity != null) { + Entity lookingEntity = TraceTool.findMeleeEntity(player, player.entityInteractionRange()); + if (lookingEntity != null) { + + // TODO melee attack msg // ModUtils.PACKET_HANDLER.sendToServer(new MeleeAttackMessage(lookingEntity.getUUID())); -// } + } } } @@ -279,33 +329,34 @@ public class ClientEventHandler { } public static void handleLungeAttack(Player player, ItemStack stack) { -// if (stack.is(ModItems.LUNGE_MINE.get()) && lungeAttack == 0 && lungeDraw == 0 && holdFire) { -// lungeAttack = 36; -// holdFire = false; -// player.playSound(SoundEvents.PLAYER_ATTACK_SWEEP, 1f, 1); -// } -// -// if (stack.is(ModItems.LUNGE_MINE.get()) && ((lungeAttack >= 18 && lungeAttack <= 21) || lungeSprint > 0)) { -// Entity lookingEntity = TraceTool.findLookingEntity(player, player.getEntityReach() + 1.5); -// -// BlockHitResult result = player.level().clip(new ClipContext(player.getEyePosition(), player.getEyePosition().add(player.getLookAngle().scale(player.getBlockReach() + 0.5)), -// ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)); -// -// Vec3 looking = Vec3.atLowerCornerOf(player.level().clip(new ClipContext(player.getEyePosition(), player.getEyePosition().add(player.getLookAngle().scale(player.getBlockReach() + 0.5)), ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)).getBlockPos()); -// BlockState blockState = player.level().getBlockState(BlockPos.containing(looking.x(), looking.y(), looking.z())); -// -// if (lookingEntity != null) { + if (stack.is(ModItems.LUNGE_MINE.get()) && lungeAttack == 0 && lungeDraw == 0 && holdFire) { + lungeAttack = 36; + holdFire = false; + player.playSound(SoundEvents.PLAYER_ATTACK_SWEEP, 1f, 1); + } + + if (stack.is(ModItems.LUNGE_MINE.get()) && ((lungeAttack >= 18 && lungeAttack <= 21) || lungeSprint > 0)) { + Entity lookingEntity = TraceTool.findLookingEntity(player, player.entityInteractionRange() + 1.5); + + BlockHitResult result = player.level().clip(new ClipContext(player.getEyePosition(), player.getEyePosition().add(player.getLookAngle().scale(player.getBlockReach() + 0.5)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)); + + Vec3 looking = Vec3.atLowerCornerOf(player.level().clip(new ClipContext(player.getEyePosition(), player.getEyePosition().add(player.getLookAngle().scale(player.getBlockReach() + 0.5)), ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)).getBlockPos()); + BlockState blockState = player.level().getBlockState(BlockPos.containing(looking.x(), looking.y(), looking.z())); + + if (lookingEntity != null) { + // TODO lunge mine attack msg // ModUtils.PACKET_HANDLER.sendToServer(new LungeMineAttackMessage(0, lookingEntity.getUUID(), result)); -// lungeSprint = 0; -// lungeAttack = 0; -// lungeDraw = 30; -// } else if ((blockState.canOcclude() || blockState.getBlock() instanceof DoorBlock || blockState.getBlock() instanceof CrossCollisionBlock || blockState.getBlock() instanceof BellBlock) && lungeSprint == 0) { + lungeSprint = 0; + lungeAttack = 0; + lungeDraw = 30; + } else if ((blockState.canOcclude() || blockState.getBlock() instanceof DoorBlock || blockState.getBlock() instanceof CrossCollisionBlock || blockState.getBlock() instanceof BellBlock) && lungeSprint == 0) { // ModUtils.PACKET_HANDLER.sendToServer(new LungeMineAttackMessage(1, player.getUUID(), result)); -// lungeSprint = 0; -// lungeAttack = 0; -// lungeDraw = 30; -// } -// } + lungeSprint = 0; + lungeAttack = 0; + lungeDraw = 30; + } + } if (lungeSprint > 0) { lungeSprint--; @@ -340,6 +391,7 @@ public class ClientEventHandler { return; } + // TODO perk // var perk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); int mode = GunsTool.getGunIntTag(stack, "FireMode"); @@ -366,13 +418,15 @@ public class ClientEventHandler { // } // } else if (stack.is(ModItems.MINIGUN.get())) { // zoomSpread = 1 - (0.25 * zoomTime); + zoomSpread = 1 - (0.9 * zoomTime); + // TODO perk } else { zoomSpread = 1 - (0.9 * zoomTime); } -// double spread = stack.is(ModTags.Items.SHOTGUN) || stack.is(ModItems.MINIGUN.get()) ? 1.2 * zoomSpread * (basicDev + 0.2 * (walk + sprint + crouching + prone + jump + ride) + fireSpread) : zoomSpread * (0.7 * basicDev + walk + sprint + crouching + prone + jump + ride + 0.8 * fireSpread); + double spread = stack.is(ModTags.Items.SHOTGUN) || stack.is(ModItems.MINIGUN.get()) ? 1.2 * zoomSpread * (basicDev + 0.2 * (walk + sprint + crouching + prone + jump + ride) + fireSpread) : zoomSpread * (0.7 * basicDev + walk + sprint + crouching + prone + jump + ride + 0.8 * fireSpread); -// gunSpread = Mth.lerp(0.14 * times, gunSpread, spread); + gunSpread = Mth.lerp(0.14 * times, gunSpread, spread); // 开火部分 double weight = GunsTool.getGunDoubleTag(stack, "Weight") + GunsTool.getGunDoubleTag(stack, "CustomWeight"); @@ -390,6 +444,7 @@ public class ClientEventHandler { } if (GunsTool.getPerkIntTag(stack, "DesperadoTimePost") > 0) { + // TODO perk // int perkLevel = PerkHelper.getItemPerkLevel(ModPerks.DESPERADO.get(), stack); // rpm *= (int) (1.285 + 0.015 * perkLevel); } @@ -411,8 +466,7 @@ public class ClientEventHandler { var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); if ((holdFire || burstFireSize > 0) - // todo ban hand -// && !(player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) + && !(player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) && !holdFireVehicle && (stack.is(ModTags.Items.NORMAL_GUN) && cantFireTime == 0 @@ -426,13 +480,11 @@ public class ClientEventHandler { && !player.getCooldowns().isOnCooldown(stack.getItem()) && !GunsTool.getGunBooleanTag(stack, "NeedBoltAction", false) && revolverPre()) - || ( - // todo minigun -// stack.is(ModItems.MINIGUN.get()) && - !player.isSprinting() - && NBTTool.getTag(stack).getDouble("overheat") == 0 - && !player.getCooldowns().isOnCooldown(stack.getItem()) && miniGunRot >= 20 - && (cap != null && cap.rifleAmmo > 0 || InventoryTool.hasCreativeAmmoBox(player)) + || (stack.is(ModItems.MINIGUN.get()) + && !player.isSprinting() + && NBTTool.getTag(stack).getDouble("overheat") == 0 + && !player.getCooldowns().isOnCooldown(stack.getItem()) && miniGunRot >= 20 + && (cap != null && cap.rifleAmmo > 0 || InventoryTool.hasCreativeAmmoBox(player)) ))) { if (mode == 0) { if (clientTimer.getProgress() == 0) { @@ -469,14 +521,15 @@ public class ClientEventHandler { clientTimer.stop(); } -// if (stack.getItem() == ModItems.DEVOTION.get() && (GunNBTTool.getOrCreateTag(stack).getBoolean("is_normal_reloading") || GunNBTTool.getOrCreateTag(stack).getBoolean("is_empty_reloading"))) { -// customRpm = 0; -// } + if (stack.getItem() == ModItems.DEVOTION.get() && (NBTTool.getTag(stack).getBoolean("is_normal_reloading") || NBTTool.getTag(stack).getBoolean("is_empty_reloading"))) { + customRpm = 0; + } } public static void beamShoot(Player player, ItemStack stack) { if (stack.is(ModItems.BEAM_TEST.get()) && player.getUseItem() == stack) { Entity lookingEntity = TraceTool.laserfindLookingEntity(player, 512); + if (lookingEntity == null) return; if (player.isCrouching()) { Entity seekingEntity = SeekTool.seekLivingEntity(player, player.level(), 64, 32); @@ -485,10 +538,6 @@ public class ClientEventHandler { } } - if (lookingEntity == null) { - return; - } - boolean canAttack = lookingEntity != player && !(lookingEntity instanceof Player player_ && (player_.isCreative() || player_.isSpectator())) && (!player.isAlliedTo(lookingEntity) || lookingEntity.getTeam() == null || lookingEntity.getTeam().getName().equals("TDM")); @@ -520,18 +569,19 @@ public class ClientEventHandler { burstFireSize--; } -// if (stack.is(ModItems.DEVOTION.get())) { + if (stack.is(ModItems.DEVOTION.get())) { + // TODO perk // int perkLevel = PerkHelper.getItemPerkLevel(ModPerks.TURBO_CHARGER.get(), stack); // customRpm = Math.min(customRpm + 15 + ((perkLevel > 0 ? 5 : 0) + 3 * perkLevel), 500); -// } + } -// if (stack.getItem() == ModItems.SENTINEL.get()) { -// chamberRot = 1; -// } -// -// if (stack.getItem() == ModItems.NTW_20.get()) { -// actionMove = 1; -// } + if (stack.getItem() == ModItems.SENTINEL.get()) { + chamberRot = 1; + } + + if (stack.getItem() == ModItems.NTW_20.get()) { + actionMove = 1; + } // 判断是否为栓动武器(BoltActionTime > 0),并在开火后给一个需要上膛的状态 if (GunsTool.getGunIntTag(stack, "BoltActionTime", 0) > 0 && GunsTool.getGunIntTag(stack, "Ammo", 0) > (stack.is(ModTags.Items.REVOLVER) ? 0 : 1)) { @@ -544,28 +594,28 @@ public class ClientEventHandler { playGunClientSounds(player); handleClientShoot(); } -// } else if (stack.is(ModItems.MINIGUN.get())) { -// var tag = GunNBTTool.getOrCreateTag(stack); -// -// if ((player.getCapability(ModVariables.PLAYER_VARIABLES_CAPABILITY, null).orElse(new ModVariables.PlayerVariables())).rifleAmmo > 0 -// || InventoryTool.hasCreativeAmmoBox(player)) { -// + } else if (stack.is(ModItems.MINIGUN.get())) { + var tag = NBTTool.getTag(stack); + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap != null && cap.rifleAmmo > 0 || InventoryTool.hasCreativeAmmoBox(player)) { + // TODO perk // var perk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); -// float pitch = tag.getDouble("heat") <= 40 ? 1 : (float) (1 - 0.025 * Math.abs(40 - tag.getDouble("heat"))); -// -// player.playSound(ModSounds.MINIGUN_FIRE_1P.get(), 1f, pitch); -// + float pitch = tag.getDouble("heat") <= 40 ? 1 : (float) (1 - 0.025 * Math.abs(40 - tag.getDouble("heat"))); + + player.playSound(ModSounds.MINIGUN_FIRE_1P.get(), 1f, pitch); + // if (perk == ModPerks.BEAST_BULLET.get()) { // player.playSound(ModSounds.HENG.get(), 1f, 1f); // } -// -// double shooterHeight = player.getEyePosition().distanceTo((Vec3.atLowerCornerOf(player.level().clip(new ClipContext(player.getEyePosition(), player.getEyePosition().add(new Vec3(0, -1, 0).scale(10)), -// ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)).getBlockPos()))); -// -// ModUtils.queueClientWork((int) (1 + 1.5 * shooterHeight), () -> player.playSound(ModSounds.SHELL_CASING_NORMAL.get(), (float) Math.max(1.5 - 0.2 * shooterHeight, 0), 1)); -// } -// -// handleClientShoot(); + + double shooterHeight = player.getEyePosition().distanceTo((Vec3.atLowerCornerOf(player.level().clip(new ClipContext(player.getEyePosition(), player.getEyePosition().add(new Vec3(0, -1, 0).scale(10)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)).getBlockPos()))); + + ModUtils.queueClientWork((int) (1 + 1.5 * shooterHeight), () -> player.playSound(ModSounds.SHELL_CASING_NORMAL.get(), (float) Math.max(1.5 - 0.2 * shooterHeight, 0), 1)); + } + + handleClientShoot(); } } @@ -599,17 +649,15 @@ public class ClientEventHandler { } public static void handleShakeClient(double time, double radius, double amplitude, double x, double y, double z, final IPayloadContext context) { -// if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) { -// Player player = Minecraft.getInstance().player; -// if (player == null) return; -// shakeTime = time; -// shakeRadius = radius; -// shakeAmplitude = amplitude * Mth.DEG_TO_RAD; -// shakePos[0] = x; -// shakePos[1] = y; -// shakePos[2] = z; -// shakeType = 2 * (Math.random() - 0.5); -// } + Player player = Minecraft.getInstance().player; + if (player == null) return; + shakeTime = time; + shakeRadius = radius; + shakeAmplitude = amplitude * Mth.DEG_TO_RAD; + shakePos[0] = x; + shakePos[1] = y; + shakePos[2] = z; + shakeType = 2 * (Math.random() - 0.5); } public static void playGunClientSounds(Player player) { @@ -621,35 +669,33 @@ public class ClientEventHandler { String origin = stack.getItem().getDescriptionId(); String name = origin.substring(origin.lastIndexOf(".") + 1); -// if (stack.getItem() == ModItems.SENTINEL.get()) { -// AtomicBoolean charged = new AtomicBoolean(false); -// -// stack.getCapability(ForgeCapabilities.ENERGY).ifPresent( -// e -> charged.set(e.getEnergyStored() > 0) -// ); -// -// if (charged.get()) { -// SoundEvent sound1p = BuiltInRegistries.SOUND_EVENT.get(ModUtils.loc( "sentinel_charge_fire_1p")); -// if (sound1p != null) { -// player.playSound(sound1p, 2f, 1); -// } -// return; -// } -// } + if (stack.getItem() == ModItems.SENTINEL.get()) { + var cap = stack.getCapability(Capabilities.EnergyStorage.ITEM); + var charged = cap != null && cap.getEnergyStored() > 0; + if (charged) { + SoundEvent sound1p = BuiltInRegistries.SOUND_EVENT.get(ModUtils.loc("sentinel_charge_fire_1p")); + if (sound1p != null) { + player.playSound(sound1p, 2f, 1); + } + return; + } + } + + // TODO perk // var perk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); -// + // if (perk == ModPerks.BEAST_BULLET.get()) { // player.playSound(ModSounds.HENG.get(), 1f, 1f); // } int barrelType = GunsTool.getAttachmentType(stack, GunsTool.AttachmentType.BARREL); -// SoundEvent sound1p = ForgeRegistries.SOUND_EVENTS.getValue(ModUtils.loc(name + (barrelType == 2 ? "_fire_1p_s" : "_fire_1p"))); + SoundEvent sound1p = BuiltInRegistries.SOUND_EVENT.get(ModUtils.loc(name + (barrelType == 2 ? "_fire_1p_s" : "_fire_1p"))); -// if (sound1p != null) { -// player.playSound(sound1p, 2f, 1); -// } + if (sound1p != null) { + player.playSound(sound1p, 2f, 1); + } double shooterHeight = player.getEyePosition().distanceTo((Vec3.atLowerCornerOf(player.level().clip(new ClipContext(player.getEyePosition(), player.getEyePosition().add(new Vec3(0, -1, 0).scale(10)), ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)).getBlockPos()))); @@ -680,83 +726,85 @@ public class ClientEventHandler { holdFireVehicle = false; } -// if (player.getVehicle() instanceof VehicleEntity pVehicle && player.getVehicle() instanceof WeaponVehicleEntity iVehicle && iVehicle.hasWeapon(pVehicle.getSeatIndex(player)) && iVehicle.canShoot(player)) { -// int rpm = iVehicle.mainGunRpm(player); -// if (rpm == 0) { -// rpm = 240; -// } -// -// double rps = (double) rpm / 60; -// int cooldown = (int) (1000 / rps); -// -// if ((holdFireVehicle)) { -// if (!clientTimerVehicle.started()) { -// clientTimerVehicle.start(); -// // 首发瞬间发射 -// clientTimerVehicle.setProgress((cooldown + 1)); -// } -// -// if (clientTimerVehicle.getProgress() >= cooldown) { + if (player.getVehicle() instanceof VehicleEntity pVehicle && player.getVehicle() instanceof WeaponVehicleEntity iVehicle && iVehicle.hasWeapon(pVehicle.getSeatIndex(player)) && iVehicle.canShoot(player)) { + int rpm = iVehicle.mainGunRpm(player); + if (rpm == 0) { + rpm = 240; + } + + double rps = (double) rpm / 60; + int cooldown = (int) (1000 / rps); + + if ((holdFireVehicle)) { + if (!clientTimerVehicle.started()) { + clientTimerVehicle.start(); + // 首发瞬间发射 + clientTimerVehicle.setProgress((cooldown + 1)); + } + + if (clientTimerVehicle.getProgress() >= cooldown) { + // TODO vehicle fire msg // ModUtils.PACKET_HANDLER.sendToServer(new VehicleFireMessage(pVehicle.getSeatIndex(player))); -// playVehicleClientSounds(player, iVehicle, pVehicle.getSeatIndex(player)); -// clientTimerVehicle.setProgress((clientTimerVehicle.getProgress() - cooldown)); -// } -// } else if (clientTimerVehicle.getProgress() >= cooldown) { -// clientTimerVehicle.stop(); -// } -// } else { -// clientTimerVehicle.stop(); -// } + + playVehicleClientSounds(player, iVehicle, pVehicle.getSeatIndex(player)); + clientTimerVehicle.setProgress((clientTimerVehicle.getProgress() - cooldown)); + } + } else if (clientTimerVehicle.getProgress() >= cooldown) { + clientTimerVehicle.stop(); + } + } else { + clientTimerVehicle.stop(); + } } -// public static void playVehicleClientSounds(Player player, WeaponVehicleEntity iVehicle, int type) { -// if (iVehicle instanceof SpeedboatEntity speedboat) { -// float pitch = speedboat.getEntityData().get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - speedboat.getEntityData().get(HEAT))); -// player.playSound(ModSounds.M_2_FIRE_1P.get(), 1f, pitch); -// player.playSound(ModSounds.SHELL_CASING_50CAL.get(), 0.3f, 1); -// } -// -// if (iVehicle instanceof Ah6Entity ah6Entity) { -// float pitch = ah6Entity.getEntityData().get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - ah6Entity.getEntityData().get(HEAT))); -// if (ah6Entity.getWeaponIndex(0) == 0) { -// player.playSound(ModSounds.HELICOPTER_CANNON_FIRE_1P.get(), 1f, pitch); -// } else if (ah6Entity.getWeaponIndex(0) == 1) { -// player.playSound(ModSounds.HELICOPTER_ROCKET_FIRE_1P.get(), 1f, 1); -// } -// } -// if (iVehicle instanceof Lav150Entity lav150) { -// if (lav150.getWeaponIndex(0) == 0) { -// float pitch = lav150.getEntityData().get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - lav150.getEntityData().get(HEAT))); -// player.playSound(ModSounds.LAV_CANNON_FIRE_1P.get(), 1f, pitch); -// player.playSound(ModSounds.SHELL_CASING_50CAL.get(), 0.3f, 1); -// } else if (lav150.getWeaponIndex(0) == 1) { -// float pitch = lav150.getEntityData().get(COAX_HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - lav150.getEntityData().get(COAX_HEAT))); -// player.playSound(ModSounds.COAX_FIRE_1P.get(), 1f, pitch); -// } -// -// } -// if (iVehicle instanceof Bmp2Entity bmp2) { -// if (bmp2.getWeaponIndex(0) == 0) { -// float pitch = bmp2.getEntityData().get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - bmp2.getEntityData().get(HEAT))); -// player.playSound(ModSounds.BMP_CANNON_FIRE_1P.get(), 1f, pitch); -// player.playSound(ModSounds.SHELL_CASING_50CAL.get(), 0.3f, 1); -// } else if (bmp2.getWeaponIndex(0) == 1) { -// float pitch = bmp2.getEntityData().get(COAX_HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - bmp2.getEntityData().get(COAX_HEAT))); -// player.playSound(ModSounds.COAX_FIRE_1P.get(), 1f, pitch); -// } else if (bmp2.getWeaponIndex(0) == 2) { -// player.playSound(ModSounds.BMP_MISSILE_FIRE_1P.get(), 1f, 1); -// } -// } -// if (iVehicle instanceof Yx100Entity yx100) { -// if (type == 1) { -// float pitch = yx100.getEntityData().get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - yx100.getEntityData().get(HEAT))); -// player.playSound(ModSounds.M_2_FIRE_1P.get(), 1f, pitch); -// player.playSound(ModSounds.SHELL_CASING_50CAL.get(), 0.3f, 1); -// } else { -// player.playSound(ModSounds.YX_100_FIRE_1P.get(), 1f, 1); -// } -// } -// } + public static void playVehicleClientSounds(Player player, WeaponVehicleEntity iVehicle, int type) { + if (iVehicle instanceof SpeedboatEntity speedboat) { + float pitch = speedboat.getEntityData().get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - speedboat.getEntityData().get(HEAT))); + player.playSound(ModSounds.M_2_FIRE_1P.get(), 1f, pitch); + player.playSound(ModSounds.SHELL_CASING_50CAL.get(), 0.3f, 1); + } + + if (iVehicle instanceof Ah6Entity ah6Entity) { + float pitch = ah6Entity.getEntityData().get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - ah6Entity.getEntityData().get(HEAT))); + if (ah6Entity.getWeaponIndex(0) == 0) { + player.playSound(ModSounds.HELICOPTER_CANNON_FIRE_1P.get(), 1f, pitch); + } else if (ah6Entity.getWeaponIndex(0) == 1) { + player.playSound(ModSounds.HELICOPTER_ROCKET_FIRE_1P.get(), 1f, 1); + } + } + if (iVehicle instanceof Lav150Entity lav150) { + if (lav150.getWeaponIndex(0) == 0) { + float pitch = lav150.getEntityData().get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - lav150.getEntityData().get(HEAT))); + player.playSound(ModSounds.LAV_CANNON_FIRE_1P.get(), 1f, pitch); + player.playSound(ModSounds.SHELL_CASING_50CAL.get(), 0.3f, 1); + } else if (lav150.getWeaponIndex(0) == 1) { + float pitch = lav150.getEntityData().get(COAX_HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - lav150.getEntityData().get(COAX_HEAT))); + player.playSound(ModSounds.COAX_FIRE_1P.get(), 1f, pitch); + } + + } + if (iVehicle instanceof Bmp2Entity bmp2) { + if (bmp2.getWeaponIndex(0) == 0) { + float pitch = bmp2.getEntityData().get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - bmp2.getEntityData().get(HEAT))); + player.playSound(ModSounds.BMP_CANNON_FIRE_1P.get(), 1f, pitch); + player.playSound(ModSounds.SHELL_CASING_50CAL.get(), 0.3f, 1); + } else if (bmp2.getWeaponIndex(0) == 1) { + float pitch = bmp2.getEntityData().get(COAX_HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - bmp2.getEntityData().get(COAX_HEAT))); + player.playSound(ModSounds.COAX_FIRE_1P.get(), 1f, pitch); + } else if (bmp2.getWeaponIndex(0) == 2) { + player.playSound(ModSounds.BMP_MISSILE_FIRE_1P.get(), 1f, 1); + } + } + if (iVehicle instanceof Yx100Entity yx100) { + if (type == 1) { + float pitch = yx100.getEntityData().get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - yx100.getEntityData().get(HEAT))); + player.playSound(ModSounds.M_2_FIRE_1P.get(), 1f, pitch); + player.playSound(ModSounds.SHELL_CASING_50CAL.get(), 0.3f, 1); + } else { + player.playSound(ModSounds.YX_100_FIRE_1P.get(), 1f, 1); + } + } + } @SubscribeEvent public static void handleWeaponBreathSway(RenderFrameEvent.Pre event) { @@ -764,8 +812,8 @@ public class ClientEventHandler { if (player == null) return; ItemStack stack = player.getMainHandItem(); if (!(stack.getItem() instanceof GunItem gunItem)) return; -// if (player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.isDriver(player) && iArmedVehicle.hidePassenger(player)) -// return; + if (player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.isDriver(player) && iArmedVehicle.hidePassenger(player)) + return; float pose; float times = 2 * (float) Math.min(Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), 0.8); @@ -810,10 +858,10 @@ public class ClientEventHandler { ItemStack stack = living.getMainHandItem(); if (level != null - && ( - // todo monitor -// stack.is(ModItems.MONITOR.get()) && - NBTTool.getTag(stack).getBoolean("Using") && NBTTool.getTag(stack).getBoolean("Linked"))) { + && (stack.is(ModItems.MONITOR.get()) + && NBTTool.getTag(stack).getBoolean("Using") + && NBTTool.getTag(stack).getBoolean("Linked")) + ) { handleDroneCamera(event, living); } else { var effect = Minecraft.getInstance().gameRenderer.currentEffect(); @@ -851,9 +899,9 @@ public class ClientEventHandler { cameraYaw = event.getYaw(); cameraRoll = event.getRoll(); -// if (player != null && player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) { -// return; -// } + if (player != null && player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) { + return; + } if (level != null && stack.is(ModTags.Items.GUN)) { handleWeaponSway(living); @@ -871,21 +919,20 @@ public class ClientEventHandler { handleShockCamera(event, living); } - private static void handleDroneCamera(ViewportEvent.ComputeCameraAngles event, LivingEntity entity) { + public static void handleDroneCamera(ViewportEvent.ComputeCameraAngles event, LivingEntity entity) { ItemStack stack = entity.getMainHandItem(); - float yaw = event.getYaw(); -// DroneEntity drone = EntityFindUtil.findDrone(entity.level(), GunNBTTool.getOrCreateTag(stack).getString("LinkedDrone")); -// -// if (drone != null) { -// event.setRoll(drone.getRoll((float) event.getPartialTick()) * (1 - (drone.getPitch((float) event.getPartialTick()) / 90))); -// } -// -// if (drone != null && GunNBTTool.getOrCreateTag(stack).getBoolean("Using")) { -// if (Minecraft.getInstance().gameRenderer.currentEffect() == null) { -// Minecraft.getInstance().gameRenderer.loadEffect(ModUtils.loc("shaders/post/scan_pincushion.json")); -// } -// } + DroneEntity drone = EntityFindUtil.findDrone(entity.level(), NBTTool.getTag(stack).getString("LinkedDrone")); + + if (drone != null) { + event.setRoll(drone.getRoll((float) event.getPartialTick()) * (1 - (drone.getPitch((float) event.getPartialTick()) / 90))); + } + + if (drone != null && NBTTool.getTag(stack).getBoolean("Using")) { + if (Minecraft.getInstance().gameRenderer.currentEffect() == null) { + Minecraft.getInstance().gameRenderer.loadEffect(ModUtils.loc("shaders/post/scan_pincushion.json")); + } + } } @SubscribeEvent @@ -911,21 +958,21 @@ public class ClientEventHandler { } ItemStack stack = player.getMainHandItem(); -// if (stack.is(ModItems.MONITOR.get()) && GunNBTTool.getOrCreateTag(stack).getBoolean("Using") && GunNBTTool.getOrCreateTag(stack).getBoolean("Linked")) { -// if (EntityFindUtil.findDrone(player.level(), GunNBTTool.getOrCreateTag(stack).getString("LinkedDrone")) != null) { -// event.setCanceled(true); -// } -// } -// -// if (player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) { -// event.setCanceled(true); -// } + if (stack.is(ModItems.MONITOR.get()) && NBTTool.getTag(stack).getBoolean("Using") && NBTTool.getTag(stack).getBoolean("Linked")) { + if (EntityFindUtil.findDrone(player.level(), NBTTool.getTag(stack).getString("LinkedDrone")) != null) { + event.setCanceled(true); + } + } + + if (player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) { + event.setCanceled(true); + } } private static void handleWeaponSway(LivingEntity entity) { ItemStack stack = entity.getMainHandItem(); if (stack.getItem() instanceof GunItem gunItem && entity instanceof Player player) { -// float times = 2 * (float) Math.min(Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), 0.8); + float times = 2 * (float) Math.min(Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), 0.8); double pose; if (player.isShiftKeyDown() && player.getBbHeight() >= 1 && isProne(player)) { @@ -936,7 +983,7 @@ public class ClientEventHandler { pose = 1; } -// swayTime += 0.05 * times; + swayTime += 0.05 * times; swayX = pose * -0.008 * Math.sin(swayTime) * (1 - 0.95 * zoomTime); swayY = pose * 0.125 * Math.sin(swayTime - 1.585) * (1 - 0.95 * zoomTime) - 3 * moveRotZ; @@ -1014,21 +1061,22 @@ public class ClientEventHandler { double weight = GunsTool.getGunDoubleTag(stack, "Weight") + GunsTool.getGunDoubleTag(stack, "CustomWeight"); double speed = 1.5 - (0.07 * weight); -// if (zoom -// && !(player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) -// && !notInGame() -// && drawTime < 0.01 -// && !cap != null && cap.edit) { -// if (Minecraft.getInstance().player != null) { -// Minecraft.getInstance().player.getPersistentData().putDouble("noRun", 5); -// } -// if (cantFireTime <= 10) { -// zoomTime = Mth.clamp(zoomTime + 0.03 * speed * times, 0, 1); -// } -// -// } else { -// zoomTime = Mth.clamp(zoomTime - 0.04 * speed * times, 0, 1); -// } + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (zoom + && !(player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) + && !notInGame() + && drawTime < 0.01 + && cap != null && !cap.edit) { + if (Minecraft.getInstance().player != null) { + Minecraft.getInstance().player.getPersistentData().putDouble("noRun", 5); + } + if (cantFireTime <= 10) { + zoomTime = Mth.clamp(zoomTime + 0.03 * speed * times, 0, 1); + } + + } else { + zoomTime = Mth.clamp(zoomTime - 0.04 * speed * times, 0, 1); + } zoomPos = AnimationCurves.EASE_IN_OUT_QUINT.apply(zoomTime); zoomPosZ = AnimationCurves.PARABOLA.apply(zoomTime); } @@ -1073,9 +1121,9 @@ public class ClientEventHandler { double rpm = 1; -// if (stack.is(ModItems.MINIGUN.get())) { -// rpm = (double) GunsTool.getGunIntTag(stack, "RPM", 0) / 1800; -// } + if (stack.is(ModItems.MINIGUN.get())) { + rpm = (double) GunsTool.getGunIntTag(stack, "RPM", 0) / 1800; + } float[] shake = {0, 0}; shake[0] = (float) (1.3 * amplitude * (1 / 6.3 * (fireRotTimer - 0.5)) * Math.sin(6.3 * (fireRotTimer - 0.5)) * (3 - Math.pow(fireRotTimer, 2)) + 1 * Mth.clamp(0.3 - fireRotTimer, 0, 1) * (2 * Math.random() - 1)); @@ -1162,9 +1210,9 @@ public class ClientEventHandler { double rpm = 1; -// if (stack.is(ModItems.MINIGUN.get())) { -// rpm = (double) GunsTool.getGunIntTag(stack, "RPM", 0) / 1800; -// } + if (stack.is(ModItems.MINIGUN.get())) { + rpm = (double) GunsTool.getGunIntTag(stack, "RPM", 0) / 1800; + } float gunRecoilX = (float) GunsTool.getGunDoubleTag(stack, "RecoilX", 0) * 60; @@ -1319,23 +1367,22 @@ public class ClientEventHandler { ItemStack stack = player.getMainHandItem(); -// if (player.getVehicle() instanceof WeaponVehicleEntity iVehicle && zoomVehicle) { -// event.setFOV(event.getFOV() / iVehicle.zoomFov()); -// return; -// } + if (player.getVehicle() instanceof WeaponVehicleEntity iVehicle && zoomVehicle) { + event.setFOV(event.getFOV() / iVehicle.zoomFov()); + return; + } if (stack.is(ModTags.Items.GUN)) { if (!event.usedConfiguredFov()) { return; } - double p = zoomPos; -// double p; -// if (stack.is(ModItems.BOCEK.get())) { -// p = (pullPos + 0.25) * zoomTime; -// } else { -// p = zoomPos; -// } + double p; + if (stack.is(ModItems.BOCEK.get())) { + p = (pullPos + 0.25) * zoomTime; + } else { + p = zoomPos; + } customZoom = Mth.lerp(0.6 * times, customZoom, GunsTool.getGunDoubleTag(stack, "CustomZoom", 0)); @@ -1356,6 +1403,7 @@ public class ClientEventHandler { && cap != null && !cap.edit) { if (!player.isShiftKeyDown()) { + // TODO perk // int intelligentChipLevel = PerkHelper.getItemPerkLevel(ModPerks.INTELLIGENT_CHIP.get(), stack); // // if (intelligentChipLevel > 0) { @@ -1374,11 +1422,11 @@ public class ClientEventHandler { } } -// if (stack.is(ModItems.MONITOR.get()) && GunNBTTool.getOrCreateTag(stack).getBoolean("Using") && GunNBTTool.getOrCreateTag(stack).getBoolean("Linked")) { -// droneFovLerp = Mth.lerp(0.1 * Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), droneFovLerp, droneFov); -// event.setFOV(event.getFOV() / droneFovLerp); -// fov = event.getFOV(); -// } + if (stack.is(ModItems.MONITOR.get()) && NBTTool.getTag(stack).getBoolean("Using") && NBTTool.getTag(stack).getBoolean("Linked")) { + droneFovLerp = Mth.lerp(0.1 * Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), droneFovLerp, droneFov); + event.setFOV(event.getFOV() / droneFovLerp); + fov = event.getFOV(); + } } private static Vec3 getVec3(ViewportEvent.ComputeFov event, Player player) { @@ -1403,76 +1451,64 @@ public class ClientEventHandler { public static void setPlayerInvisible(RenderPlayerEvent.Pre event) { var otherPlayer = event.getEntity(); -// if (otherPlayer.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.hidePassenger(otherPlayer)) { -// event.setCanceled(true); -// } + if (otherPlayer.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.hidePassenger(otherPlayer)) { + event.setCanceled(true); + } } -// @SubscribeEvent -// public static void handleRenderCrossHair(RenderGuiOverlayEvent.Pre event) { -// if (event.getOverlay() != VanillaGuiOverlay.CROSSHAIR.type()) { -// return; -// } -// -// Minecraft mc = Minecraft.getInstance(); -// Player player = mc.player; -// if (player == null) { -// return; -// } -// -// if (!mc.options.getCameraType().isFirstPerson()) { -// return; -// } -// -// ItemStack stack = player.getMainHandItem(); -// -// if (stack.getItem() instanceof GunItem) { -// event.setCanceled(true); -// } -// -// if (player.getVehicle() instanceof VehicleEntity pVehicle && player.getVehicle() instanceof WeaponVehicleEntity iVehicle && iVehicle.hasWeapon(pVehicle.getSeatIndex(player))) { -// event.setCanceled(true); -// } -// -// if (stack.is(ModItems.MONITOR.get()) && GunNBTTool.getOrCreateTag(stack).getBoolean("Using") && GunNBTTool.getOrCreateTag(stack).getBoolean("Linked")) { -// event.setCanceled(true); -// } -// } + @SubscribeEvent + public static void handleRenderCrossHair(RenderGuiLayerEvent.Pre event) { + if (!event.getName().equals(VanillaGuiLayers.CROSSHAIR)) return; + + Minecraft mc = Minecraft.getInstance(); + Player player = mc.player; + if (player == null) return; + if (!mc.options.getCameraType().isFirstPerson()) return; + + ItemStack stack = player.getMainHandItem(); + + if (stack.getItem() instanceof GunItem) { + event.setCanceled(true); + } + + if (player.getVehicle() instanceof VehicleEntity pVehicle && player.getVehicle() instanceof WeaponVehicleEntity iVehicle && iVehicle.hasWeapon(pVehicle.getSeatIndex(player))) { + event.setCanceled(true); + } + + if (stack.is(ModItems.MONITOR.get()) && NBTTool.getTag(stack).getBoolean("Using") && NBTTool.getTag(stack).getBoolean("Linked")) { + event.setCanceled(true); + } + } /** * 载具banHand时,禁用快捷栏渲染 */ -// @SubscribeEvent -// public static void handleAvoidRenderingHotbar(RenderGuiOverlayEvent.Pre event) { -// if (event.getOverlay() != VanillaGuiOverlay.HOTBAR.type()) { -// return; -// } -// -// Minecraft mc = Minecraft.getInstance(); -// Player player = mc.player; -// if (player == null) { -// return; -// } -// -// if (player.getVehicle() instanceof ArmedVehicleEntity vehicle && vehicle.banHand(player)) { -// event.setCanceled(true); -// } -// } + @SubscribeEvent + public static void handleAvoidRenderingHotbar(RenderGuiLayerEvent.Pre event) { + if (!event.getName().equals(VanillaGuiLayers.HOTBAR)) return; + + Minecraft mc = Minecraft.getInstance(); + Player player = mc.player; + if (player == null) return; + + if (player.getVehicle() instanceof ArmedVehicleEntity vehicle && vehicle.banHand(player)) { + event.setCanceled(true); + } + } + + public static void handleDrawMessage(boolean draw, final IPayloadContext context) { + drawTime = 1; + for (int i = 0; i < 5; i++) { + shellIndexTime[i] = 0; + } + zoom = false; + holdFire = false; + ClickHandler.switchZoom = false; + lungeDraw = 30; + lungeSprint = 0; + lungeAttack = 0; + } -// public static void handleDrawMessage(boolean draw, Supplier ctx) { -// if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) { -// drawTime = 1; -// for (int i = 0; i < 5; i++) { -// shellIndexTime[i] = 0; -// } -// zoom = false; -// holdFire = false; -// ClickHandler.switchZoom = false; -// lungeDraw = 30; -// lungeSprint = 0; -// lungeAttack = 0; -// } -// } private static void handleWeaponDraw(LivingEntity entity) { float times = Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(); ItemStack stack = entity.getMainHandItem(); @@ -1502,6 +1538,7 @@ public class ClientEventHandler { List entities = SeekTool.seekLivingEntities(villager, villager.level(), 16, 120); for (var e : entities) { if (e == player) { + // TODO aimVillager // ModUtils.PACKET_HANDLER.sendToServer(new AimVillagerMessage(villager.getId())); aimVillagerCountdown = 80; break; diff --git a/src/main/java/com/atsuishio/superbwarfare/event/ClientMouseHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/ClientMouseHandler.java new file mode 100644 index 000000000..a70b4d116 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/event/ClientMouseHandler.java @@ -0,0 +1,76 @@ +package com.atsuishio.superbwarfare.event; + +import com.atsuishio.superbwarfare.client.MouseMovementHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec2; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.ViewportEvent; + +import static com.atsuishio.superbwarfare.event.ClientEventHandler.isFreeCam; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) +public class ClientMouseHandler { + public static Vec2 posO = new Vec2(0, 0); + public static Vec2 posN = new Vec2(0, 0); + public static Vec2 mousePos = new Vec2(0, 0); + public static double PosX = 0; + public static double lerpPosX = 0; + public static double PosY = 0; + public static double lerpPosY = 0; + + public static double freeCameraPitch = 0; + public static double freeCameraYaw = 0; + + private static boolean notInGame() { + Minecraft mc = Minecraft.getInstance(); + if (mc.player == null) return true; + if (mc.getOverlay() != null) return true; + if (mc.screen != null) return true; + if (!mc.mouseHandler.isMouseGrabbed()) return true; + return !mc.isWindowActive(); + } + + @SubscribeEvent + public static void handleClientTick(ViewportEvent.ComputeCameraAngles event) { + LocalPlayer player = Minecraft.getInstance().player; + if (player == null) return; + + posO = posN; + posN = MouseMovementHandler.getMousePos(); + + if (!notInGame()) { + mousePos = posN.add(posO.scale(-1)); + + if (mousePos.x != 0) { + lerpPosX = Mth.lerp(0.1, PosX, mousePos.x); + } + if (mousePos.y != 0) { + lerpPosY = Mth.lerp(0.1, PosY, mousePos.y); + } + } + + lerpPosX = Mth.clamp(Mth.lerp(event.getPartialTick(), lerpPosX, 0), -1, 1); + lerpPosY = Mth.clamp(Mth.lerp(event.getPartialTick(), lerpPosY, 0), -1, 1); + + + if (isFreeCam(player)) { + freeCameraYaw = Mth.clamp(freeCameraYaw + 4 * lerpPosX, -100, 100); + freeCameraPitch = Mth.clamp(freeCameraPitch + 4 * lerpPosY, -90, 90); + } + + float yaw = event.getYaw(); + float pitch = event.getPitch(); + + event.setYaw((float) (yaw + freeCameraYaw)); + event.setPitch((float) (pitch + freeCameraPitch)); + + if (!isFreeCam(player)) { + freeCameraYaw *= 0.8; + freeCameraPitch *= 0.8; + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/event/ClientSoundHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/ClientSoundHandler.java new file mode 100644 index 000000000..5fde33639 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/event/ClientSoundHandler.java @@ -0,0 +1,93 @@ +package com.atsuishio.superbwarfare.event; + +import com.atsuishio.superbwarfare.entity.vehicle.*; +import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.tools.NBTTool; +import com.atsuishio.superbwarfare.tools.SeekTool; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.ClientTickEvent; +import org.joml.Math; + +import java.util.List; + +import static com.atsuishio.superbwarfare.entity.vehicle.Ah6Entity.PROPELLER_ROT; +import static com.atsuishio.superbwarfare.entity.vehicle.Bmp2Entity.DELTA_ROT; +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.POWER; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) +public class ClientSoundHandler { + @SubscribeEvent + public static void handleClientTick(ClientTickEvent event) { + LocalPlayer player = Minecraft.getInstance().player; + if (player == null) return; + + List engineVehicle = SeekTool.getVehicleWithinRange(player, player.level(), 192); + + for (var e : engineVehicle) { + if (e instanceof MobileVehicleEntity mobileVehicle) { + + Vec3 listener = player.getEyePosition(); + Vec3 engineRealPos = e.getEyePosition(); + Vec3 toVec = listener.vectorTo(engineRealPos).normalize(); + double distance = listener.distanceTo(engineRealPos); + + var engineSoundPos = new Vec3(listener.x + toVec.x, listener.y + toVec.y, listener.z + toVec.z); + SoundEvent engineSound = mobileVehicle.getEngineSound(); + float distanceReduce; + if (e instanceof Ah6Entity ah6Entity) { + distanceReduce = (float) Math.max((1 - distance / 128), 0); + if (player.getVehicle() == ah6Entity) { + player.playSound(ModSounds.HELICOPTER_ENGINE_1P.get(), 2 * (mobileVehicle.getEntityData().get(PROPELLER_ROT) - 0.012f), (float) ((2 * Math.random() - 1) * 0.1f + 1.0f)); + } else { + player.level().playLocalSound(BlockPos.containing(engineSoundPos), engineSound, mobileVehicle.getSoundSource(), 5 * (mobileVehicle.getEntityData().get(PROPELLER_ROT) - 0.012f) * distanceReduce * distanceReduce, (float) ((2 * Math.random() - 1) * 0.1f + 1), false); + } + } + if (e instanceof Lav150Entity lav150) { + distanceReduce = (float) Math.max((1 - distance / 64), 0); + if (player.getVehicle() == lav150) { + player.playSound(ModSounds.LAV_ENGINE_1P.get(), 1 * (Mth.abs(mobileVehicle.getEntityData().get(POWER)) - 0.006f), (float) ((2 * Math.random() - 1) * 0.1f + 0.95f)); + } else { + player.level().playLocalSound(BlockPos.containing(engineSoundPos), engineSound, mobileVehicle.getSoundSource(), 5 * (Mth.abs(mobileVehicle.getEntityData().get(POWER)) - 0.006f) * distanceReduce * distanceReduce, (float) ((2 * Math.random() - 1) * 0.1f + 1), false); + } + } + if (e instanceof Bmp2Entity bmp2) { + distanceReduce = (float) Math.max((1 - distance / 64), 0); + if (player.getVehicle() == bmp2) { + player.playSound(ModSounds.BMP_ENGINE_1P.get(), 1 * (Mth.abs(mobileVehicle.getEntityData().get(POWER)) + Mth.abs(0.08f * mobileVehicle.getEntityData().get(DELTA_ROT)) - 0.004f), (float) ((2 * Math.random() - 1) * 0.1f + 0.95f)); + } else { + player.level().playLocalSound(BlockPos.containing(engineSoundPos), engineSound, mobileVehicle.getSoundSource(), 5 * (Mth.abs(mobileVehicle.getEntityData().get(POWER)) + Mth.abs(0.08f * mobileVehicle.getEntityData().get(DELTA_ROT)) - 0.004f) * distanceReduce * distanceReduce, (float) ((2 * Math.random() - 1) * 0.1f + 1), false); + } + } + if (e instanceof Yx100Entity yx100) { + distanceReduce = (float) Math.max((1 - distance / 64), 0); + if (player.getVehicle() == yx100) { + player.playSound(ModSounds.BMP_ENGINE_1P.get(), 1 * (Mth.abs(mobileVehicle.getEntityData().get(POWER)) + Mth.abs(0.08f * mobileVehicle.getEntityData().get(DELTA_ROT)) - 0.004f), (float) ((2 * Math.random() - 1) * 0.1f + 0.95f)); + } else { + player.level().playLocalSound(BlockPos.containing(engineSoundPos), engineSound, mobileVehicle.getSoundSource(), 5 * (Mth.abs(mobileVehicle.getEntityData().get(POWER)) + Mth.abs(0.08f * mobileVehicle.getEntityData().get(DELTA_ROT)) - 0.004f) * distanceReduce * distanceReduce, (float) ((2 * Math.random() - 1) * 0.1f + 1), false); + } + } + if (e instanceof DroneEntity drone) { + distanceReduce = (float) Math.max((1 - distance / 64), 0); + ItemStack stack = player.getMainHandItem(); + if (stack.is(ModItems.MONITOR.get()) && NBTTool.getBoolean(stack, "Using", false)) { + player.playSound(engineSound, 1, (float) ((2 * Math.random() - 1) * 0.002f + 1.05)); + } else { + player.level().playLocalSound(BlockPos.containing(engineSoundPos), engineSound, mobileVehicle.getSoundSource(), e.onGround() ? 0 : distanceReduce * distanceReduce, (float) ((2 * Math.random() - 1) * 0.002f + 1.05), false); + } + } + } + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/event/GunEventHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/GunEventHandler.java index 2ccaeb6b8..82dddd503 100644 --- a/src/main/java/com/atsuishio/superbwarfare/event/GunEventHandler.java +++ b/src/main/java/com/atsuishio/superbwarfare/event/GunEventHandler.java @@ -4,6 +4,7 @@ import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.capability.ModCapabilities; import com.atsuishio.superbwarfare.capability.player.PlayerVariable; import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity; +import com.atsuishio.superbwarfare.event.events.ReloadEvent; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.init.ModTags; @@ -22,6 +23,7 @@ import net.minecraft.world.phys.Vec3; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.tick.PlayerTickEvent; import java.text.DecimalFormat; @@ -54,16 +56,14 @@ public class GunEventHandler { if (GunsTool.getGunIntTag(stack, "BoltActionTick") > 0) { GunsTool.setGunIntTag(stack, "BoltActionTick", GunsTool.getGunIntTag(stack, "BoltActionTick") - 1); } - - // todo marlin -// if (stack.getItem() == ModItems.MARLIN.get() && GunsTool.getGunIntTag(stack, "BoltActionTick") == 9) { -// GunNBTTool.getOrCreateTag(stack).putBoolean("empty", false); -// } + if (stack.getItem() == ModItems.MARLIN.get() && GunsTool.getGunIntTag(stack, "BoltActionTick") == 9) { + NBTTool.setBoolean(stack, "empty", false); + } if (GunsTool.getGunIntTag(stack, "BoltActionTick") == 1) { GunsTool.setGunBooleanTag(stack, "NeedBoltAction", false); if (stack.is(ModTags.Items.REVOLVER)) { - NBTTool.getTag(stack).putBoolean("canImmediatelyShoot", true); + NBTTool.setBoolean(stack, "canImmediatelyShoot", true); } } } @@ -82,36 +82,32 @@ public class GunEventHandler { String origin = stack.getItem().getDescriptionId(); String name = origin.substring(origin.lastIndexOf(".") + 1); - // todo other guns -// if (stack.getItem() == ModItems.SENTINEL.get()) { -// AtomicBoolean charged = new AtomicBoolean(false); -// -// stack.getCapability(ForgeCapabilities.ENERGY).ifPresent( -// e -> charged.set(e.getEnergyStored() > 0) -// ); -// -// if (charged.get()) { -// float soundRadius = (float) GunsTool.getGunDoubleTag(stack, "SoundRadius"); -// -// SoundEvent sound3p = BuiltInRegistries.SOUND_EVENT.get(ModUtils.loc( "sentinel_charge_fire_3p")); -// if (sound3p != null) { -// player.playSound(sound3p, soundRadius * 0.4f, 1f); -// } -// -// SoundEvent soundFar = BuiltInRegistries.SOUND_EVENT.get(ModUtils.loc( "sentinel_charge_far")); -// if (soundFar != null) { -// player.playSound(soundFar, soundRadius * 0.7f, 1f); -// } -// -// SoundEvent soundVeryFar = BuiltInRegistries.SOUND_EVENT.get(ModUtils.loc( "sentinel_charge_veryfar")); -// if (soundVeryFar != null) { -// player.playSound(soundVeryFar, soundRadius, 1f); -// } -// -// return; -// } -// } + if (stack.getItem() == ModItems.SENTINEL.get()) { + var cap = stack.getCapability(Capabilities.EnergyStorage.ITEM); + if (cap != null && cap.getEnergyStored() > 0) { + float soundRadius = (float) GunsTool.getGunDoubleTag(stack, "SoundRadius"); + + SoundEvent sound3p = BuiltInRegistries.SOUND_EVENT.get(ModUtils.loc("sentinel_charge_fire_3p")); + if (sound3p != null) { + player.playSound(sound3p, soundRadius * 0.4f, 1f); + } + + SoundEvent soundFar = BuiltInRegistries.SOUND_EVENT.get(ModUtils.loc("sentinel_charge_far")); + if (soundFar != null) { + player.playSound(soundFar, soundRadius * 0.7f, 1f); + } + + SoundEvent soundVeryFar = BuiltInRegistries.SOUND_EVENT.get(ModUtils.loc("sentinel_charge_veryfar")); + if (soundVeryFar != null) { + player.playSound(soundVeryFar, soundRadius, 1f); + } + + return; + } + } + + // TODO perk // var perk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); // // if (perk == ModPerks.BEAST_BULLET.get()) { @@ -255,7 +251,7 @@ public class GunEventHandler { 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, -// TODO incendiary bullet +// TODO perk incendiary bullet // stack.is(ModTags.Items.SHOTGUN) && perk == ModPerks.INCENDIARY_BULLET.get() ? 4.5f : velocity, velocity, (float) spared); @@ -324,8 +320,7 @@ public class GunEventHandler { // 启动换弹 if (GunsTool.getGunBooleanTag(stack, "StartReload")) { - // TODO reload event -// NeoForge.EVENT_BUS.post(new ReloadEvent.Pre(player, stack)); + NeoForge.EVENT_BUS.post(new ReloadEvent.Pre(player, stack)); if (gunItem.isOpenBolt(stack)) { if (GunsTool.getGunIntTag(stack, "Ammo", 0) == 0) { data.putInt("ReloadTime", data.getInt("EmptyReloadTime") + 1); @@ -348,51 +343,50 @@ public class GunEventHandler { data.putInt("ReloadTime", data.getInt("ReloadTime") - 1); } - // todo other guns -// if (stack.getItem() == ModItems.RPG.get()) { -// if (data.getInt("ReloadTime") == 84) { -// tag.putBoolean("empty", false); -// } -// if (data.getInt("ReloadTime") == 9) { -// data.putBoolean("CloseHammer", false); -// } -// } -// -// if (stack.getItem() == ModItems.MK_14.get()) { -// if (data.getInt("ReloadTime") == 18) { -// data.putBoolean("HoldOpen", false); -// } -// } -// -// if (stack.getItem() == ModItems.SVD.get()) { -// if (data.getInt("ReloadTime") == 17) { -// data.putBoolean("HoldOpen", false); -// } -// } -// -// if (stack.getItem() == ModItems.SKS.get()) { -// if (data.getInt("ReloadTime") == 14) { -// data.putBoolean("HoldOpen", false); -// } -// } -// -// if (stack.getItem() == ModItems.M_60.get()) { -// if (data.getInt("ReloadTime") == 55) { -// data.putBoolean("HideBulletChain", false); -// } -// } -// -// if (stack.getItem() == ModItems.GLOCK_17.get() || stack.getItem() == ModItems.GLOCK_18.get() || stack.getItem() == ModItems.M_1911.get() || stack.getItem() == ModItems.MP_443.get()) { -// if (data.getInt("ReloadTime") == 9) { -// data.putBoolean("HoldOpen", false); -// } -// } -// -// if (stack.getItem() == ModItems.QBZ_95.get()) { -// if (data.getInt("ReloadTime") == 14) { -// data.putBoolean("HoldOpen", false); -// } -// } + if (stack.getItem() == ModItems.RPG.get()) { + if (data.getInt("ReloadTime") == 84) { + tag.putBoolean("empty", false); + } + if (data.getInt("ReloadTime") == 9) { + data.putBoolean("CloseHammer", false); + } + } + + if (stack.getItem() == ModItems.MK_14.get()) { + if (data.getInt("ReloadTime") == 18) { + data.putBoolean("HoldOpen", false); + } + } + + if (stack.getItem() == ModItems.SVD.get()) { + if (data.getInt("ReloadTime") == 17) { + data.putBoolean("HoldOpen", false); + } + } + + if (stack.getItem() == ModItems.SKS.get()) { + if (data.getInt("ReloadTime") == 14) { + data.putBoolean("HoldOpen", false); + } + } + + if (stack.getItem() == ModItems.M_60.get()) { + if (data.getInt("ReloadTime") == 55) { + data.putBoolean("HideBulletChain", false); + } + } + + if (stack.getItem() == ModItems.GLOCK_17.get() || stack.getItem() == ModItems.GLOCK_18.get() || stack.getItem() == ModItems.M_1911.get() || stack.getItem() == ModItems.MP_443.get()) { + if (data.getInt("ReloadTime") == 9) { + data.putBoolean("HoldOpen", false); + } + } + + if (stack.getItem() == ModItems.QBZ_95.get()) { + if (data.getInt("ReloadTime") == 14) { + data.putBoolean("HoldOpen", false); + } + } if (data.getInt("ReloadTime") == 1) { if (gunItem.isOpenBolt(stack)) { @@ -435,8 +429,7 @@ public class GunEventHandler { NBTTool.getTag(stack).putBoolean("is_normal_reloading", false); NBTTool.getTag(stack).putBoolean("is_empty_reloading", false); - // TODO reload event -// NeoForge.EVENT_BUS.post(new ReloadEvent.Post(player, stack)); + NeoForge.EVENT_BUS.post(new ReloadEvent.Post(player, stack)); } public static void playGunEmptyReload(Player player) { @@ -456,28 +449,25 @@ public class GunEventHandler { GunsTool.reload(player, stack, AmmoType.RIFLE); } else if (stack.is(ModTags.Items.USE_HEAVY_AMMO)) { GunsTool.reload(player, stack, AmmoType.HEAVY); + } else if (stack.getItem() == ModItems.TASER.get()) { + GunsTool.setGunIntTag(stack, "Ammo", 1); + player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.TASER_ELECTRODE.get(), 1, player.inventoryMenu.getCraftSlots()); + } else if (stack.getItem() == ModItems.M_79.get()) { + GunsTool.setGunIntTag(stack, "Ammo", 1); + player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.GRENADE_40MM.get(), 1, player.inventoryMenu.getCraftSlots()); + } else if (stack.getItem() == ModItems.RPG.get()) { + GunsTool.setGunIntTag(stack, "Ammo", 1); + player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.ROCKET.get(), 1, player.inventoryMenu.getCraftSlots()); + } else if (stack.getItem() == ModItems.JAVELIN.get()) { + GunsTool.setGunIntTag(stack, "Ammo", 1); + player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.JAVELIN_MISSILE.get(), 1, player.inventoryMenu.getCraftSlots()); } - // todo other guns -// } else if (stack.getItem() == ModItems.TASER.get()) { -// GunsTool.setGunIntTag(stack, "Ammo", 1); -// player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.TASER_ELECTRODE.get(), 1, player.inventoryMenu.getCraftSlots()); -// } else if (stack.getItem() == ModItems.M_79.get()) { -// GunsTool.setGunIntTag(stack, "Ammo", 1); -// player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.GRENADE_40MM.get(), 1, player.inventoryMenu.getCraftSlots()); -// } else if (stack.getItem() == ModItems.RPG.get()) { -// GunsTool.setGunIntTag(stack, "Ammo", 1); -// player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.ROCKET.get(), 1, player.inventoryMenu.getCraftSlots()); -// } else if (stack.getItem() == ModItems.JAVELIN.get()) { -// GunsTool.setGunIntTag(stack, "Ammo", 1); -// player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.JAVELIN_MISSILE.get(), 1, player.inventoryMenu.getCraftSlots()); -// } } NBTTool.getTag(stack).putBoolean("is_normal_reloading", false); NBTTool.getTag(stack).putBoolean("is_empty_reloading", false); - // TODO reload event -// NeoForge.EVENT_BUS.post(new ReloadEvent.Post(player, stack)); + NeoForge.EVENT_BUS.post(new ReloadEvent.Post(player, stack)); } public static void playGunEmptyReloadSounds(Player player) { @@ -547,12 +537,11 @@ public class GunEventHandler { // 一阶段 if (tag.getBoolean("start_single_reload")) { - // todo reload event -// NeoForge.EVENT_BUS.post(new ReloadEvent.Pre(player, stack)); + NeoForge.EVENT_BUS.post(new ReloadEvent.Pre(player, stack)); - if ((GunsTool.getGunIntTag(stack, "PrepareLoadTime", 0) != 0 && GunsTool.getGunIntTag(stack, "Ammo", 0) == 0) -// todo 2nd -// || stack.is(ModItems.SECONDARY_CATACLYSM.get()) + if ((GunsTool.getGunIntTag(stack, "PrepareLoadTime", 0) != 0 + && GunsTool.getGunIntTag(stack, "Ammo", 0) == 0) + || stack.is(ModItems.SECONDARY_CATACLYSM.get()) ) { // 此处判断空仓换弹的时候,是否在准备阶段就需要装填一发,如M870 playGunPrepareLoadReloadSounds(player); @@ -579,18 +568,17 @@ public class GunEventHandler { tag.putBoolean("start_single_reload", false); } - // todo other guns -// if (stack.getItem() == ModItems.M_870.get()) { -// if (tag.getInt("prepare_load") == 10) { -// singleLoad(player); -// } -// } -// -// if (stack.getItem() == ModItems.SECONDARY_CATACLYSM.get()) { -// if (tag.getInt("prepare_load") == 3) { -// singleLoad(player); -// } -// } + if (stack.getItem() == ModItems.M_870.get()) { + if (tag.getInt("prepare_load") == 10) { + singleLoad(player); + } + } + + if (stack.getItem() == ModItems.SECONDARY_CATACLYSM.get()) { + if (tag.getInt("prepare_load") == 3) { + singleLoad(player); + } + } // 一阶段结束,检查备弹,如果有则二阶段启动,无则直接跳到三阶段 if ((tag.getDouble("prepare") == 1 || tag.getDouble("prepare_load") == 1)) { @@ -610,19 +598,17 @@ public class GunEventHandler { tag.putBoolean("force_stage3_start", true); } else if (stack.is(ModTags.Items.LAUNCHER) && GunsTool.getGunIntTag(stack, "MaxAmmo") == 0) { tag.putBoolean("force_stage3_start", true); - // todo 2nd -// } else if (stack.is(ModItems.SECONDARY_CATACLYSM.get()) && GunsTool.getGunIntTag(stack, "Ammo", 0) >= GunsTool.getGunIntTag(stack, "Magazine", 0)) { -// tag.putBoolean("force_stage3_start", true); + } else if (stack.is(ModItems.SECONDARY_CATACLYSM.get()) && GunsTool.getGunIntTag(stack, "Ammo", 0) >= GunsTool.getGunIntTag(stack, "Magazine", 0)) { + tag.putBoolean("force_stage3_start", true); } else { tag.putInt("reload_stage", 2); } } else { - // todo 2nd -// if (stack.is(ModItems.SECONDARY_CATACLYSM.get()) && GunsTool.getGunIntTag(stack, "Ammo", 0) >= GunsTool.getGunIntTag(stack, "Magazine", 0)) { -// tag.putBoolean("force_stage3_start", true); -// } else { - tag.putInt("reload_stage", 2); -// } + if (stack.is(ModItems.SECONDARY_CATACLYSM.get()) && GunsTool.getGunIntTag(stack, "Ammo", 0) >= GunsTool.getGunIntTag(stack, "Magazine", 0)) { + tag.putBoolean("force_stage3_start", true); + } else { + tag.putInt("reload_stage", 2); + } } // 检查备弹 } @@ -652,24 +638,24 @@ public class GunEventHandler { } } - // 装填 todo other guns -// if (stack.getItem() == ModItems.M_870.get() || stack.getItem() == ModItems.MARLIN.get()) { -// if (tag.getInt("iterative") == 3) { -// singleLoad(player); -// } -// } -// -// if (stack.getItem() == ModItems.SECONDARY_CATACLYSM.get()) { -// if (tag.getInt("iterative") == 16) { -// singleLoad(player); -// } -// } -// -// if (stack.getItem() == ModItems.K_98.get() || stack.getItem() == ModItems.MOSIN_NAGANT.get()) { -// if (tag.getInt("iterative") == 1) { -// singleLoad(player); -// } -// } + // 装填 + if (stack.getItem() == ModItems.M_870.get() || stack.getItem() == ModItems.MARLIN.get()) { + if (tag.getInt("iterative") == 3) { + singleLoad(player); + } + } + + if (stack.getItem() == ModItems.SECONDARY_CATACLYSM.get()) { + if (tag.getInt("iterative") == 16) { + singleLoad(player); + } + } + + if (stack.getItem() == ModItems.K_98.get() || stack.getItem() == ModItems.MOSIN_NAGANT.get()) { + if (tag.getInt("iterative") == 1) { + singleLoad(player); + } + } // 二阶段结束 if (tag.getInt("iterative") == 1) { @@ -715,10 +701,9 @@ public class GunEventHandler { playGunEndReloadSounds(player); } - // todo marlin -// if (stack.getItem() == ModItems.MARLIN.get() && tag.getInt("finish") == 10) { -// tag.putBoolean("empty", false); -// } + if (stack.getItem() == ModItems.MARLIN.get() && tag.getInt("finish") == 10) { + tag.putBoolean("empty", false); + } // 三阶段结束 if (tag.getInt("finish") == 1) { @@ -729,8 +714,7 @@ public class GunEventHandler { GunsTool.setGunBooleanTag(stack, "Reloading", false); tag.putBoolean("start_single_reload", false); - // todo reload event -// NeoForge.EVENT_BUS.post(new ReloadEvent.Post(player, stack)); + NeoForge.EVENT_BUS.post(new ReloadEvent.Post(player, stack)); } saveTag(stack, tag); } @@ -754,13 +738,10 @@ public class GunEventHandler { AmmoType.RIFLE.add(cap, -1); } else if (stack.is(ModTags.Items.USE_HEAVY_AMMO)) { AmmoType.HEAVY.add(cap, -1); + } else if (stack.getItem() == ModItems.SECONDARY_CATACLYSM.get()) { + player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.GRENADE_40MM.get(), 1, player.inventoryMenu.getCraftSlots()); } - // todo secondary -// } else if (stack.getItem() == ModItems.SECONDARY_CATACLYSM.get()) { -// player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.GRENADE_40MM.get(), 1, player.inventoryMenu.getCraftSlots()); -// } - cap.syncPlayerVariables(player); } } @@ -876,10 +857,9 @@ public class GunEventHandler { double shooterHeight = player.getEyePosition().distanceTo((Vec3.atLowerCornerOf(player.level().clip(new ClipContext(player.getEyePosition(), player.getEyePosition().add(new Vec3(0, -1, 0).scale(10)), ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)).getBlockPos()))); - // todo marlin -// if (stack.is(ModItems.MARLIN.get())) { -// ModUtils.queueServerWork((int) (5 + 1.5 * shooterHeight), () -> SoundTool.playLocalSound(serverPlayer, ModSounds.SHELL_CASING_NORMAL.get(), (float) Math.max(1.5 - 0.2 * shooterHeight, 0), 1)); -// } + if (stack.is(ModItems.MARLIN.get())) { + ModUtils.queueServerWork((int) (5 + 1.5 * shooterHeight), () -> SoundTool.playLocalSound(serverPlayer, ModSounds.SHELL_CASING_NORMAL.get(), (float) Math.max(1.5 - 0.2 * shooterHeight, 0), 1)); + } } } } diff --git a/src/main/java/com/atsuishio/superbwarfare/event/HitboxHelperEvent.java b/src/main/java/com/atsuishio/superbwarfare/event/HitboxHelperEvent.java new file mode 100644 index 000000000..2b7b3ac0c --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/event/HitboxHelperEvent.java @@ -0,0 +1,24 @@ +package com.atsuishio.superbwarfare.event; + +import com.atsuishio.superbwarfare.tools.HitboxHelper; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import net.neoforged.neoforge.event.tick.PlayerTickEvent; + +@EventBusSubscriber +public class HitboxHelperEvent { + @SubscribeEvent(receiveCanceled = true) + public static void onPlayerTick(PlayerTickEvent.Post event) { + if (FMLEnvironment.dist == Dist.DEDICATED_SERVER) { + HitboxHelper.onPlayerTick(event.getEntity()); + } + } + + @SubscribeEvent(receiveCanceled = true) + public static void onPlayerLoggedOut(PlayerEvent.PlayerLoggedOutEvent event) { + HitboxHelper.onPlayerLoggedOut(event.getEntity()); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/event/KillMessageHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/KillMessageHandler.java new file mode 100644 index 000000000..c8790d772 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/event/KillMessageHandler.java @@ -0,0 +1,29 @@ +package com.atsuishio.superbwarfare.event; + +import com.atsuishio.superbwarfare.tools.PlayerKillRecord; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.ClientTickEvent; + +import java.util.ArrayDeque; +import java.util.Queue; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) +public class KillMessageHandler { + + public static Queue QUEUE = new ArrayDeque<>(); + + @SubscribeEvent + public static void onClientTick(ClientTickEvent.Post event) { + for (PlayerKillRecord record : QUEUE) { + if (record.freeze && record.tick >= 3) { + continue; + } + record.tick++; + if (record.fastRemove && record.tick >= 82 || record.tick >= 100) { + QUEUE.poll(); + } + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/event/LivingEventHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/LivingEventHandler.java new file mode 100644 index 000000000..fb0c3ddb1 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/event/LivingEventHandler.java @@ -0,0 +1,881 @@ +package com.atsuishio.superbwarfare.event; + +import com.atsuishio.superbwarfare.capability.ModCapabilities; +import com.atsuishio.superbwarfare.capability.player.PlayerVariable; +import com.atsuishio.superbwarfare.config.common.GameplayConfig; +import com.atsuishio.superbwarfare.config.server.MiscConfig; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.entity.ICustomKnockback; +import com.atsuishio.superbwarfare.entity.TargetEntity; +import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity; +import com.atsuishio.superbwarfare.entity.vehicle.LaserTowerEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ContainerMobileVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.event.events.PreKillEvent; +import com.atsuishio.superbwarfare.init.*; +import com.atsuishio.superbwarfare.item.gun.GunItem; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.perk.AmmoPerk; +import com.atsuishio.superbwarfare.perk.Perk; +import com.atsuishio.superbwarfare.perk.PerkHelper; +import com.atsuishio.superbwarfare.tools.*; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundStopSoundPacket; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.DamageType; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.Projectile; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.block.entity.HopperBlockEntity; +import net.minecraftforge.event.entity.living.*; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.common.util.TriState; +import net.neoforged.neoforge.event.entity.living.*; +import net.neoforged.neoforge.event.entity.player.ItemEntityPickupEvent; +import net.neoforged.neoforge.network.PacketDistributor; + +import java.util.Objects; + +@EventBusSubscriber +public class LivingEventHandler { + + @SubscribeEvent + public static void onEntityAttacked(LivingIncomingDamageEvent event) { + if (!event.getSource().is(ModDamageTypes.VEHICLE_EXPLOSION) && event.getEntity().getVehicle() instanceof VehicleEntity vehicle) { + if (event.getEntity().getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.hidePassenger(event.getEntity())) { + if (!(event.getSource().is(DamageTypes.EXPLOSION) + || event.getSource().is(DamageTypes.PLAYER_EXPLOSION) + || event.getSource().is(ModDamageTypes.CUSTOM_EXPLOSION) + || event.getSource().is(ModDamageTypes.MINE) + || event.getSource().is(ModDamageTypes.PROJECTILE_BOOM))) { + vehicle.hurt(event.getSource(), event.getContainer().getOriginalDamage()); + } + event.setCanceled(true); + } + } + } + + @SubscribeEvent + public static void onEntityHurt(LivingIncomingDamageEvent event) { + if (event == null) return; + + handleVehicleHurt(event); + handleGunPerksWhenHurt(event); + renderDamageIndicator(event); + reduceBulletDamage(event); + giveExpToWeapon(event); + handleGunLevels(event); + } + + @SubscribeEvent + public static void onEntityDeath(LivingDeathEvent event) { + if (event == null) return; + + killIndication(event); + handleGunPerksWhenDeath(event); + handlePlayerKillEntity(event); + handlePlayerDeathDropAmmo(event.getEntity()); + giveKillExpToWeapon(event); + + if (event.getEntity() instanceof Player player) { + handlePlayerBeamReset(player); + } + } + + private static void handleVehicleHurt(LivingIncomingDamageEvent event) { + var vehicle = event.getEntity().getVehicle(); + if (vehicle instanceof VehicleEntity) { + if (vehicle instanceof ArmedVehicleEntity iArmedVehicle) { + if (iArmedVehicle.hidePassenger(event.getEntity())) { + if (!event.getSource().is(ModDamageTypes.VEHICLE_EXPLOSION)) { + event.setCanceled(true); + } + } else { + if (!(event.getSource().is(DamageTypes.EXPLOSION) + || event.getSource().is(DamageTypes.PLAYER_EXPLOSION) + || event.getSource().is(ModDamageTypes.CUSTOM_EXPLOSION) + || event.getSource().is(ModDamageTypes.MINE) + || event.getSource().is(ModDamageTypes.PROJECTILE_BOOM))) { + vehicle.hurt(event.getSource(), 0.7f * event.getAmount()); + } + + event.setAmount(0.3f * event.getAmount()); + } + } + } + } + + /** + * 计算子弹伤害衰减 + */ + private static void reduceBulletDamage(LivingIncomingDamageEvent event) { + DamageSource source = event.getSource(); + LivingEntity entity = event.getEntity(); + Entity sourceEntity = source.getEntity(); + if (sourceEntity == null) return; + + double amount = event.getAmount(); + double damage = amount; + + ItemStack stack = sourceEntity instanceof LivingEntity living ? living.getMainHandItem() : ItemStack.EMPTY; + var perk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); + + // 距离衰减 + if (DamageTypeTool.isGunDamage(source)) { + double distance = entity.position().distanceTo(sourceEntity.position()); + + if (stack.is(ModTags.Items.USE_SHOTGUN_AMMO)) { + if (perk instanceof AmmoPerk ammoPerk && ammoPerk.slug) { + damage = reduceDamageByDistance(amount, distance, 0.015, 30); + } else { + damage = reduceDamageByDistance(amount, distance, 0.05, 15); + } + } else if (stack.is(ModTags.Items.USE_SNIPER_AMMO)) { + damage = reduceDamageByDistance(amount, distance, 0.001, 150); + } else if (stack.is(ModTags.Items.USE_HEAVY_AMMO)) { + damage = reduceDamageByDistance(amount, distance, 0.0007, 250); + } else if (stack.is(ModTags.Items.USE_HANDGUN_AMMO)) { + damage = reduceDamageByDistance(amount, distance, 0.03, 40); + } else if (stack.is(ModTags.Items.SMG)) { + damage = reduceDamageByDistance(amount, distance, 0.02, 50); + } else if (stack.is(ModTags.Items.USE_RIFLE_AMMO) || stack.getItem() == ModItems.BOCEK.get()) { + damage = reduceDamageByDistance(amount, distance, 0.007, 100); + } + } + + // 计算防弹插板减伤 + ItemStack armor = entity.getItemBySlot(EquipmentSlot.CHEST); + var tag = NBTTool.getTag(armor); + + if (armor != ItemStack.EMPTY && tag != null && tag.contains("ArmorPlate")) { + double armorValue; + armorValue = tag.getDouble("ArmorPlate"); + tag.putDouble("ArmorPlate", Math.max(tag.getDouble("ArmorPlate") - damage, 0)); + damage = Math.max(damage - armorValue, 0); + } + + // 计算防弹护具减伤 + if (source.is(ModTags.DamageTypes.PROJECTILE) || source.is(DamageTypes.MOB_PROJECTILE)) { + damage *= 1 - 0.8 * Mth.clamp(entity.getAttributeValue(ModAttributes.BULLET_RESISTANCE), 0, 1); + } + + if (source.is(ModTags.DamageTypes.PROJECTILE_ABSOLUTE)) { + damage *= 1 - 0.2 * Mth.clamp(entity.getAttributeValue(ModAttributes.BULLET_RESISTANCE), 0, 1); + } + + if (source.is(ModDamageTypes.PROJECTILE_BOOM) || source.is(ModDamageTypes.MINE) || source.is(ModDamageTypes.CANNON_FIRE) || source.is(ModDamageTypes.CUSTOM_EXPLOSION) + || source.is(DamageTypes.EXPLOSION) || source.is(DamageTypes.PLAYER_EXPLOSION)) { + damage *= 1 - 0.3 * Mth.clamp(entity.getAttributeValue(ModAttributes.BULLET_RESISTANCE), 0, 1); + } + + event.setAmount((float) damage); + + if (entity instanceof TargetEntity && sourceEntity instanceof Player player) { + player.displayClientMessage(Component.translatable("tips.superbwarfare.target.damage", + FormatTool.format2D(damage), + FormatTool.format1D(entity.position().distanceTo(sourceEntity.position())), "m"), false); + } + } + + private static double reduceDamageByDistance(double amount, double distance, double rate, double minDistance) { + return amount / (1 + rate * Math.max(0, distance - minDistance)); + } + + /** + * 根据造成的伤害,提供武器经验 + */ + private static void giveExpToWeapon(LivingIncomingDamageEvent event) { + DamageSource source = event.getSource(); + Entity sourceEntity = source.getEntity(); + if (!(sourceEntity instanceof Player player)) return; + ItemStack stack = player.getMainHandItem(); + if (!stack.is(ModTags.Items.GUN)) return; + if (event.getEntity() instanceof TargetEntity) return; + + double amount = Math.min(0.125 * event.getAmount(), event.getEntity().getMaxHealth()); + + // 先处理发射器类武器或高爆弹的爆炸伤害 + if (source.is(ModDamageTypes.PROJECTILE_BOOM)) { + if (stack.is(ModTags.Items.LAUNCHER) + // TODO perk +// || PerkHelper.getItemPerkLevel(ModPerks.HE_BULLET.get(), stack) > 0 + ) { + GunsTool.setGunDoubleTag(stack, "Exp", GunsTool.getGunDoubleTag(stack, "Exp", 0) + amount); + } + } + + // 再判断是不是枪械能造成的伤害 + if (!DamageTypeTool.isGunDamage(source)) return; + + GunsTool.setGunDoubleTag(stack, "Exp", GunsTool.getGunDoubleTag(stack, "Exp", 0) + amount); + } + + private static void giveKillExpToWeapon(LivingDeathEvent event) { + DamageSource source = event.getSource(); + Entity sourceEntity = source.getEntity(); + if (!(sourceEntity instanceof Player player)) return; + ItemStack stack = player.getMainHandItem(); + if (!stack.is(ModTags.Items.GUN)) return; + if (event.getEntity() instanceof TargetEntity) return; + + double amount = 20 + 2 * event.getEntity().getMaxHealth(); + + // 先处理发射器类武器或高爆弹的爆炸伤害 + if (source.is(ModDamageTypes.PROJECTILE_BOOM)) { + if (stack.is(ModTags.Items.LAUNCHER) + // TODO perk +// || PerkHelper.getItemPerkLevel(ModPerks.HE_BULLET.get(), stack) > 0 + ) { + GunsTool.setGunDoubleTag(stack, "Exp", GunsTool.getGunDoubleTag(stack, "Exp", 0) + amount); + } + } + + // 再判断是不是枪械能造成的伤害 + if (DamageTypeTool.isGunDamage(source)) { + GunsTool.setGunDoubleTag(stack, "Exp", GunsTool.getGunDoubleTag(stack, "Exp", 0) + amount); + } + + // 提升武器等级 + int level = GunsTool.getGunIntTag(stack, "Level", 0); + double exp = GunsTool.getGunDoubleTag(stack, "Exp", 0); + double upgradeExpNeeded = 20 * Math.pow(level, 2) + 160 * level + 20; + + while (exp >= upgradeExpNeeded) { + exp -= upgradeExpNeeded; + level = GunsTool.getGunIntTag(stack, "Level", 0) + 1; + upgradeExpNeeded = 20 * Math.pow(level, 2) + 160 * level + 20; + GunsTool.setGunDoubleTag(stack, "Exp", exp); + GunsTool.setGunIntTag(stack, "Level", level); + GunsTool.setGunDoubleTag(stack, "UpgradePoint", GunsTool.getGunDoubleTag(stack, "UpgradePoint", 0) + 0.5); + } + } + + private static void handleGunLevels(LivingIncomingDamageEvent event) { + DamageSource source = event.getSource(); + Entity sourceEntity = source.getEntity(); + if (!(sourceEntity instanceof Player player)) return; + ItemStack stack = player.getMainHandItem(); + if (!stack.is(ModTags.Items.GUN)) return; + if (event.getEntity() instanceof TargetEntity) return; + + int level = GunsTool.getGunIntTag(stack, "Level", 0); + double exp = GunsTool.getGunDoubleTag(stack, "Exp", 0); + double upgradeExpNeeded = 20 * Math.pow(level, 2) + 160 * level + 20; + + while (exp >= upgradeExpNeeded) { + exp -= upgradeExpNeeded; + level = GunsTool.getGunIntTag(stack, "Level", 0) + 1; + upgradeExpNeeded = 20 * Math.pow(level, 2) + 160 * level + 20; + GunsTool.setGunDoubleTag(stack, "Exp", exp); + GunsTool.setGunIntTag(stack, "Level", level); + GunsTool.setGunDoubleTag(stack, "UpgradePoint", GunsTool.getGunDoubleTag(stack, "UpgradePoint", 0) + 0.5); + } + } + + private static void killIndication(LivingDeathEvent event) { + DamageSource source = event.getSource(); + + var sourceEntity = source.getEntity(); + if (sourceEntity == null) { + return; + } + + // 如果配置不选择全局伤害提示,则只在伤害类型为mod添加的时显示指示器 + if (!GameplayConfig.GLOBAL_INDICATION.get() && !DamageTypeTool.isModDamage(source)) { + return; + } + + if (!sourceEntity.level().isClientSide() && sourceEntity instanceof ServerPlayer player) { + // TODO pre kill event +// if (NeoForge.EVENT_BUS.post(new PreKillEvent.Indicator(player, source, event.getEntity()))) { +// return; +// } + + SoundTool.playLocalSound(player, ModSounds.TARGET_DOWN.get(), 3f, 1f); + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(2, 8)); + } + } + + private static void renderDamageIndicator(LivingIncomingDamageEvent event) { + if (event == null) return; + + var damagesource = event.getSource(); + var sourceEntity = damagesource.getEntity(); + + if (sourceEntity == null) return; + + if (sourceEntity instanceof ServerPlayer player && (damagesource.is(DamageTypes.EXPLOSION) || damagesource.is(DamageTypes.PLAYER_EXPLOSION) + || damagesource.is(ModDamageTypes.MINE) || damagesource.is(ModDamageTypes.PROJECTILE_BOOM))) { + SoundTool.playLocalSound(player, ModSounds.INDICATION.get(), 1f, 1f); + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5)); + } + } + + /** + * 换弹时切换枪械,取消换弹音效播放 + */ + @SubscribeEvent + public static void handleChangeSlot(LivingEquipmentChangeEvent event) { + if (event.getEntity() instanceof Player player && event.getSlot() == EquipmentSlot.MAINHAND) { + if (player.level().isClientSide) { + return; + } + + ItemStack oldStack = event.getFrom(); + ItemStack newStack = event.getTo(); + + var laserCap = player.getCapability(ModCapabilities.LASER_CAPABILITY); + if (laserCap != null) laserCap.stop(); + + var oldTag = NBTTool.getTag(oldStack); + var newTag = NBTTool.getTag(newStack); + if (player instanceof ServerPlayer serverPlayer) { + if (newStack.getItem() != oldStack.getItem() + || (newStack.is(ModTags.Items.GUN) && !GunsTool.getGunData(newStack).hasUUID("UUID")) + || (oldStack.is(ModTags.Items.GUN) && !GunsTool.getGunData(oldStack).hasUUID("UUID")) + || (newStack.is(ModTags.Items.GUN) && oldStack.is(ModTags.Items.GUN) && !Objects.equals(GunsTool.getGunUUID(newStack), GunsTool.getGunUUID(oldStack))) + ) { + if (oldStack.getItem() instanceof GunItem oldGun) { + stopGunReloadSound(serverPlayer, oldGun); + + CompoundTag data = oldTag.getCompound("GunData"); + + if (GunsTool.getGunDoubleTag(oldStack, "BoltActionTime", 0) > 0) { + data.putInt("BoltActionTick", 0); + } + + data.putInt("ReloadTime", 0); + oldTag.put("GunData", data); + + oldTag.putBoolean("is_normal_reloading", false); + oldTag.putBoolean("is_empty_reloading", false); + + if (GunsTool.getGunIntTag(oldStack, "IterativeTime", 0) != 0) { + oldTag.putBoolean("force_stop", false); + oldTag.putBoolean("stop", false); + oldTag.putInt("reload_stage", 0); + data.putBoolean("Reloading", false); + oldTag.putDouble("prepare", 0); + oldTag.putDouble("prepare_load", 0); + oldTag.putDouble("iterative", 0); + oldTag.putDouble("finish", 0); + } + NBTTool.saveTag(oldStack, oldTag); + + if (oldStack.is(ModItems.SENTINEL.get())) { + data.putBoolean("Charging", false); + data.putInt("ChargeTime", 0); + } + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap != null) { + cap.edit = false; + cap.syncPlayerVariables(player); + } + } + + if (newStack.getItem() instanceof GunItem) { + player.getPersistentData().putDouble("noRun", 40); + newTag.putBoolean("draw", true); + if (GunsTool.getGunIntTag(newStack, "BoltActionTime", 0) > 0) { + GunsTool.setGunIntTag(newStack, "BoltActionTick", 0); + } + newTag.putBoolean("is_normal_reloading", false); + newTag.putBoolean("is_empty_reloading", false); + + CompoundTag data = newTag.getCompound("GunData"); + data.putInt("ReloadTime", 0); + newTag.put("GunData", data); + + if (GunsTool.getGunIntTag(newStack, "IterativeTime", 0) != 0) { + newTag.putBoolean("force_stop", false); + newTag.putBoolean("stop", false); + newTag.putInt("reload_stage", 0); + GunsTool.setGunBooleanTag(newStack, "Reloading", false); + newTag.putDouble("prepare", 0); + newTag.putDouble("prepare_load", 0); + newTag.putDouble("iterative", 0); + newTag.putDouble("finish", 0); + } + + if (newStack.is(ModItems.SENTINEL.get())) { + GunsTool.setGunBooleanTag(newStack, "Charging", false); + GunsTool.setGunIntTag(newStack, "ChargeTime", 0); + } + NBTTool.saveTag(newStack, newTag); + + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.KILLING_TALLY.get(), newStack); +// if (level != 0) { +// GunsTool.setPerkIntTag(newStack, "KillingTally", 0); +// } +// +// if (player.level() instanceof ServerLevel) { +// ModUtils.PACKET_HANDLER.send(PacketDistributor.PLAYER.with(() -> serverPlayer), new DrawClientMessage(true)); +// } + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap != null) { + cap.tacticalSprint = false; + cap.syncPlayerVariables(player); + } + } + } + } + } + } + + private static void stopGunReloadSound(ServerPlayer player, GunItem gun) { + gun.getReloadSound().forEach(sound -> { + var clientboundstopsoundpacket = new ClientboundStopSoundPacket(sound.getLocation(), SoundSource.PLAYERS); + player.connection.send(clientboundstopsoundpacket); + }); + } + + /** + * 发送击杀消息 + */ + private static void handlePlayerKillEntity(LivingDeathEvent event) { + LivingEntity entity = event.getEntity(); + DamageSource source = event.getSource(); + + ResourceKey damageTypeResourceKey = source.typeHolder().unwrapKey().isPresent() ? source.typeHolder().unwrapKey().get() : DamageTypes.GENERIC; + + ServerPlayer attacker = null; + if (source.getEntity() instanceof ServerPlayer player) { + attacker = player; + } + if (source.getDirectEntity() instanceof Projectile projectile && projectile.getOwner() instanceof ServerPlayer player) { + attacker = player; + } + + // TODO pre kill event +// if (NeoForge.EVENT_BUS.post(new PreKillEvent.SendKillMessage(attacker, source, entity))) { +// return; +// } + + if (attacker != null && MiscConfig.SEND_KILL_FEEDBACK.get()) { + if (DamageTypeTool.isHeadshotDamage(source)) { + // TODO player gun kill msg +// ModUtils.PACKET_HANDLER.send(PacketDistributor.ALL.noArg(), new PlayerGunKillMessage(attacker.getId(), entity.getId(), true, damageTypeResourceKey)); + } else { +// ModUtils.PACKET_HANDLER.send(PacketDistributor.ALL.noArg(), new PlayerGunKillMessage(attacker.getId(), entity.getId(), false, damageTypeResourceKey)); + } + } + } + + private static void handleGunPerksWhenHurt(LivingIncomingDamageEvent event) { + DamageSource source = event.getSource(); + + Player attacker = null; + if (source.getEntity() instanceof Player player) { + attacker = player; + } + if (source.getDirectEntity() instanceof Projectile projectile && projectile.getOwner() instanceof Player player) { + attacker = player; + } + + if (attacker == null) { + return; + } + + ItemStack stack = attacker.getMainHandItem(); + if (!stack.is(ModTags.Items.GUN)) { + return; + } + + if (DamageTypeTool.isGunDamage(source) || source.is(ModDamageTypes.PROJECTILE_BOOM)) { + handleKillClipDamage(stack, event); + handleVorpalWeaponDamage(stack, event); + } + + if (DamageTypeTool.isGunFireDamage(source) && source.getDirectEntity() instanceof ProjectileEntity projectile && projectile.isZoom()) { + handleGutshotStraightDamage(stack, event); + } + + if (DamageTypeTool.isGunDamage(source)) { + handleKillingTallyDamage(stack, event); + } + + if (DamageTypeTool.isGunFireDamage(source)) { + handleHeadSeekerTime(stack); + } + + if (source.getDirectEntity() instanceof ProjectileEntity projectile) { + // TODO perk +// if (PerkHelper.getItemPerkLevel(ModPerks.FOURTH_TIMES_CHARM.get(), stack) > 0) { +// float bypassArmorRate = projectile.getBypassArmorRate(); +// if (bypassArmorRate >= 1.0f && source.is(ModDamageTypes.GUN_FIRE_HEADSHOT_ABSOLUTE)) { +// handleFourthTimesCharm(stack); +// } else if (source.is(ModDamageTypes.GUN_FIRE_HEADSHOT)) { +// handleFourthTimesCharm(stack); +// } +// } + + if (!projectile.isZoom()) { + handleFieldDoctor(stack, event, attacker); + } + } + + if (DamageTypeTool.isHeadshotDamage(source)) { + handleHeadSeekerDamage(stack, event); + } + } + + private static void handleGunPerksWhenDeath(LivingDeathEvent event) { + DamageSource source = event.getSource(); + + Player attacker = null; + if (source.getEntity() instanceof Player player) { + attacker = player; + } + if (source.getDirectEntity() instanceof Projectile projectile && projectile.getOwner() instanceof Player player) { + attacker = player; + } + + if (attacker == null) { + return; + } + + ItemStack stack = attacker.getMainHandItem(); + if (!stack.is(ModTags.Items.GUN)) { + return; + } + + if (DamageTypeTool.isGunDamage(source) || source.is(ModDamageTypes.PROJECTILE_BOOM)) { + handleClipPerks(stack); + } + + if (DamageTypeTool.isGunDamage(source)) { + handleKillingTallyAddCount(stack); + handleSubsistence(stack, attacker); + } + + if (DamageTypeTool.isHeadshotDamage(source)) { + handleDesperado(stack); + } + } + + private static void handleClipPerks(ItemStack stack) { + // TODO perk +// int healClipLevel = PerkHelper.getItemPerkLevel(ModPerks.HEAL_CLIP.get(), stack); +// if (healClipLevel != 0) { +// GunsTool.setPerkIntTag(stack, "HealClipTime", 80 + healClipLevel * 20); +// } +// +// int killClipLevel = PerkHelper.getItemPerkLevel(ModPerks.KILL_CLIP.get(), stack); +// if (killClipLevel != 0) { +// GunsTool.setPerkIntTag(stack, "KillClipReloadTime", 80); +// } + } + + private static void handleKillClipDamage(ItemStack stack, LivingIncomingDamageEvent event) { + // TODO perk +// if (GunsTool.getPerkIntTag(stack, "KillClipTime") > 0) { +// int level = PerkHelper.getItemPerkLevel(ModPerks.KILL_CLIP.get(), stack); +// if (level == 0) { +// return; +// } +// +// event.setAmount(event.getAmount() * (1.2f + 0.05f * level)); +// } + } + + private static void handleGutshotStraightDamage(ItemStack stack, LivingIncomingDamageEvent event) { + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.GUTSHOT_STRAIGHT.get(), stack); +// if (level == 0) { +// return; +// } + +// event.setAmount(event.getAmount() * (1.15f + 0.05f * level)); + } + + private static void handleKillingTallyDamage(ItemStack stack, LivingIncomingDamageEvent event) { + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.KILLING_TALLY.get(), stack); +// if (level == 0) { +// return; +// } +// +// int killTally = GunsTool.getPerkIntTag(stack, "KillingTally"); +// if (killTally == 0) { +// return; +// } +// +// event.setAmount(event.getAmount() * (1.0f + (0.1f * level) * killTally)); + } + + private static void handleKillingTallyAddCount(ItemStack stack) { + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.KILLING_TALLY.get(), stack); +// if (level != 0) { +// GunsTool.setPerkIntTag(stack, "KillingTally", Math.min(3, GunsTool.getPerkIntTag(stack, "KillingTally") + 1)); +// } + } + + private static void handleFourthTimesCharm(ItemStack stack) { + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.FOURTH_TIMES_CHARM.get(), stack); +// if (level == 0) { +// return; +// } +// +// int fourthTimesCharmTick = GunsTool.getPerkIntTag(stack, "FourthTimesCharmTick"); +// if (fourthTimesCharmTick <= 0) { +// GunsTool.setPerkIntTag(stack, "FourthTimesCharmTick", 40 + 10 * level); +// GunsTool.setPerkIntTag(stack, "FourthTimesCharmCount", 1); +// } else { +// int count = GunsTool.getPerkIntTag(stack, "FourthTimesCharmCount"); +// if (count < 4) { +// GunsTool.setPerkIntTag(stack, "FourthTimesCharmCount", Math.min(4, count + 1)); +// } +// } + } + + private static void handleSubsistence(ItemStack stack, Player player) { + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.SUBSISTENCE.get(), stack); +// if (level == 0) { +// return; +// } +// +// float rate = level * 0.1f + (stack.is(ModTags.Items.SMG) || stack.is(ModTags.Items.RIFLE) ? 0.07f : 0f); + float rate = 1; + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) return; + + int mag = GunsTool.getGunIntTag(stack, "Magazine", 0) + GunsTool.getGunIntTag(stack, "CustomMagazine", 0); + int ammo = GunsTool.getGunIntTag(stack, "Ammo", 0); + int ammoReload = (int) Math.min(mag, mag * rate); + int ammoNeed = Math.min(mag - ammo, ammoReload); + + boolean flag = InventoryTool.hasCreativeAmmoBox(player); + + if (stack.is(ModTags.Items.USE_RIFLE_AMMO)) { + int ammoFinal = Math.min(cap.rifleAmmo, ammoNeed); + if (flag) { + ammoFinal = ammoNeed; + } else { + cap.rifleAmmo -= ammoFinal; + } + GunsTool.setGunIntTag(stack, "Ammo", Math.min(mag, ammo + ammoFinal)); + } else if (stack.is(ModTags.Items.USE_HANDGUN_AMMO)) { + int ammoFinal = Math.min(cap.handgunAmmo, ammoNeed); + if (flag) { + ammoFinal = ammoNeed; + } else { + cap.handgunAmmo -= ammoFinal; + } + GunsTool.setGunIntTag(stack, "Ammo", Math.min(mag, ammo + ammoFinal)); + } + cap.syncPlayerVariables(player); + } + + + private static void handleFieldDoctor(ItemStack stack, LivingIncomingDamageEvent event, Player player) { + // TODO perk + // int level = PerkHelper.getItemPerkLevel(ModPerks.FIELD_DOCTOR.get(), stack); + // if (level == 0) { + // return; + // } + // + // if (event.getEntity().isAlliedTo(player)) { + // event.getEntity().heal(event.getAmount() * Math.min(1.0f, 0.25f + 0.05f * level)); + // event.setCanceled(true); + // } + } + + private static void handleHeadSeekerTime(ItemStack stack) { + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.HEAD_SEEKER.get(), stack); +// if (level == 0) { +// return; +// } +// +// GunsTool.setPerkIntTag(stack, "HeadSeeker", 11 + level * 2); + } + + private static void handleHeadSeekerDamage(ItemStack stack, LivingIncomingDamageEvent event) { + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.HEAD_SEEKER.get(), stack); +// if (level == 0) { +// return; +// } +// +// if (GunsTool.getPerkIntTag(stack, "HeadSeeker") > 0) { +// event.setAmount(event.getAmount() * (1.095f + 0.0225f * level)); +// } + } + + private static void handleDesperado(ItemStack stack) { + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.DESPERADO.get(), stack); +// if (level == 0) { +// return; +// } +// +// GunsTool.setPerkIntTag(stack, "DesperadoTime", 90 + level * 10); + } + + /** + * 开启死亡掉落时掉落一个弹药盒 + */ + private static void handlePlayerDeathDropAmmo(LivingEntity entity) { + if (!entity.level().getLevelData().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && entity instanceof Player player) { + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) cap = new PlayerVariable(); + + boolean drop = cap.rifleAmmo + cap.handgunAmmo + cap.shotgunAmmo + cap.sniperAmmo + cap.heavyAmmo > 0; + + if (drop) { + ItemStack stack = new ItemStack(ModItems.AMMO_BOX.get()); + CompoundTag tag = NBTTool.getTag(stack); + + for (var type : AmmoType.values()) { + type.set(tag, type.get(cap)); + type.set(cap, 0); + } + tag.putBoolean("IsDrop", true); + NBTTool.saveTag(stack, tag); + cap.syncPlayerVariables(player); + + if (player.level() instanceof ServerLevel level) { + ItemEntity itemEntity = new ItemEntity(level, player.getX(), player.getY() + 1, player.getZ(), stack); + itemEntity.setPickUpDelay(10); + level.addFreshEntity(itemEntity); + } + } + } + } + + @SubscribeEvent + public static void onPickup(ItemEntityPickupEvent.Pre event) { + if (!VehicleConfig.VEHICLE_ITEM_PICKUP.get()) return; + if (event.getPlayer().getVehicle() instanceof ContainerMobileVehicleEntity containerMobileVehicleEntity) { + var pickUp = event.getItemEntity(); + if (!containerMobileVehicleEntity.level().isClientSide) { + HopperBlockEntity.addItem(containerMobileVehicleEntity, pickUp); + } + event.setCanPickup(TriState.FALSE); + } + } + + @SubscribeEvent + public static void onLivingDrops(LivingDropsEvent event) { + DamageSource source = event.getSource(); + Entity sourceEntity = source.getEntity(); + if (!(sourceEntity instanceof Player player)) return; + ItemStack stack = player.getMainHandItem(); + + if (player.getVehicle() instanceof ContainerMobileVehicleEntity containerMobileVehicleEntity && source.is(ModDamageTypes.VEHICLE_STRIKE)) { + var drops = event.getDrops(); + drops.forEach(itemEntity -> { + ItemStack item = itemEntity.getItem(); + if (!HopperBlockEntity.addItem(containerMobileVehicleEntity, itemEntity)) { + player.drop(item, false); + } + }); + event.setCanceled(true); + return; + } + + // TODO perk +// if (stack.is(ModTags.Items.GUN) && PerkHelper.getItemPerkLevel(ModPerks.POWERFUL_ATTRACTION.get(), stack) > 0 && (DamageTypeTool.isGunDamage(source) || DamageTypeTool.isExplosionDamage(source))) { +// var drops = event.getDrops(); +// drops.forEach(itemEntity -> { +// ItemStack item = itemEntity.getItem(); +// if (!player.addItem(item)) { +// player.drop(item, false); +// } +// }); +// event.setCanceled(true); +// } + } + + @SubscribeEvent + public static void onLivingExperienceDrop(LivingExperienceDropEvent event) { + Player player = event.getAttackingPlayer(); + if (player == null) return; + + if (player.getVehicle() instanceof ArmedVehicleEntity) { + player.giveExperiencePoints(event.getDroppedExperience()); + event.setCanceled(true); + return; + } + + ItemStack stack = player.getMainHandItem(); + if (!stack.is(ModTags.Items.GUN)) return; + + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.POWERFUL_ATTRACTION.get(), stack); +// if (level > 0) { +// player.giveExperiencePoints((int) (event.getDroppedExperience() * (0.8f + 0.2f * level))); +// +// event.setCanceled(true); +// } + } + + public static void handlePlayerBeamReset(Player player) { + var cap = player.getCapability(ModCapabilities.LASER_CAPABILITY); + if (cap != null) { + cap.end(); + } + } + + private static void handleVorpalWeaponDamage(ItemStack stack, LivingIncomingDamageEvent event) { + var entity = event.getEntity(); + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.VORPAL_WEAPON.get(), stack); + int level = 0; + if (level <= 0) return; + if (entity.getHealth() < 100.0f) return; + + event.setAmount((float) (event.getAmount() + entity.getHealth() * 0.00002f * Math.pow(level, 2))); + } + + @SubscribeEvent + public static void onKnockback(LivingKnockBackEvent event) { + ICustomKnockback knockback = ICustomKnockback.getInstance(event.getEntity()); + if (knockback.superbWarfare$getKnockbackStrength() >= 0) { + event.setStrength((float) knockback.superbWarfare$getKnockbackStrength()); + } + } + + @SubscribeEvent + public static void onEntityFall(LivingFallEvent event) { + LivingEntity living = event.getEntity(); + if (living.getVehicle() instanceof VehicleEntity) { + event.setCanceled(true); + } + } + + @SubscribeEvent + public static void onPreSendKillMessage(PreKillEvent.SendKillMessage event) { + if (event.getSource().getDirectEntity() instanceof LaserTowerEntity && !(event.getTarget() instanceof Player)) { + event.setCanceled(true); + } + } + + @SubscribeEvent + public static void onPreIndicator(PreKillEvent.Indicator event) { + if (event.getSource().getDirectEntity() instanceof LaserTowerEntity && !(event.getTarget() instanceof Player)) { + event.setCanceled(true); + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/event/PlayerEventHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/PlayerEventHandler.java new file mode 100644 index 000000000..d71764314 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/event/PlayerEventHandler.java @@ -0,0 +1,355 @@ +package com.atsuishio.superbwarfare.event; + +import com.atsuishio.superbwarfare.capability.ModCapabilities; +import com.atsuishio.superbwarfare.config.common.GameplayConfig; +import com.atsuishio.superbwarfare.config.server.MiscConfig; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.init.ModTags; +import com.atsuishio.superbwarfare.tools.*; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.AnvilUpdateEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import net.neoforged.neoforge.event.tick.PlayerTickEvent; + +@EventBusSubscriber +public class PlayerEventHandler { + @SubscribeEvent + public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) { + Player player = event.getEntity(); + ItemStack stack = player.getMainHandItem(); + var tag = NBTTool.getTag(stack); + if (stack.is(ModItems.MONITOR.get()) && tag.getBoolean("Using")) { + tag.putBoolean("Using", false); + NBTTool.saveTag(stack, tag); + } + for (ItemStack pStack : player.getInventory().items) { + if (pStack.is(ModTags.Items.GUN)) { + tag = NBTTool.getTag(pStack); + tag.putBoolean("draw", true); + tag.putBoolean("init", false); + NBTTool.saveTag(pStack, tag); + } + } + } + + @SubscribeEvent + public static void onPlayerRespawned(PlayerEvent.PlayerRespawnEvent event) { + Player player = event.getEntity(); + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap != null) { + cap.zoom = false; + cap.tacticalSprintExhaustion = false; + cap.tacticalSprintTime = 600; + cap.syncPlayerVariables(player); + } + + handleRespawnReload(player); + handleRespawnAutoArmor(player); + + for (ItemStack pStack : player.getInventory().items) { + if (pStack.is(ModTags.Items.GUN)) { + var tag = NBTTool.getTag(pStack); + tag.putBoolean("draw", true); + NBTTool.saveTag(pStack, tag); + } + } + } + + @SubscribeEvent + public static void onPlayerTick(PlayerTickEvent.Post event) { + Player player = event.getEntity(); + ItemStack stack = player.getMainHandItem(); + + if (stack.is(ModTags.Items.GUN)) { + handlePlayerSprint(player); + handleSpecialWeaponAmmo(player); + handleBocekPulling(player); + } + + handleGround(player); + handleSimulationDistance(player); + handleTacticalSprint(player); + handleBreath(player); + } + + private static void handleBreath(Player player) { + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) return; + + if (cap.breath) { + cap.breathTime = Mth.clamp(cap.breathTime - 1, 0, 100); + } else { + cap.breathTime = Mth.clamp(cap.breathTime + 1, 0, 100); + } + + if (cap.breathTime == 0) { + cap.breathExhaustion = true; + cap.breath = false; + } + + if (cap.breathTime == 100) { + cap.breathExhaustion = false; + } + + cap.syncPlayerVariables(player); + } + + private static void handleTacticalSprint(Player player) { + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) return; + + ItemStack stack = player.getMainHandItem(); + int sprintCost; + + if (stack.is(ModTags.Items.GUN)) { + double weight = GunsTool.getGunDoubleTag(stack, "Weight") + GunsTool.getGunDoubleTag(stack, "CustomWeight"); + sprintCost = (int) (5 + 0.2 * weight); + } else { + sprintCost = 5; + } + + if (!player.isSprinting()) { + cap.tacticalSprint = false; + player.getPersistentData().putBoolean("canTacticalSprint", true); + } + + if (player.isSprinting() + && !cap.tacticalSprintExhaustion + && player.getPersistentData().getBoolean("canTacticalSprint") + ) { + cap.tacticalSprint = true; + player.getPersistentData().putBoolean("canTacticalSprint", false); + } + + if (cap.tacticalSprint) { + cap.tacticalSprintTime = Mth.clamp(cap.tacticalSprintTime - sprintCost, 0, 1000); + + if (MiscConfig.ALLOW_TACTICAL_SPRINT.get()) { + player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SPEED, 2, 0, false, false)); + } + } else { + cap.tacticalSprintTime = Mth.clamp(cap.tacticalSprintTime + 7, 0, 1000); + } + + if (cap.tacticalSprintTime == 0) { + cap.tacticalSprintExhaustion = true; + cap.tacticalSprint = false; + } + + if (cap.tacticalSprintTime == 1000) { + cap.tacticalSprintExhaustion = false; + player.getPersistentData().putBoolean("canTacticalSprint", true); + } + + cap.syncPlayerVariables(player); + } + + /** + * 判断玩家是否在奔跑 + */ + private static void handlePlayerSprint(Player player) { + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) return; + + if (cap.holdFire) { + player.getPersistentData().putDouble("noRun", 10); + } + + if (player.isShiftKeyDown() + || player.isPassenger() + || player.isInWater() + || cap.zoom + ) player.getPersistentData().putDouble("noRun", 3); + + if (player.getPersistentData().getDouble("noRun") > 0) { + player.getPersistentData().putDouble("noRun", (player.getPersistentData().getDouble("noRun") - 1)); + } + + if (cap.zoom || cap.holdFire) { + player.setSprinting(false); + } + } + + private static void handleGround(Player player) { + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) return; + + if (player.onGround()) { + cap.playerDoubleJump = false; + cap.syncPlayerVariables(player); + } + } + + private static void handleSpecialWeaponAmmo(Player player) { + ItemStack stack = player.getMainHandItem(); + + if ((stack.is(ModItems.RPG.get()) || stack.is(ModItems.BOCEK.get())) && GunsTool.getGunIntTag(stack, "Ammo", 0) == 1) { + NBTTool.setDouble(stack, "empty", 0); + } + } + + private static void handleBocekPulling(Player player) { + ItemStack stack = player.getMainHandItem(); + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) return; + + if (cap.bowPullHold) { + if (stack.getItem() == ModItems.BOCEK.get() + && GunsTool.getGunIntTag(stack, "MaxAmmo") > 0 + && !player.getCooldowns().isOnCooldown(stack.getItem()) + && GunsTool.getGunDoubleTag(stack, "Power") < 12 + ) { + GunsTool.setGunDoubleTag(stack, "Power", GunsTool.getGunDoubleTag(stack, "Power") + 1); + + cap.bowPull = true; + cap.tacticalSprint = false; + cap.syncPlayerVariables(player); + player.setSprinting(false); + } + if (GunsTool.getGunDoubleTag(stack, "Power") == 1) { + if (!player.level().isClientSide() && player instanceof ServerPlayer serverPlayer) { + SoundTool.playLocalSound(serverPlayer, ModSounds.BOCEK_PULL_1P.get(), 2f, 1f); + player.level().playSound(null, player.blockPosition(), ModSounds.BOCEK_PULL_3P.get(), SoundSource.PLAYERS, 0.5f, 1); + } + } + } else { + if (stack.getItem() == ModItems.BOCEK.get()) { + GunsTool.setGunDoubleTag(stack, "Power", 0); + } + cap.bowPull = false; + cap.syncPlayerVariables(player); + } + + if (GunsTool.getGunDoubleTag(stack, "Power") > 0) { + cap.tacticalSprint = false; + cap.syncPlayerVariables(player); + player.setSprinting(false); + } + } + + private static void handleSimulationDistance(Player player) { + if (player.level() instanceof ServerLevel serverLevel && player instanceof ServerPlayer serverPlayer) { + // TODO send simulation distance to client +// var distanceManager = serverLevel.getChunkSource().chunkMap.getDistanceManager(); +// var playerTicketManager = distanceManager.playerTicketManager; +// int maxDistance = playerTicketManager.viewDistance; +// +// ModUtils.PACKET_HANDLER.send(PacketDistributor.PLAYER.with(() -> serverPlayer), new SimulationDistanceMessage(maxDistance)); + } + } + + private static void handleRespawnReload(Player player) { + if (!GameplayConfig.RESPAWN_RELOAD.get()) return; + + for (ItemStack stack : player.getInventory().items) { + if (stack.is(ModTags.Items.GUN)) { + if (!InventoryTool.hasCreativeAmmoBox(player)) { + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) return; + + if (stack.is(ModTags.Items.USE_SHOTGUN_AMMO) && cap.shotgunAmmo > 0) { + GunsTool.reload(player, stack, AmmoType.SHOTGUN); + } + if (stack.is(ModTags.Items.USE_SNIPER_AMMO) && cap.sniperAmmo > 0) { + GunsTool.reload(player, stack, AmmoType.SNIPER); + } + if (stack.is(ModTags.Items.USE_HANDGUN_AMMO) && cap.handgunAmmo > 0) { + GunsTool.reload(player, stack, AmmoType.HANDGUN); + } + if (stack.is(ModTags.Items.USE_RIFLE_AMMO) && cap.rifleAmmo > 0) { + GunsTool.reload(player, stack, AmmoType.RIFLE); + } + if (stack.is(ModTags.Items.USE_HEAVY_AMMO) && cap.heavyAmmo > 0) { + GunsTool.reload(player, stack, AmmoType.HEAVY); + } + + if (stack.getItem() == ModItems.TASER.get() && GunsTool.getGunIntTag(stack, "MaxAmmo") > 0 && GunsTool.getGunIntTag(stack, "Ammo", 0) == 0) { + GunsTool.setGunIntTag(stack, "Ammo", 1); + player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.TASER_ELECTRODE.get(), 1, player.inventoryMenu.getCraftSlots()); + } + if (stack.getItem() == ModItems.M_79.get() && GunsTool.getGunIntTag(stack, "MaxAmmo") > 0 && GunsTool.getGunIntTag(stack, "Ammo", 0) == 0) { + GunsTool.setGunIntTag(stack, "Ammo", 1); + player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.GRENADE_40MM.get(), 1, player.inventoryMenu.getCraftSlots()); + } + if (stack.getItem() == ModItems.RPG.get() && GunsTool.getGunIntTag(stack, "MaxAmmo") > 0 && GunsTool.getGunIntTag(stack, "Ammo", 0) == 0) { + GunsTool.setGunIntTag(stack, "Ammo", 1); + player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.ROCKET.get(), 1, player.inventoryMenu.getCraftSlots()); + } + if (stack.getItem() == ModItems.JAVELIN.get() && GunsTool.getGunIntTag(stack, "MaxAmmo") > 0 && GunsTool.getGunIntTag(stack, "Ammo", 0) == 0) { + GunsTool.setGunIntTag(stack, "Ammo", 1); + player.getInventory().clearOrCountMatchingItems(p -> p.getItem() == ModItems.JAVELIN_MISSILE.get(), 1, player.inventoryMenu.getCraftSlots()); + } + } else { + GunsTool.setGunIntTag(stack, "Ammo", GunsTool.getGunIntTag(stack, "Magazine", 0) + + GunsTool.getGunIntTag(stack, "CustomMagazine", 0)); + } + GunsTool.setGunBooleanTag(stack, "HoldOpen", false); + } + } + } + + private static void handleRespawnAutoArmor(Player player) { + if (!GameplayConfig.RESPAWN_AUTO_ARMOR.get()) return; + + ItemStack armor = player.getItemBySlot(EquipmentSlot.CHEST); + if (armor == ItemStack.EMPTY) return; + + var tag = NBTTool.getTag(armor); + double armorPlate = tag.getDouble("ArmorPlate"); + + int armorLevel = 1; + if (armor.is(ModTags.Items.MILITARY_ARMOR)) { + armorLevel = 2; + } else if (armor.is(ModTags.Items.MILITARY_ARMOR_HEAVY)) { + armorLevel = 3; + } + + if (armorPlate >= armorLevel * 15) return; + + for (var stack : player.getInventory().items) { + if (stack.is(ModItems.ARMOR_PLATE.get())) { + var stackTag = NBTTool.getTag(stack); + if (stackTag.getBoolean("Infinite")) { + tag.putDouble("ArmorPlate", armorLevel * 15); + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), SoundEvents.ARMOR_EQUIP_IRON.value(), SoundSource.PLAYERS, 0.5f, 1); + } + } else { + for (int index0 = 0; index0 < Math.ceil(((armorLevel * 15) - armorPlate) / 15); index0++) { + stack.finishUsingItem(player.level(), player); + } + } + } + } + } + + @SubscribeEvent + public static void onAnvilUpdate(AnvilUpdateEvent event) { + ItemStack left = event.getLeft(); + ItemStack right = event.getRight(); + + if (left.is(ModTags.Items.GUN) && right.getItem() == ModItems.SHORTCUT_PACK.get()) { + ItemStack output = left.copy(); + + GunsTool.setGunDoubleTag(output, "UpgradePoint", GunsTool.getGunDoubleTag(output, "UpgradePoint", 0) + 1); + + event.setOutput(output); + event.setCost(10); + event.setMaterialCost(1); + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/event/ReloadEventHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/ReloadEventHandler.java new file mode 100644 index 000000000..4e4eb383c --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/event/ReloadEventHandler.java @@ -0,0 +1,126 @@ +package com.atsuishio.superbwarfare.event; + +import com.atsuishio.superbwarfare.event.events.ReloadEvent; +import com.atsuishio.superbwarfare.init.ModTags; +import com.atsuishio.superbwarfare.tools.GunsTool; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; + +@EventBusSubscriber +public class ReloadEventHandler { + + @SubscribeEvent + public static void onPreReload(ReloadEvent.Pre event) { + Player player = event.player; + ItemStack stack = event.stack; + if (player == null || !stack.is(ModTags.Items.GUN)) { + return; + } + + if (player.level().isClientSide) { + return; + } + + handleHealClipPre(stack); + handleKillClipPre(stack); + handleKillingTallyPre(stack); + handleDesperadoPre(stack); + } + + @SubscribeEvent + public static void onPostReload(ReloadEvent.Post event) { + Player player = event.player; + ItemStack stack = event.stack; + if (player == null || !stack.is(ModTags.Items.GUN)) { + return; + } + + if (player.level().isClientSide) { + return; + } + + handleHealClipPost(player, stack); + handleKillClipPost(stack); + handleDesperadoPost(stack); + } + + private static void handleHealClipPre(ItemStack stack) { + int time = GunsTool.getPerkIntTag(stack, "HealClipTime"); + if (time > 0) { + GunsTool.setPerkIntTag(stack, "HealClipTime", 0); + GunsTool.setPerkBooleanTag(stack, "HealClip", true); + } else { + GunsTool.setPerkBooleanTag(stack, "HealClip", false); + } + } + + private static void handleHealClipPost(Player player, ItemStack stack) { + if (!GunsTool.getPerkBooleanTag(stack, "HealClip")) { + return; + } + + // TODO perk +// int healClipLevel = PerkHelper.getItemPerkLevel(ModPerks.HEAL_CLIP.get(), stack); +// if (healClipLevel == 0) { +// healClipLevel = 1; +// } +// +// player.heal(12.0f * (0.8f + 0.2f * healClipLevel)); +// List players = player.level().getEntitiesOfClass(Player.class, player.getBoundingBox().inflate(5)) +// .stream().filter(p -> p.isAlliedTo(player)).toList(); +// int finalHealClipLevel = healClipLevel; +// players.forEach(p -> p.heal(6.0f * (0.8f + 0.2f * finalHealClipLevel))); + } + + private static void handleKillClipPre(ItemStack stack) { + int time = GunsTool.getPerkIntTag(stack, "KillClipReloadTime"); + if (time > 0) { + GunsTool.setPerkIntTag(stack, "KillClipReloadTime", 0); + GunsTool.setPerkBooleanTag(stack, "KillClip", true); + } else { + GunsTool.setPerkBooleanTag(stack, "KillClip", false); + } + } + + private static void handleKillClipPost(ItemStack stack) { + if (!GunsTool.getPerkBooleanTag(stack, "KillClip")) { + return; + } + + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.KILL_CLIP.get(), stack); +// GunsTool.setPerkIntTag(stack, "KillClipTime", 90 + 10 * level); + } + + private static void handleKillingTallyPre(ItemStack stack) { + // TODO perk +// int level = PerkHelper.getItemPerkLevel(ModPerks.KILLING_TALLY.get(), stack); +// if (level == 0) { +// return; +// } +// +// GunsTool.setPerkIntTag(stack, "KillingTally", 0); + } + + private static void handleDesperadoPre(ItemStack stack) { + int time = GunsTool.getPerkIntTag(stack, "DesperadoTime"); + if (time > 0) { + GunsTool.setPerkIntTag(stack, "DesperadoTime", 0); + GunsTool.setPerkBooleanTag(stack, "Desperado", true); + } else { + GunsTool.setPerkBooleanTag(stack, "Desperado", false); + } + } + + private static void handleDesperadoPost(ItemStack stack) { + // TODO perk +// if (!GunsTool.getPerkBooleanTag(stack, "Desperado")) { +// return; +// } +// +// int level = PerkHelper.getItemPerkLevel(ModPerks.DESPERADO.get(), stack); +// GunsTool.setPerkIntTag(stack, "DesperadoTimePost", 110 + level * 10); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/event/TACZGunEventHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/TACZGunEventHandler.java new file mode 100644 index 000000000..0a385696e --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/event/TACZGunEventHandler.java @@ -0,0 +1,12 @@ +package com.atsuishio.superbwarfare.event; + +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.tacz.guns.api.event.common.EntityHurtByGunEvent; + +public class TACZGunEventHandler { + public static void entityHurtByTACZGun(EntityHurtByGunEvent.Pre event) { + if (event.getHurtEntity() instanceof VehicleEntity) { + event.setHeadshot(false); + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/event/events/PreKillEvent.java b/src/main/java/com/atsuishio/superbwarfare/event/events/PreKillEvent.java new file mode 100644 index 000000000..857f39d02 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/event/events/PreKillEvent.java @@ -0,0 +1,49 @@ +package com.atsuishio.superbwarfare.event.events; + +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.neoforged.bus.api.Event; +import net.neoforged.bus.api.ICancellableEvent; + +/** + * 玩家击杀生物后,用于判断是否发送击杀播报/显示击杀指示 + */ +public class PreKillEvent extends Event implements ICancellableEvent { + + private final Player player; + private final DamageSource source; + private final LivingEntity target; + + private PreKillEvent(Player player, DamageSource source, LivingEntity target) { + this.player = player; + this.source = source; + this.target = target; + } + + public static class SendKillMessage extends PreKillEvent { + + public SendKillMessage(Player player, DamageSource source, LivingEntity target) { + super(player, source, target); + } + } + + public static class Indicator extends PreKillEvent { + + public Indicator(Player player, DamageSource source, LivingEntity target) { + super(player, source, target); + } + } + + public Player getPlayer() { + return player; + } + + public DamageSource getSource() { + return source; + } + + public LivingEntity getTarget() { + return target; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/event/events/ReloadEvent.java b/src/main/java/com/atsuishio/superbwarfare/event/events/ReloadEvent.java new file mode 100644 index 000000000..0a5f8100f --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/event/events/ReloadEvent.java @@ -0,0 +1,37 @@ +package com.atsuishio.superbwarfare.event.events; + +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.bus.api.Event; +import net.neoforged.bus.api.ICancellableEvent; + +public class ReloadEvent extends Event implements ICancellableEvent { + + public final Player player; + public final ItemStack stack; + + private ReloadEvent(Player player, ItemStack stack) { + this.player = player; + this.stack = stack; + } + + public static class Pre extends ReloadEvent { + public Pre(Player player, ItemStack stack) { + super(player, stack); + } + } + + public static class Post extends ReloadEvent { + public Post(Player player, ItemStack stack) { + super(player, stack); + } + } + + public Player getPlayer() { + return player; + } + + public ItemStack getStack() { + return stack; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/headshot/BasicHeadshotBox.java b/src/main/java/com/atsuishio/superbwarfare/headshot/BasicHeadshotBox.java new file mode 100644 index 000000000..461359cd4 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/headshot/BasicHeadshotBox.java @@ -0,0 +1,36 @@ +package com.atsuishio.superbwarfare.headshot; + +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.AABB; + +import javax.annotation.Nullable; + +/** + * Author: MrCrayfish + */ +public class BasicHeadshotBox implements IHeadshotBox { + protected double headWidth; + protected double headHeight; + protected double headYOffset; + + public BasicHeadshotBox(double headSize, double headYOffset) { + this.headWidth = headSize; + this.headHeight = headSize; + this.headYOffset = headYOffset; + } + + public BasicHeadshotBox(double headWidth, double headHeight, double headYOffset) { + this.headWidth = headWidth; + this.headHeight = headHeight; + this.headYOffset = headYOffset; + } + + @Nullable + @Override + public AABB getHeadshotBox(T entity) { + double halfWidth = this.headWidth / 2.0; + AABB headBox = new AABB(-halfWidth * 0.0625, 0, -halfWidth * 0.0625, halfWidth * 0.0625, this.headHeight * 0.0625, halfWidth * 0.0625); + headBox = headBox.move(0, this.headYOffset * 0.0625, 0); + return headBox; + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/headshot/BoundingBoxManager.java b/src/main/java/com/atsuishio/superbwarfare/headshot/BoundingBoxManager.java new file mode 100644 index 000000000..38263c500 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/headshot/BoundingBoxManager.java @@ -0,0 +1,130 @@ +package com.atsuishio.superbwarfare.headshot; + +import com.atsuishio.superbwarfare.init.ModEntities; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import net.neoforged.neoforge.event.tick.PlayerTickEvent; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.WeakHashMap; + +/** + * Author: MrCrayfish + */ +public class BoundingBoxManager { + private static final Map, IHeadshotBox> headshotBoxes = new HashMap<>(); + private static final WeakHashMap> playerBoxes = new WeakHashMap<>(); + + static { + /* Player */ + registerHeadshotBox(EntityType.PLAYER, (entity) -> { + AABB headBox = new AABB(-4 * 0.0625, 0, -4 * 0.0625, 4 * 0.0625, 8 * 0.0625, 4 * 0.0625); + double scale = 30.0 / 32.0; + if (entity.getBbHeight() <= 1) { + headBox = headBox.move(0, 3 * 0.0625, 0); + Vec3 pos = Vec3.directionFromRotation(entity.getXRot(), entity.yBodyRot).normalize().scale(0.8); + headBox = headBox.move(pos); + } else { + headBox = headBox.move(0, entity.isShiftKeyDown() ? 20 * 0.0625 : 24 * 0.0625, 0); + } + return new AABB(headBox.minX * scale, headBox.minY * scale, headBox.minZ * scale, headBox.maxX * scale, headBox.maxY * scale, headBox.maxZ * scale); + }); + registerHeadshotBox(ModEntities.SENPAI.get(), new BasicHeadshotBox<>(8.0, 22.0)); + registerHeadshotBox(ModEntities.TARGET.get(), new BasicHeadshotBox<>(14.0, 20.0)); + registerHeadshotBox(EntityType.ENDERMAN, new BasicHeadshotBox<>(8.0, 38.0)); + registerHeadshotBox(EntityType.ZOMBIE, new ChildHeadshotBox<>(8.0, 26.0, 0.75, 0.5)); + registerHeadshotBox(EntityType.ZOMBIFIED_PIGLIN, new ChildHeadshotBox<>(8.0, 26.0, 0.75, 0.5)); + registerHeadshotBox(EntityType.HUSK, new ChildHeadshotBox<>(8.0, 26.0, 0.75, 0.5)); + registerHeadshotBox(EntityType.SKELETON, new BasicHeadshotBox<>(8.0, 26.0)); + registerHeadshotBox(EntityType.STRAY, new BasicHeadshotBox<>(8.0, 26.0)); + registerHeadshotBox(EntityType.CREEPER, new BasicHeadshotBox<>(8.0, 21.0)); + registerHeadshotBox(EntityType.SPIDER, new RotatedHeadshotBox<>(8.0, 5.0, 7.0, false, true)); + registerHeadshotBox(EntityType.DROWNED, new BasicHeadshotBox<>(8.0, 26.0)); + registerHeadshotBox(EntityType.VILLAGER, new NoChildHeadshotBox<>(8.0, 9.0, 25.0)); + registerHeadshotBox(EntityType.ZOMBIE_VILLAGER, new NoChildHeadshotBox<>(8.0, 9.0, 25.0)); + registerHeadshotBox(EntityType.VINDICATOR, new NoChildHeadshotBox<>(8.0, 9.0, 25.0)); + registerHeadshotBox(EntityType.EVOKER, new BasicHeadshotBox<>(8.0, 9.0, 25.0)); + registerHeadshotBox(EntityType.PILLAGER, new BasicHeadshotBox<>(8.0, 9.0, 25.0)); + registerHeadshotBox(EntityType.ILLUSIONER, new BasicHeadshotBox<>(8.0, 9.0, 25.0)); + registerHeadshotBox(EntityType.WANDERING_TRADER, new BasicHeadshotBox<>(8.0, 9.0, 25.0)); + registerHeadshotBox(EntityType.WITCH, new BasicHeadshotBox<>(8.0, 9.0, 25.0)); + registerHeadshotBox(EntityType.SHEEP, new RotatedHeadshotBox<>(7.5, 8.0, 15.0, 9.5, false, true)); + registerHeadshotBox(EntityType.CHICKEN, new NoChildRotatedHeadshotBox<>(4.0, 6.0, 9.0, 5.0, false, true)); + registerHeadshotBox(EntityType.COW, new NoChildRotatedHeadshotBox<>(7.5, 8.0, 16.0, 10.5, false, true)); + registerHeadshotBox(EntityType.MOOSHROOM, new NoChildRotatedHeadshotBox<>(7.5, 8.0, 16.0, 10.5, false, true)); + registerHeadshotBox(EntityType.PIG, new NoChildRotatedHeadshotBox<>(8.0, 8.0, 10, false, true)); + registerHeadshotBox(EntityType.HORSE, new RotatedHeadshotBox<>(10.0, 26.0, 16.0, false, true)); + registerHeadshotBox(EntityType.SKELETON_HORSE, new RotatedHeadshotBox<>(10.0, 26.0, 16.0, false, true)); + registerHeadshotBox(EntityType.DONKEY, new RotatedHeadshotBox<>(7.5, 8.0, 20.0, 13.0, false, true)); + registerHeadshotBox(EntityType.MULE, new RotatedHeadshotBox<>(7.5, 8.0, 21.0, 14.0, false, true)); + registerHeadshotBox(EntityType.LLAMA, new RotatedHeadshotBox<>(8.0, 26.0, 10.0, false, true)); + registerHeadshotBox(EntityType.TRADER_LLAMA, new RotatedHeadshotBox<>(8.0, 26.0, 10.0, false, true)); + registerHeadshotBox(EntityType.POLAR_BEAR, new RotatedHeadshotBox<>(9.0, 12.0, 20.0, false, true)); + registerHeadshotBox(EntityType.SNOW_GOLEM, new BasicHeadshotBox<>(10.0, 22.5)); + registerHeadshotBox(EntityType.TURTLE, new RotatedHeadshotBox<>(6.0, 5.0, 1.0, 10.0, false, true)); + registerHeadshotBox(EntityType.IRON_GOLEM, new BasicHeadshotBox<>(8.0, 35.0)); + registerHeadshotBox(EntityType.WARDEN, new BasicHeadshotBox<>(14.0, 37.0)); + registerHeadshotBox(EntityType.PHANTOM, new RotatedHeadshotBox<>(6.0, 3.0, 1.5, 6.5, true, true)); + registerHeadshotBox(EntityType.HOGLIN, new RotatedHeadshotBox<>(14.0, 16.0, 7.0, 21.0, false, true)); + registerHeadshotBox(EntityType.ZOGLIN, new RotatedHeadshotBox<>(14.0, 16.0, 7.0, 21.0, false, true)); + registerHeadshotBox(EntityType.PIGLIN, new ChildHeadshotBox<>(8.0, 26.0, 0.75, 0.5)); + } + + /** + * Registers a headshot box for the specified entity type. + * + * @param type the entity type + * @param headshotBox a {@link IHeadshotBox} get + * @param a type that extends {@link LivingEntity} + */ + public static void registerHeadshotBox(EntityType type, IHeadshotBox headshotBox) { + headshotBoxes.putIfAbsent(type, headshotBox); + } + + @Nullable + @SuppressWarnings("unchecked") + public static IHeadshotBox getHeadshotBoxes(EntityType type) { + return (IHeadshotBox) headshotBoxes.get(type); + } + + @SubscribeEvent(receiveCanceled = true) + public void onPlayerTick(PlayerTickEvent.Pre event) { + if (FMLEnvironment.dist == Dist.CLIENT) { + if (event.getEntity().isSpectator()) { + playerBoxes.remove(event.getEntity()); + return; + } + LinkedList boxes = playerBoxes.computeIfAbsent(event.getEntity(), player -> new LinkedList<>()); + boxes.addFirst(event.getEntity().getBoundingBox()); + if (boxes.size() > 20) { + boxes.removeLast(); + } + } + } + + @SubscribeEvent(receiveCanceled = true) + public void onPlayerLoggedOut(PlayerEvent.PlayerLoggedOutEvent event) { + playerBoxes.remove(event.getEntity()); + } + + public static AABB getBoundingBox(Player entity, int ping) { + if (playerBoxes.containsKey(entity)) { + LinkedList boxes = playerBoxes.get(entity); + int index = Mth.clamp(ping, 0, boxes.size() - 1); + return boxes.get(index); + } + return entity.getBoundingBox(); + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/headshot/ChildHeadshotBox.java b/src/main/java/com/atsuishio/superbwarfare/headshot/ChildHeadshotBox.java new file mode 100644 index 000000000..aa06925f6 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/headshot/ChildHeadshotBox.java @@ -0,0 +1,36 @@ +package com.atsuishio.superbwarfare.headshot; + +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.AABB; + +import javax.annotation.Nullable; + +/** + * Author: MrCrayfish + */ +public class ChildHeadshotBox extends BasicHeadshotBox { + private final double childHeadScale; + private final double headYOffsetScale; + + public ChildHeadshotBox(double headSize, double headYOffset, double childHeadScale, double headYOffsetScale) { + super(headSize, headYOffset); + this.childHeadScale = childHeadScale; + this.headYOffsetScale = headYOffsetScale; + } + + public ChildHeadshotBox(double headWidth, double headHeight, double headYOffset, double childHeadScale, double headYOffsetScale) { + super(headWidth, headHeight, headYOffset); + this.childHeadScale = childHeadScale; + this.headYOffsetScale = headYOffsetScale; + } + + @Nullable + @Override + public AABB getHeadshotBox(T entity) { + AABB headBox = super.getHeadshotBox(entity); + if (headBox != null && entity.isBaby()) { + return new AABB(headBox.minX * this.childHeadScale, headBox.minY * this.headYOffsetScale, headBox.minZ * this.childHeadScale, headBox.maxX * this.childHeadScale, headBox.maxY * (this.headYOffsetScale + 0.065), headBox.maxZ * this.childHeadScale); + } + return headBox; + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/headshot/IHeadshotBox.java b/src/main/java/com/atsuishio/superbwarfare/headshot/IHeadshotBox.java new file mode 100644 index 000000000..9fa662ad5 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/headshot/IHeadshotBox.java @@ -0,0 +1,15 @@ +package com.atsuishio.superbwarfare.headshot; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.AABB; + +import javax.annotation.Nullable; + +/** + * Author: MrCrayfish + */ +public interface IHeadshotBox { + + @Nullable + AABB getHeadshotBox(T entity); +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/headshot/NoChildHeadshotBox.java b/src/main/java/com/atsuishio/superbwarfare/headshot/NoChildHeadshotBox.java new file mode 100644 index 000000000..01ef227c8 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/headshot/NoChildHeadshotBox.java @@ -0,0 +1,26 @@ +package com.atsuishio.superbwarfare.headshot; + +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.AABB; + +import javax.annotation.Nullable; + +/** + * Author: MrCrayfish + */ +public class NoChildHeadshotBox extends BasicHeadshotBox { + public NoChildHeadshotBox(double headSize, double headYOffset) { + super(headSize, headYOffset); + } + + public NoChildHeadshotBox(double headWidth, double headHeight, double headYOffset) { + super(headWidth, headHeight, headYOffset); + } + + @Nullable + @Override + public AABB getHeadshotBox(T entity) { + if (entity.isBaby()) return null; + return super.getHeadshotBox(entity); + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/headshot/NoChildRotatedHeadshotBox.java b/src/main/java/com/atsuishio/superbwarfare/headshot/NoChildRotatedHeadshotBox.java new file mode 100644 index 000000000..45675dc03 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/headshot/NoChildRotatedHeadshotBox.java @@ -0,0 +1,26 @@ +package com.atsuishio.superbwarfare.headshot; + +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.AABB; + +import javax.annotation.Nullable; + +/** + * Author: MrCrayfish + */ +public class NoChildRotatedHeadshotBox extends RotatedHeadshotBox { + public NoChildRotatedHeadshotBox(double headSize, double headYOffset, double headZOffset, boolean rotatePitch, boolean rotateYaw) { + super(headSize, headYOffset, headZOffset, rotatePitch, rotateYaw); + } + + public NoChildRotatedHeadshotBox(double headWidth, double headHeight, double headYOffset, double headZOffset, boolean rotatePitch, boolean rotateYaw) { + super(headWidth, headHeight, headYOffset, headZOffset, rotatePitch, rotateYaw); + } + + @Nullable + @Override + public AABB getHeadshotBox(T entity) { + if (entity.isBaby()) return null; + return super.getHeadshotBox(entity); + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/headshot/RotatedHeadshotBox.java b/src/main/java/com/atsuishio/superbwarfare/headshot/RotatedHeadshotBox.java new file mode 100644 index 000000000..70d67a5ac --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/headshot/RotatedHeadshotBox.java @@ -0,0 +1,41 @@ +package com.atsuishio.superbwarfare.headshot; + +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +import javax.annotation.Nullable; + +/** + * Author: MrCrayfish + */ +public class RotatedHeadshotBox extends BasicHeadshotBox { + protected double headZOffset; + protected boolean rotatePitch; + protected boolean rotateYaw; + + public RotatedHeadshotBox(double headSize, double headYOffset, double headZOffset, boolean rotatePitch, boolean rotateYaw) { + super(headSize, headSize, headYOffset); + this.headZOffset = headZOffset; + this.rotatePitch = rotatePitch; + this.rotateYaw = rotateYaw; + } + + public RotatedHeadshotBox(double headWidth, double headHeight, double headYOffset, double headZOffset, boolean rotatePitch, boolean rotateYaw) { + super(headWidth, headHeight, headYOffset); + this.headZOffset = headZOffset; + this.rotatePitch = rotatePitch; + this.rotateYaw = rotateYaw; + } + + @Nullable + @Override + public AABB getHeadshotBox(T entity) { + AABB headBox = super.getHeadshotBox(entity); + if (headBox != null) { + headBox = headBox.move(Vec3.directionFromRotation(this.rotatePitch ? entity.getXRot() : 0.0F, this.rotateYaw ? entity.yBodyRot : 0.0F).normalize().scale(this.headZOffset * 0.0625)); + return headBox; + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java b/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java index 8596724ac..fa60b44b1 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java @@ -4,7 +4,6 @@ import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.item.*; import com.atsuishio.superbwarfare.item.armor.*; 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; diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModKeyMappings.java b/src/main/java/com/atsuishio/superbwarfare/init/ModKeyMappings.java index f20a918b5..00249b2cd 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModKeyMappings.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModKeyMappings.java @@ -1,7 +1,7 @@ package com.atsuishio.superbwarfare.init; import com.atsuishio.superbwarfare.ModUtils; -import com.atsuishio.superbwarfare.network.message.BreathMessage; +import com.atsuishio.superbwarfare.network.message.send.BreathMessage; import com.mojang.blaze3d.platform.InputConstants; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; diff --git a/src/main/java/com/atsuishio/superbwarfare/item/BeamTest.java b/src/main/java/com/atsuishio/superbwarfare/item/BeamTest.java index ff6daf144..ca7d70e50 100644 --- a/src/main/java/com/atsuishio/superbwarfare/item/BeamTest.java +++ b/src/main/java/com/atsuishio/superbwarfare/item/BeamTest.java @@ -5,8 +5,8 @@ import com.atsuishio.superbwarfare.capability.laser.LaserHandler; import com.atsuishio.superbwarfare.client.TooltipTool; import com.atsuishio.superbwarfare.entity.projectile.LaserEntity; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.LaserShootMessage; -import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; +import com.atsuishio.superbwarfare.network.message.send.LaserShootMessage; import com.atsuishio.superbwarfare.tools.TraceTool; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundStopSoundPacket; diff --git a/src/main/java/com/atsuishio/superbwarfare/item/common/CannonShellItem.java b/src/main/java/com/atsuishio/superbwarfare/item/common/CannonShellItem.java deleted file mode 100644 index 5b4b037c1..000000000 --- a/src/main/java/com/atsuishio/superbwarfare/item/common/CannonShellItem.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.atsuishio.superbwarfare.item.common; - -import net.minecraft.world.item.Item; - -public class CannonShellItem extends Item { - - public CannonShellItem(Properties properties) { - super(properties); - } -} diff --git a/src/main/java/com/atsuishio/superbwarfare/item/common/CreativeAmmoBox.java b/src/main/java/com/atsuishio/superbwarfare/item/common/CreativeAmmoBox.java deleted file mode 100644 index fa360a713..000000000 --- a/src/main/java/com/atsuishio/superbwarfare/item/common/CreativeAmmoBox.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.atsuishio.superbwarfare.item.common; - -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 tooltipComponents, TooltipFlag tooltipFlag) { - tooltipComponents.add(Component.translatable("des.superbwarfare.creative_ammo_box").withStyle(ChatFormatting.GRAY)); - } -} diff --git a/src/main/java/com/atsuishio/superbwarfare/mobeffect/BurnMobEffect.java b/src/main/java/com/atsuishio/superbwarfare/mobeffect/BurnMobEffect.java index 768aea81d..e97757d2a 100644 --- a/src/main/java/com/atsuishio/superbwarfare/mobeffect/BurnMobEffect.java +++ b/src/main/java/com/atsuishio/superbwarfare/mobeffect/BurnMobEffect.java @@ -3,7 +3,7 @@ package com.atsuishio.superbwarfare.mobeffect; import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModMobEffects; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import net.minecraft.core.registries.Registries; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundSource; diff --git a/src/main/java/com/atsuishio/superbwarfare/mobeffect/ShockMobEffect.java b/src/main/java/com/atsuishio/superbwarfare/mobeffect/ShockMobEffect.java index 317179bf6..4e45063b7 100644 --- a/src/main/java/com/atsuishio/superbwarfare/mobeffect/ShockMobEffect.java +++ b/src/main/java/com/atsuishio/superbwarfare/mobeffect/ShockMobEffect.java @@ -3,7 +3,7 @@ package com.atsuishio.superbwarfare.mobeffect; import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModMobEffects; import com.atsuishio.superbwarfare.init.ModSounds; -import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; diff --git a/src/main/java/com/atsuishio/superbwarfare/network/ClientPacketHandler.java b/src/main/java/com/atsuishio/superbwarfare/network/ClientPacketHandler.java new file mode 100644 index 000000000..6fc64687f --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/network/ClientPacketHandler.java @@ -0,0 +1,64 @@ +package com.atsuishio.superbwarfare.network; + +import com.atsuishio.superbwarfare.client.overlay.CrossHairOverlay; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +public class ClientPacketHandler { + + public static void handleClientIndicatorMessage(ClientIndicatorMessage message, final IPayloadContext context) { + var type = message.messageType(); + switch (type) { + case 1 -> CrossHairOverlay.HEAD_INDICATOR = message.value(); + case 2 -> CrossHairOverlay.KILL_INDICATOR = message.value(); + case 3 -> CrossHairOverlay.VEHICLE_INDICATOR = message.value(); + default -> CrossHairOverlay.HIT_INDICATOR = message.value(); + } + } + +// public static void handleSimulationDistanceMessage(int distance, final IPayloadContext context) { +// if (context.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) { +// DroneUIOverlay.MAX_DISTANCE = distance * 16; +// } +// } +// +// public static void handleContainerDataMessage(int containerId, List data, final IPayloadContext context) { +// if (context.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) { +// Minecraft mc = Minecraft.getInstance(); +// if (mc.player != null && mc.player.containerMenu.containerId == containerId) { +// data.forEach(p -> ((EnergyMenu) mc.player.containerMenu).setData(p.id, p.data)); +// } +// } +// } +// +// public static void handleRadarMenuOpen(RadarMenuOpenMessage message, final IPayloadContext context) { +// FuMO25ScreenHelper.resetEntities(); +// FuMO25ScreenHelper.pos = message.pos; +// } +// +// public static void handleRadarMenuClose() { +// FuMO25ScreenHelper.resetEntities(); +// FuMO25ScreenHelper.pos = null; +// } +// +// public static void handleResetCameraType(final IPayloadContext context) { +// if (context.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) { +// Minecraft minecraft = Minecraft.getInstance(); +// Player player = minecraft.player; +// if (player == null) return; +// +// Minecraft.getInstance().options.setCameraType(Objects.requireNonNullElse(ClientEventHandler.lastCameraType, CameraType.FIRST_PERSON)); +// } +// } +// +// public static void handleClientSyncMotion(ClientMotionSyncMessage message, final IPayloadContext context) { +// if (context.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) { +// var level = Minecraft.getInstance().level; +// if (level == null) return; +// Entity entity = level.getEntity(message.id); +// if (entity != null) { +// entity.lerpMotion(message.x, message.y, message.z); +// } +// } +// } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/network/NetworkRegistry.java b/src/main/java/com/atsuishio/superbwarfare/network/NetworkRegistry.java index d6a2f8573..633b503eb 100644 --- a/src/main/java/com/atsuishio/superbwarfare/network/NetworkRegistry.java +++ b/src/main/java/com/atsuishio/superbwarfare/network/NetworkRegistry.java @@ -1,6 +1,7 @@ package com.atsuishio.superbwarfare.network; -import com.atsuishio.superbwarfare.network.message.*; +import com.atsuishio.superbwarfare.network.message.receive.*; +import com.atsuishio.superbwarfare.network.message.send.*; import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; import net.neoforged.neoforge.network.registration.PayloadRegistrar; @@ -18,6 +19,7 @@ public class NetworkRegistry { registrar.playToServer(LaserShootMessage.TYPE, LaserShootMessage.STREAM_CODEC, LaserShootMessage::handler); registrar.playToServer(BreathMessage.TYPE, BreathMessage.STREAM_CODEC, BreathMessage::handler); registrar.playToServer(ShootMessage.TYPE, ShootMessage.STREAM_CODEC, ShootMessage::handler); - + registrar.playToServer(DoubleJumpMessage.TYPE, DoubleJumpMessage.STREAM_CODEC, DoubleJumpMessage::handler); + registrar.playToServer(VehicleMovementMessage.TYPE, VehicleMovementMessage.STREAM_CODEC, VehicleMovementMessage::handler); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/ShakeClientMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/ShakeClientMessage.java deleted file mode 100644 index 3c6559b07..000000000 --- a/src/main/java/com/atsuishio/superbwarfare/network/message/ShakeClientMessage.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.atsuishio.superbwarfare.network.message; - -import com.atsuishio.superbwarfare.ModUtils; -import io.netty.buffer.ByteBuf; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.codec.ByteBufCodecs; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.Vec3; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.neoforge.client.event.ViewportEvent; -import net.neoforged.neoforge.network.handling.IPayloadContext; -import org.jetbrains.annotations.NotNull; - -@EventBusSubscriber(modid = ModUtils.MODID, bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) -public record ShakeClientMessage( - double time, double radius, double amplitude, - double x, double y, double z -) implements CustomPacketPayload { - public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ModUtils.loc("shake_client")); - - public static final StreamCodec STREAM_CODEC = StreamCodec.composite( - ByteBufCodecs.DOUBLE, - ShakeClientMessage::time, - ByteBufCodecs.DOUBLE, - ShakeClientMessage::radius, - ByteBufCodecs.DOUBLE, - ShakeClientMessage::amplitude, - ByteBufCodecs.DOUBLE, - ShakeClientMessage::x, - ByteBufCodecs.DOUBLE, - ShakeClientMessage::y, - ByteBufCodecs.DOUBLE, - ShakeClientMessage::z, - ShakeClientMessage::new - ); - - public static void handler(final ShakeClientMessage message, final IPayloadContext context) { - Player player = Minecraft.getInstance().player; - if (player == null) return; - shakeTime = message.time; - shakeRadius = message.radius; - shakeAmplitude = message.amplitude * Mth.DEG_TO_RAD; - shakePos[0] = message.x; - shakePos[1] = message.y; - shakePos[2] = message.z; - shakeType = 2 * (Math.random() - 0.5); - } - - public static double shakeTime = 0; - public static double shakeRadius = 0; - public static double shakeAmplitude = 0; - public static double[] shakePos = {0, 0, 0}; - public static double shakeType = 0; - - @SubscribeEvent - public static void computeCameraAngles(ViewportEvent.ComputeCameraAngles event) { - ClientLevel level = Minecraft.getInstance().level; - Entity entity = event.getCamera().getEntity(); - - if (!(entity instanceof LivingEntity living)) return; - ItemStack stack = living.getMainHandItem(); - -// if (level != null && -// (stack.is(ModItems.MONITOR.get()) && NBTTool.getOrCreateTag(stack).getBoolean("Using") && NBTTool.getOrCreateTag(stack).getBoolean("Linked"))) { -// handleDroneCamera(event, living); -// } else { -// var effect = Minecraft.getInstance().gameRenderer.currentEffect(); -// if (effect != null && effect.getName().equals(ModUtils.MODID + ":shaders/post/scan_pincushion.json")) { -// Minecraft.getInstance().gameRenderer.shutdownEffect(); -// } -// } - - float times = Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(); - LocalPlayer player = Minecraft.getInstance().player; - - float yaw = event.getYaw(); - float pitch = event.getPitch(); - float roll = event.getRoll(); - - shakeTime = Mth.lerp(0.175 * times, shakeTime, 0); - - if (player != null && shakeTime > 0) { - float shakeRadiusAmplitude = (float) Mth.clamp(1 - player.position().distanceTo(new Vec3(shakePos[0], shakePos[1], shakePos[2])) / shakeRadius, 0, 1); - - boolean onVehicle = player.getVehicle() != null; - - if (shakeType > 0) { - event.setYaw((float) (yaw + (shakeTime * Math.sin(0.5 * Math.PI * shakeTime) * shakeAmplitude * shakeRadiusAmplitude * shakeType * (onVehicle ? 0.4 : 1)))); - event.setPitch((float) (pitch - (shakeTime * Math.sin(0.5 * Math.PI * shakeTime) * shakeAmplitude * shakeRadiusAmplitude * shakeType * (onVehicle ? 0.4 : 1)))); - event.setRoll((float) (roll - (shakeTime * Math.sin(0.5 * Math.PI * shakeTime) * shakeAmplitude * shakeRadiusAmplitude * (onVehicle ? 0.4 : 1)))); - } else { - event.setYaw((float) (yaw - (shakeTime * Math.sin(0.5 * Math.PI * shakeTime) * shakeAmplitude * shakeRadiusAmplitude * shakeType * (onVehicle ? 0.4 : 1)))); - event.setPitch((float) (pitch + (shakeTime * Math.sin(0.5 * Math.PI * shakeTime) * shakeAmplitude * shakeRadiusAmplitude * shakeType * (onVehicle ? 0.4 : 1)))); - event.setRoll((float) (roll + (shakeTime * Math.sin(0.5 * Math.PI * shakeTime) * shakeAmplitude * shakeRadiusAmplitude * (onVehicle ? 0.4 : 1)))); - } - } - - // TODO 完善事件处理 -// cameraPitch = event.getPitch(); -// cameraYaw = event.getYaw(); -// cameraRoll = event.getRoll(); -// -// if (player != null && player.getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.banHand(player)) { -// return; -// } -// -// if (level != null && stack.is(ModTags.Items.GUN)) { -// handleWeaponSway(living); -// handleWeaponMove(living); -// handleWeaponZoom(living); -// handlePlayerBreath(living); -// handleWeaponFire(event, living); -// handleWeaponShell(); -// handleGunRecoil(); -// handleBowPullAnimation(living); -// handleWeaponDraw(living); -// handlePlayerCamera(event); -// } -// -// handleShockCamera(event, living); - } - - - @Override - public @NotNull Type type() { - return TYPE; - } -} diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/ShootMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/ShootMessage.java deleted file mode 100644 index 5462881ee..000000000 --- a/src/main/java/com/atsuishio/superbwarfare/network/message/ShootMessage.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.atsuishio.superbwarfare.network.message; - -import com.atsuishio.superbwarfare.ModUtils; -import com.atsuishio.superbwarfare.event.GunEventHandler; -import com.atsuishio.superbwarfare.init.ModTags; -import com.atsuishio.superbwarfare.tools.GunsTool; -import com.atsuishio.superbwarfare.tools.NBTTool; -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.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.neoforged.neoforge.network.handling.IPayloadContext; -import org.jetbrains.annotations.NotNull; - -public record ShootMessage(double spread) implements CustomPacketPayload { - public static final Type TYPE = new Type<>(ModUtils.loc("shoot")); - - public static final StreamCodec STREAM_CODEC = StreamCodec.composite( - ByteBufCodecs.DOUBLE, - ShootMessage::spread, - ShootMessage::new - ); - - public static void handler(final ShootMessage message, final IPayloadContext context) { - pressAction(context.player(), message.spread); - } - - public static void pressAction(Player player, double spared) { - ItemStack stack = player.getMainHandItem(); - if (stack.is(ModTags.Items.NORMAL_GUN)) { - int projectileAmount = GunsTool.getGunIntTag(stack, "ProjectileAmount", 1); - - if (GunsTool.getGunIntTag(stack, "Ammo", 0) > 0) { - // 空仓挂机 - if (GunsTool.getGunIntTag(stack, "Ammo", 0) == 1) { - GunsTool.setGunBooleanTag(stack, "HoldOpen", true); - } - - if (stack.is(ModTags.Items.REVOLVER)) { - NBTTool.getTag(stack).putBoolean("canImmediatelyShoot", false); - } - - // 判断是否为栓动武器(BoltActionTime > 0),并在开火后给一个需要上膛的状态 - if (GunsTool.getGunIntTag(stack, "BoltActionTime", 0) > 0 && GunsTool.getGunIntTag(stack, "Ammo", 0) > (stack.is(ModTags.Items.REVOLVER) ? 0 : 1)) { - GunsTool.setGunBooleanTag(stack, "NeedBoltAction", true); - } - - GunsTool.setGunIntTag(stack, "Ammo", GunsTool.getGunIntTag(stack, "Ammo", 0) - 1); - - NBTTool.getTag(stack).putDouble("empty", 1); - -// if (stack.getItem() == ModItems.M_60.get() && GunsTool.getGunIntTag(stack, "Ammo", 0) <= 5) { -// GunsTool.setGunBooleanTag(stack, "HideBulletChain", true); -// } -// -// if (stack.getItem() == ModItems.HOMEMADE_SHOTGUN.get()) { -// stack.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(InteractionHand.MAIN_HAND)); -// if (player instanceof ServerPlayer serverPlayer && player.level() instanceof ServerLevel serverLevel) { -// ParticleTool.sendParticle(serverLevel, ParticleTypes.CLOUD, player.getX() + 1.8 * player.getLookAngle().x, player.getY() + player.getBbHeight() - 0.1 + 1.8 * player.getLookAngle().y, -// player.getZ() + 1.8 * player.getLookAngle().z, 30, 0.4, 0.4, 0.4, 0.005, true, serverPlayer); -// } -// } -// -// if (stack.getItem() == ModItems.SENTINEL.get()) { -// stack.getCapability(ForgeCapabilities.ENERGY).ifPresent( -// iEnergyStorage -> iEnergyStorage.extractEnergy(3000, false) -// ); -// } -// -// var perk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); - - for (int index0 = 0; index0 < ( - // todo perk -// perk instanceof AmmoPerk ammoPerk && ammoPerk.slug ? 1 : projectileAmount - projectileAmount - ); index0++) { - GunEventHandler.gunShoot(player, spared); - } - - GunEventHandler.playGunSounds(player); - } - } - // todo minigun -// else if (stack.is(ModItems.MINIGUN.get())) { -// var tag = GunNBTTool.getOrCreateTag(stack); -// -// if ((player.getCapability(ModVariables.PLAYER_VARIABLES_CAPABILITY, null).orElse(new ModVariables.PlayerVariables())).rifleAmmo > 0 -// || InventoryTool.hasCreativeAmmoBox(player)) { -// 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); -// } -// } -// var perk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); -// float pitch = tag.getDouble("heat") <= 40 ? 1 : (float) (1 - 0.025 * Math.abs(40 - tag.getDouble("heat"))); -// -// if (!player.level().isClientSide() && player instanceof ServerPlayer) { -// float soundRadius = (float) GunsTool.getGunDoubleTag(stack, "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, spared); -// if (!InventoryTool.hasCreativeAmmoBox(player)) { -// player.getCapability(ModVariables.PLAYER_VARIABLES_CAPABILITY, null).ifPresent(capability -> { -// capability.rifleAmmo = player.getCapability(ModVariables.PLAYER_VARIABLES_CAPABILITY, null).orElse(new ModVariables.PlayerVariables()).rifleAmmo - 1; -// capability.syncPlayerVariables(player); -// }); -// } -// } -// } - } - - @Override - public @NotNull Type type() { - return TYPE; - } -} diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/ClientIndicatorMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/ClientIndicatorMessage.java similarity index 84% rename from src/main/java/com/atsuishio/superbwarfare/network/message/ClientIndicatorMessage.java rename to src/main/java/com/atsuishio/superbwarfare/network/message/receive/ClientIndicatorMessage.java index 2f619a81f..7c28b3076 100644 --- a/src/main/java/com/atsuishio/superbwarfare/network/message/ClientIndicatorMessage.java +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/ClientIndicatorMessage.java @@ -1,6 +1,7 @@ -package com.atsuishio.superbwarfare.network.message; +package com.atsuishio.superbwarfare.network.message.receive; import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.network.ClientPacketHandler; import io.netty.buffer.ByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; @@ -20,8 +21,7 @@ public record ClientIndicatorMessage(int messageType, int value) implements Cust ); public static void handler(final ClientIndicatorMessage message, final IPayloadContext context) { - // TODO indicator process -// ClientPacketHandler.handleClientIndicatorMessage(message, ctx); + ClientPacketHandler.handleClientIndicatorMessage(message, context); } @Override diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/ClientMotionSyncMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/ClientMotionSyncMessage.java similarity index 96% rename from src/main/java/com/atsuishio/superbwarfare/network/message/ClientMotionSyncMessage.java rename to src/main/java/com/atsuishio/superbwarfare/network/message/receive/ClientMotionSyncMessage.java index ca5f4bbbe..4f8d4a123 100644 --- a/src/main/java/com/atsuishio/superbwarfare/network/message/ClientMotionSyncMessage.java +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/ClientMotionSyncMessage.java @@ -1,4 +1,4 @@ -package com.atsuishio.superbwarfare.network.message; +package com.atsuishio.superbwarfare.network.message.receive; import com.atsuishio.superbwarfare.ModUtils; import io.netty.buffer.ByteBuf; diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/GunsDataMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/GunsDataMessage.java similarity index 95% rename from src/main/java/com/atsuishio/superbwarfare/network/message/GunsDataMessage.java rename to src/main/java/com/atsuishio/superbwarfare/network/message/receive/GunsDataMessage.java index ba07ac498..00dbac917 100644 --- a/src/main/java/com/atsuishio/superbwarfare/network/message/GunsDataMessage.java +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/GunsDataMessage.java @@ -1,4 +1,4 @@ -package com.atsuishio.superbwarfare.network.message; +package com.atsuishio.superbwarfare.network.message.receive; import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.tools.GunsTool; diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/PlayerGunKillMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/PlayerGunKillMessage.java similarity index 84% rename from src/main/java/com/atsuishio/superbwarfare/network/message/PlayerGunKillMessage.java rename to src/main/java/com/atsuishio/superbwarfare/network/message/receive/PlayerGunKillMessage.java index d1af88d8c..29b3dd139 100644 --- a/src/main/java/com/atsuishio/superbwarfare/network/message/PlayerGunKillMessage.java +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/PlayerGunKillMessage.java @@ -1,6 +1,9 @@ -package com.atsuishio.superbwarfare.network.message; +package com.atsuishio.superbwarfare.network.message.receive; import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.client.KillMessageConfig; +import com.atsuishio.superbwarfare.event.KillMessageHandler; +import com.atsuishio.superbwarfare.tools.PlayerKillRecord; import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; @@ -83,8 +86,10 @@ public class PlayerGunKillMessage implements CustomPacketPayload { if (player != null && target != null) { var type = message.getDamageType(); - // TODO 处理kill message - // DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientPacketHandler.handlePlayerKillMessage(player, target, message.headshot, type, ctx)); + if (KillMessageHandler.QUEUE.size() >= KillMessageConfig.KILL_MESSAGE_COUNT.get()) { + KillMessageHandler.QUEUE.poll(); + } + KillMessageHandler.QUEUE.offer(new PlayerKillRecord(player, target, player.getMainHandItem(), message.headshot, type)); } } } diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/PlayerVariablesSyncMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/PlayerVariablesSyncMessage.java similarity index 97% rename from src/main/java/com/atsuishio/superbwarfare/network/message/PlayerVariablesSyncMessage.java rename to src/main/java/com/atsuishio/superbwarfare/network/message/receive/PlayerVariablesSyncMessage.java index 28d237858..00bba6924 100644 --- a/src/main/java/com/atsuishio/superbwarfare/network/message/PlayerVariablesSyncMessage.java +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/PlayerVariablesSyncMessage.java @@ -1,4 +1,4 @@ -package com.atsuishio.superbwarfare.network.message; +package com.atsuishio.superbwarfare.network.message.receive; import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.capability.ModCapabilities; diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/receive/ShakeClientMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/ShakeClientMessage.java new file mode 100644 index 000000000..e12e70634 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/receive/ShakeClientMessage.java @@ -0,0 +1,46 @@ +package com.atsuishio.superbwarfare.network.message.receive; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +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.neoforged.api.distmarker.Dist; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import org.jetbrains.annotations.NotNull; + +@EventBusSubscriber(modid = ModUtils.MODID, bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) +public record ShakeClientMessage( + double time, double radius, double amplitude, + double x, double y, double z +) implements CustomPacketPayload { + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ModUtils.loc("shake_client")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.DOUBLE, + ShakeClientMessage::time, + ByteBufCodecs.DOUBLE, + ShakeClientMessage::radius, + ByteBufCodecs.DOUBLE, + ShakeClientMessage::amplitude, + ByteBufCodecs.DOUBLE, + ShakeClientMessage::x, + ByteBufCodecs.DOUBLE, + ShakeClientMessage::y, + ByteBufCodecs.DOUBLE, + ShakeClientMessage::z, + ShakeClientMessage::new + ); + + public static void handler(final ShakeClientMessage message, final IPayloadContext context) { + ClientEventHandler.handleShakeClient(message.time, message.radius, message.amplitude, message.x, message.y, message.z, context); + } + + + @Override + public @NotNull Type type() { + return TYPE; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/BreathMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/send/BreathMessage.java similarity index 56% rename from src/main/java/com/atsuishio/superbwarfare/network/message/BreathMessage.java rename to src/main/java/com/atsuishio/superbwarfare/network/message/send/BreathMessage.java index 5f286c926..5f4ad7cb1 100644 --- a/src/main/java/com/atsuishio/superbwarfare/network/message/BreathMessage.java +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/send/BreathMessage.java @@ -1,10 +1,12 @@ -package com.atsuishio.superbwarfare.network.message; +package com.atsuishio.superbwarfare.network.message.send; import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.capability.ModCapabilities; 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.neoforged.neoforge.network.handling.IPayloadContext; import org.jetbrains.annotations.NotNull; @@ -19,7 +21,23 @@ public record BreathMessage(boolean messageType) implements CustomPacketPayload public static void handler(final BreathMessage message, final IPayloadContext context) { - // TODO handler + ServerPlayer player = (ServerPlayer) context.player(); + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) return; + if (message.messageType + && !cap.breathExhaustion + && cap.zoom + && player.getPersistentData().getDouble("NoBreath") == 0 + ) { + cap.breath = true; + cap.syncPlayerVariables(player); + } + + if (!message.messageType) { + cap.breath = false; + cap.syncPlayerVariables(player); + } } @Override diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/send/DoubleJumpMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/send/DoubleJumpMessage.java new file mode 100644 index 000000000..1d01bdfe0 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/send/DoubleJumpMessage.java @@ -0,0 +1,47 @@ +package com.atsuishio.superbwarfare.network.message.send; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.capability.ModCapabilities; +import com.atsuishio.superbwarfare.init.ModSounds; +import io.netty.buffer.ByteBuf; +import net.minecraft.core.BlockPos; +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.sounds.SoundSource; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import org.jetbrains.annotations.NotNull; + +public record DoubleJumpMessage(boolean canDoubleJump) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(ModUtils.loc("double_jump")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.BOOL, + DoubleJumpMessage::canDoubleJump, + DoubleJumpMessage::new + ); + + public static void handler(final DoubleJumpMessage message, final IPayloadContext context) { + ServerPlayer player = (ServerPlayer) context.player(); + + Level level = player.level(); + double x = player.getX(); + double y = player.getY(); + double z = player.getZ(); + + level.playSound(null, BlockPos.containing(x, y, z), ModSounds.DOUBLE_JUMP.get(), SoundSource.BLOCKS, 1, 1); + + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) return; + + cap.playerDoubleJump = message.canDoubleJump; + cap.syncPlayerVariables(player); + } + + @Override + public @NotNull Type type() { + return TYPE; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/LaserShootMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/send/LaserShootMessage.java similarity index 95% rename from src/main/java/com/atsuishio/superbwarfare/network/message/LaserShootMessage.java rename to src/main/java/com/atsuishio/superbwarfare/network/message/send/LaserShootMessage.java index 648a98115..ed95b06f0 100644 --- a/src/main/java/com/atsuishio/superbwarfare/network/message/LaserShootMessage.java +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/send/LaserShootMessage.java @@ -1,8 +1,9 @@ -package com.atsuishio.superbwarfare.network.message; +package com.atsuishio.superbwarfare.network.message.send; import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.EntityFindUtil; import io.netty.buffer.ByteBuf; import net.minecraft.core.UUIDUtil; diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/send/ShootMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/send/ShootMessage.java new file mode 100644 index 000000000..11f2d519e --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/send/ShootMessage.java @@ -0,0 +1,138 @@ +package com.atsuishio.superbwarfare.network.message.send; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.capability.ModCapabilities; +import com.atsuishio.superbwarfare.event.GunEventHandler; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.init.ModTags; +import com.atsuishio.superbwarfare.tools.*; +import io.netty.buffer.ByteBuf; +import net.minecraft.core.particles.ParticleTypes; +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.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import org.jetbrains.annotations.NotNull; + +public record ShootMessage(double spread) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(ModUtils.loc("shoot")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.DOUBLE, + ShootMessage::spread, + ShootMessage::new + ); + + public static void handler(final ShootMessage message, final IPayloadContext context) { + pressAction(context.player(), message.spread); + } + + public static void pressAction(Player player, double spared) { + ItemStack stack = player.getMainHandItem(); + if (stack.is(ModTags.Items.NORMAL_GUN)) { + int projectileAmount = GunsTool.getGunIntTag(stack, "ProjectileAmount", 1); + + if (GunsTool.getGunIntTag(stack, "Ammo", 0) > 0) { + // 空仓挂机 + if (GunsTool.getGunIntTag(stack, "Ammo", 0) == 1) { + GunsTool.setGunBooleanTag(stack, "HoldOpen", true); + } + + if (stack.is(ModTags.Items.REVOLVER)) { + NBTTool.getTag(stack).putBoolean("canImmediatelyShoot", false); + } + + // 判断是否为栓动武器(BoltActionTime > 0),并在开火后给一个需要上膛的状态 + if (GunsTool.getGunIntTag(stack, "BoltActionTime", 0) > 0 && GunsTool.getGunIntTag(stack, "Ammo", 0) > (stack.is(ModTags.Items.REVOLVER) ? 0 : 1)) { + GunsTool.setGunBooleanTag(stack, "NeedBoltAction", true); + } + + GunsTool.setGunIntTag(stack, "Ammo", GunsTool.getGunIntTag(stack, "Ammo", 0) - 1); + + NBTTool.getTag(stack).putDouble("empty", 1); + + if (stack.getItem() == ModItems.M_60.get() && GunsTool.getGunIntTag(stack, "Ammo", 0) <= 5) { + GunsTool.setGunBooleanTag(stack, "HideBulletChain", true); + } + + if (stack.getItem() == ModItems.HOMEMADE_SHOTGUN.get()) { + // TODO is hurt an break correct? +// stack.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(InteractionHand.MAIN_HAND)); + stack.hurtAndBreak(1, (ServerLevel) player.level(), player, p -> { + }); + if (player instanceof ServerPlayer serverPlayer && player.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.CLOUD, player.getX() + 1.8 * player.getLookAngle().x, player.getY() + player.getBbHeight() - 0.1 + 1.8 * player.getLookAngle().y, + player.getZ() + 1.8 * player.getLookAngle().z, 30, 0.4, 0.4, 0.4, 0.005, true, serverPlayer); + } + } + + if (stack.getItem() == ModItems.SENTINEL.get()) { + var cap = stack.getCapability(Capabilities.EnergyStorage.ITEM); + if (cap != null) { + cap.extractEnergy(3000, false); + } + } + +// var perk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); + + for (int index0 = 0; index0 < ( + // todo perk +// perk instanceof AmmoPerk ammoPerk && ammoPerk.slug ? 1 : projectileAmount + projectileAmount + ); index0++) { + GunEventHandler.gunShoot(player, spared); + } + + GunEventHandler.playGunSounds(player); + } + } else if (stack.is(ModItems.MINIGUN.get())) { + var tag = NBTTool.getTag(stack); + var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE); + if (cap == null) return; + + if (cap.rifleAmmo > 0 || InventoryTool.hasCreativeAmmoBox(player)) { + 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); + } + } + + // TODO perk +// var perk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); + float pitch = tag.getDouble("heat") <= 40 ? 1 : (float) (1 - 0.025 * Math.abs(40 - tag.getDouble("heat"))); + + if (!player.level().isClientSide() && player instanceof ServerPlayer) { + float soundRadius = (float) GunsTool.getGunDoubleTag(stack, "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, spared); + if (!InventoryTool.hasCreativeAmmoBox(player)) { + cap.rifleAmmo = cap.rifleAmmo - 1; + cap.syncPlayerVariables(player); + } + } + } + } + + @Override + public @NotNull Type type() { + return TYPE; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/send/VehicleMovementMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/send/VehicleMovementMessage.java new file mode 100644 index 000000000..f90d8999a --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/send/VehicleMovementMessage.java @@ -0,0 +1,50 @@ +package com.atsuishio.superbwarfare.network.message.send; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.base.ControllableVehicle; +import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.NBTTool; +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.item.ItemStack; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import org.jetbrains.annotations.NotNull; + +public record VehicleMovementMessage(short keys) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(ModUtils.loc("vehicle_movement")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.SHORT, + VehicleMovementMessage::keys, + VehicleMovementMessage::new + ); + + public static void handler(final VehicleMovementMessage message, final IPayloadContext context) { + var player = (ServerPlayer) context.player(); + var entity = player.getVehicle(); + ItemStack stack = player.getMainHandItem(); + + VehicleEntity vehicle = null; + if (entity instanceof MobileVehicleEntity mobileVehicleEntity) { + if (mobileVehicleEntity.getFirstPassenger() != player) return; + vehicle = mobileVehicleEntity; + } else if (stack.is(ModItems.MONITOR.get()) + && NBTTool.getBoolean(stack, "Using", false) + && NBTTool.getBoolean(stack, "Linked", false) + ) vehicle = EntityFindUtil.findDrone(player.level(), NBTTool.getTag(stack).getString("LinkedDrone")); + + if (!(vehicle instanceof ControllableVehicle controllable)) return; + controllable.processInput(message.keys); + } + + @Override + public @NotNull Type type() { + return TYPE; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/CustomExplosion.java b/src/main/java/com/atsuishio/superbwarfare/tools/CustomExplosion.java index fa4244138..9074dabd6 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/CustomExplosion.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/CustomExplosion.java @@ -1,7 +1,7 @@ package com.atsuishio.superbwarfare.tools; import com.atsuishio.superbwarfare.config.server.ExplosionConfig; -import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; import com.google.common.collect.Sets; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/DamageTypeTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/DamageTypeTool.java new file mode 100644 index 000000000..7c44eaae4 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/tools/DamageTypeTool.java @@ -0,0 +1,45 @@ +package com.atsuishio.superbwarfare.tools; + +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.DamageType; + +public class DamageTypeTool { + + public static boolean isGunDamage(DamageSource source) { + return source.is(ModDamageTypes.GUN_FIRE) || source.is(ModDamageTypes.GUN_FIRE_HEADSHOT) + || source.is(ModDamageTypes.GUN_FIRE_ABSOLUTE) || source.is(ModDamageTypes.GUN_FIRE_HEADSHOT_ABSOLUTE) + || source.is(ModDamageTypes.SHOCK) || source.is(ModDamageTypes.BURN) + || source.is(ModDamageTypes.LASER) || source.is(ModDamageTypes.LASER_HEADSHOT); + } + + public static boolean isGunDamage(ResourceKey damageType) { + return damageType == ModDamageTypes.GUN_FIRE || damageType == ModDamageTypes.GUN_FIRE_HEADSHOT + || damageType == ModDamageTypes.GUN_FIRE_ABSOLUTE || damageType == ModDamageTypes.GUN_FIRE_HEADSHOT_ABSOLUTE; + } + + public static boolean isExplosionDamage(DamageSource source) { + return source.is(ModDamageTypes.CUSTOM_EXPLOSION) || source.is(ModDamageTypes.PROJECTILE_BOOM); + } + + public static boolean isHeadshotDamage(DamageSource source) { + return source.is(ModDamageTypes.GUN_FIRE_HEADSHOT) || source.is(ModDamageTypes.GUN_FIRE_HEADSHOT_ABSOLUTE); + } + + public static boolean isGunFireDamage(DamageSource source) { + return source.is(ModDamageTypes.GUN_FIRE) || source.is(ModDamageTypes.GUN_FIRE_ABSOLUTE) + || source.is(ModDamageTypes.SHOCK) || source.is(ModDamageTypes.BURN) + || source.is(ModDamageTypes.LASER) || source.is(ModDamageTypes.LASER_HEADSHOT); + } + + public static boolean isModDamage(DamageSource source) { + return source.is(ModDamageTypes.GUN_FIRE_ABSOLUTE) || source.is(ModDamageTypes.GUN_FIRE_HEADSHOT_ABSOLUTE) + || source.is(ModDamageTypes.GUN_FIRE) || source.is(ModDamageTypes.GUN_FIRE_HEADSHOT) + || source.is(ModDamageTypes.MINE) || source.is(ModDamageTypes.MINE) || source.is(ModDamageTypes.SHOCK) + || source.is(ModDamageTypes.PROJECTILE_BOOM) || source.is(ModDamageTypes.CANNON_FIRE) + || source.is(ModDamageTypes.BURN) + || source.is(ModDamageTypes.LASER) || source.is(ModDamageTypes.LASER_HEADSHOT); + } + +} diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java index d9a6b5d5b..ab7024a56 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java @@ -4,7 +4,7 @@ import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.capability.ModCapabilities; import com.atsuishio.superbwarfare.init.ModTags; import com.atsuishio.superbwarfare.item.gun.GunItem; -import com.atsuishio.superbwarfare.network.message.GunsDataMessage; +import com.atsuishio.superbwarfare.network.message.receive.GunsDataMessage; import com.google.gson.stream.JsonReader; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index e72d85370..45a9fecf1 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -1,4 +1,5 @@ public net.minecraft.client.multiplayer.ClientLevel getEntities()Lnet/minecraft/world/level/entity/LevelEntityGetter; # getEntities public net.minecraft.world.entity.Entity passengers # passengers public net.minecraft.world.entity.Entity boardingCooldown # boardingCooldown -public net.minecraft.client.player.LocalPlayer handsBusy # handsBusy \ No newline at end of file +public net.minecraft.client.player.LocalPlayer handsBusy # handsBusy +public net.minecraft.client.renderer.culling.Frustum matrix # matrix \ No newline at end of file