From 0e1a31f3a44cb87c37846cde876d1c0976bbefbd Mon Sep 17 00:00:00 2001 From: Light_Quanta Date: Thu, 27 Mar 2025 00:44:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=89=80=E6=9C=89=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E7=B1=BB=EF=BC=8C=E5=AE=9E=E7=8E=B0=E8=8D=AF=E6=B0=B4?= =?UTF-8?q?=E6=95=88=E6=9E=9C=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/atsuishio/superbwarfare/ModUtils.java | 8 +- .../superbwarfare/init/ModLootModifier.java | 50 +++++++ .../superbwarfare/init/ModMobEffects.java | 16 +++ .../superbwarfare/init/ModPotion.java | 20 +++ .../superbwarfare/init/ModRecipes.java | 21 +++ .../superbwarfare/init/ModSerializers.java | 15 ++ .../atsuishio/superbwarfare/init/ModTabs.java | 1 + .../mobeffect/BurnMobEffect.java | 111 ++++++++++++++ .../mobeffect/ShockMobEffect.java | 135 ++++++++++++++++++ 9 files changed, 373 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/atsuishio/superbwarfare/init/ModLootModifier.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/init/ModMobEffects.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/init/ModPotion.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/init/ModRecipes.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/init/ModSerializers.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/mobeffect/BurnMobEffect.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/mobeffect/ShockMobEffect.java diff --git a/src/main/java/com/atsuishio/superbwarfare/ModUtils.java b/src/main/java/com/atsuishio/superbwarfare/ModUtils.java index 79b8a9325..b8b9a0b50 100644 --- a/src/main/java/com/atsuishio/superbwarfare/ModUtils.java +++ b/src/main/java/com/atsuishio/superbwarfare/ModUtils.java @@ -38,7 +38,7 @@ public class ModUtils { container.registerConfig(ModConfig.Type.SERVER, ServerConfig.init()); ModPerks.register(bus); -// ModSerializers.REGISTRY.register(bus); + ModSerializers.REGISTRY.register(bus); ModSounds.REGISTRY.register(bus); ModBlocks.REGISTRY.register(bus); ModBlockEntities.REGISTRY.register(bus); @@ -46,12 +46,12 @@ public class ModUtils { ModDataComponents.register(bus); ModTabs.TABS.register(bus); ModEntities.REGISTRY.register(bus); -// ModMobEffects.REGISTRY.register(bus); + ModMobEffects.REGISTRY.register(bus); ModParticleTypes.REGISTRY.register(bus); -// ModPotion.POTIONS.register(bus); + ModPotion.POTIONS.register(bus); ModMenuTypes.REGISTRY.register(bus); ModVillagers.register(bus); -// ModRecipes.RECIPE_SERIALIZERS.register(bus); + ModRecipes.RECIPE_SERIALIZERS.register(bus); // bus.addListener(this::onCommonSetup); // bus.addListener(this::onClientSetup); diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModLootModifier.java b/src/main/java/com/atsuishio/superbwarfare/init/ModLootModifier.java new file mode 100644 index 000000000..1edf074cd --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModLootModifier.java @@ -0,0 +1,50 @@ +package com.atsuishio.superbwarfare.init; + +import com.atsuishio.superbwarfare.ModUtils; +import com.mojang.serialization.MapCodec; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; +import net.neoforged.neoforge.common.loot.IGlobalLootModifier; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; + +@EventBusSubscriber(modid = ModUtils.MODID, bus = EventBusSubscriber.Bus.MOD) +public class ModLootModifier { + // TODO loot table modifier +// public static class TargetModLootTableModifier extends LootModifier { +// public static final Supplier> CODEC = Suppliers +// .memoize(() -> RecordCodecBuilder.create(instance -> codecStart(instance).and(ResourceLocation.CODEC.fieldOf("lootTable").forGetter(m -> m.lootTable)).apply(instance, TargetModLootTableModifier::new))); +// private final ResourceLocation lootTable; +// +// public TargetModLootTableModifier(LootItemCondition[] conditions, ResourceLocation lootTable) { +// super(conditions); +// this.lootTable = lootTable; +// } +// +// @Override +// protected ObjectArrayList doApply(ObjectArrayList generatedLoot, LootContext context) { +// context.getResolver().getLootTable(lootTable).getRandomItemsRaw(context, generatedLoot::add); +// return generatedLoot; +// } +// +// @Override +// public MapCodec codec() { +// return CODEC; +// } +// +//// @Override +//// public Codec codec() { +//// return CODEC.get(); +//// } +// } + + public static final DeferredRegister> LOOT_MODIFIERS = DeferredRegister.create(NeoForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, ModUtils.MODID); +// public static final DeferredHolder, Codec> LOOT_MODIFIER = LOOT_MODIFIERS.register(ModUtils.MODID + "_loot_modifier", TargetModLootTableModifier.CODEC); + + @SubscribeEvent + public static void register(FMLConstructModEvent event) { +// IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); +// event.enqueueWork(() -> LOOT_MODIFIERS.register(bus)); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModMobEffects.java b/src/main/java/com/atsuishio/superbwarfare/init/ModMobEffects.java new file mode 100644 index 000000000..57cc216da --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModMobEffects.java @@ -0,0 +1,16 @@ +package com.atsuishio.superbwarfare.init; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.mobeffect.BurnMobEffect; +import com.atsuishio.superbwarfare.mobeffect.ShockMobEffect; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.effect.MobEffect; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; + +public class ModMobEffects { + public static final DeferredRegister REGISTRY = DeferredRegister.create(BuiltInRegistries.MOB_EFFECT, ModUtils.MODID); + + public static final DeferredHolder SHOCK = REGISTRY.register("shock", ShockMobEffect::new); + public static final DeferredHolder BURN = REGISTRY.register("burn", BurnMobEffect::new); +} diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModPotion.java b/src/main/java/com/atsuishio/superbwarfare/init/ModPotion.java new file mode 100644 index 000000000..972dcc8b9 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModPotion.java @@ -0,0 +1,20 @@ +package com.atsuishio.superbwarfare.init; + +import com.atsuishio.superbwarfare.ModUtils; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.item.alchemy.Potion; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; + +@SuppressWarnings("unused") +public class ModPotion { + public static final DeferredRegister POTIONS = DeferredRegister.create(BuiltInRegistries.POTION, ModUtils.MODID); + + public static final DeferredHolder SHOCK = POTIONS.register("superbwarfare_shock", + () -> new Potion(new MobEffectInstance(ModMobEffects.SHOCK, 100, 0))); + public static final DeferredHolder STRONG_SHOCK = POTIONS.register("superbwarfare_strong_shock", + () -> new Potion(new MobEffectInstance(ModMobEffects.SHOCK, 100, 1))); + public static final DeferredHolder LONG_SHOCK = POTIONS.register("superbwarfare_long_shock", + () -> new Potion(new MobEffectInstance(ModMobEffects.SHOCK, 400, 0))); +} diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModRecipes.java b/src/main/java/com/atsuishio/superbwarfare/init/ModRecipes.java new file mode 100644 index 000000000..09a9a9d01 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModRecipes.java @@ -0,0 +1,21 @@ +package com.atsuishio.superbwarfare.init; + +import com.atsuishio.superbwarfare.ModUtils; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.neoforged.neoforge.registries.DeferredRegister; + +@SuppressWarnings("unused") +public class ModRecipes { + // TODO recipes + public static final DeferredRegister> RECIPE_SERIALIZERS = DeferredRegister.create(BuiltInRegistries.RECIPE_SERIALIZER, ModUtils.MODID); + +// public static final RegistryObject> POTION_MORTAR_SHELL_SERIALIZER = +// RECIPE_SERIALIZERS.register("potion_mortar_shell", () -> new SimpleCraftingRecipeSerializer<>(PotionMortarShellRecipe::new)); +// +// public static final RegistryObject> AMMO_BOX_ADD_AMMO_SERIALIZER = +// RECIPE_SERIALIZERS.register("ammo_box_add_ammo", () -> new SimpleCraftingRecipeSerializer<>(AmmoBoxAddAmmoRecipe::new)); +// public static final RegistryObject> AMMO_BOX_EXTRACT_AMMO_SERIALIZER = +// RECIPE_SERIALIZERS.register("ammo_box_extract_ammo", () -> new SimpleCraftingRecipeSerializer<>(AmmoBoxExtractAmmoRecipe::new)); + +} diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModSerializers.java b/src/main/java/com/atsuishio/superbwarfare/init/ModSerializers.java new file mode 100644 index 000000000..29cbaf84a --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModSerializers.java @@ -0,0 +1,15 @@ +package com.atsuishio.superbwarfare.init; + +import com.atsuishio.superbwarfare.ModUtils; +import net.minecraft.network.syncher.EntityDataSerializer; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; + +public class ModSerializers { + + // TODO serializers + public static final DeferredRegister> REGISTRY = DeferredRegister.create(NeoForgeRegistries.Keys.ENTITY_DATA_SERIALIZERS, ModUtils.MODID); + +// public static final DeferredHolder, EntityDataSerializer> INT_LIST_SERIALIZER = REGISTRY.register("int_list_serializer", +// () -> EntityDataSerializer.simple(FriendlyByteBuf::writeIntIdList, FriendlyByteBuf::readIntIdList)); +} diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModTabs.java b/src/main/java/com/atsuishio/superbwarfare/init/ModTabs.java index f042e82b5..cb120aff0 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModTabs.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModTabs.java @@ -13,6 +13,7 @@ import net.neoforged.neoforge.registries.DeferredHolder; import net.neoforged.neoforge.registries.DeferredRegister; @EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD) +@SuppressWarnings("unused") public class ModTabs { public static final DeferredRegister TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, ModUtils.MODID); diff --git a/src/main/java/com/atsuishio/superbwarfare/mobeffect/BurnMobEffect.java b/src/main/java/com/atsuishio/superbwarfare/mobeffect/BurnMobEffect.java new file mode 100644 index 000000000..1305e8e27 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/mobeffect/BurnMobEffect.java @@ -0,0 +1,111 @@ +package com.atsuishio.superbwarfare.mobeffect; + +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModMobEffects; +import com.atsuishio.superbwarfare.init.ModSounds; +import net.minecraft.core.registries.Registries; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectCategory; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.MobEffectEvent; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.GAME) +public class BurnMobEffect extends MobEffect { + + public BurnMobEffect() { + super(MobEffectCategory.HARMFUL, -12708330); + } + + @Override + public boolean applyEffectTick(LivingEntity entity, int amplifier) { + Entity attacker; + if (!entity.getPersistentData().contains("BurnAttacker")) { + attacker = null; + } else { + attacker = entity.level().getEntity(entity.getPersistentData().getInt("BurnAttacker")); + } + + entity.hurt(ModDamageTypes.causeBurnDamage(entity.level().registryAccess(), attacker), 0.6f + (0.3f * amplifier)); + entity.invulnerableTime = 0; + + if (attacker instanceof ServerPlayer player) { + player.level().playSound(null, player.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + // TODO indicator message + // ModUtils.PACKET_HANDLER.send(PacketDistributor.PLAYER.with(() -> player), new ClientIndicatorMessage(0, 5)); + } + + return false; + } + + @Override + public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) { + return duration % 20 == 0; + } + + @SubscribeEvent + public static void onEffectAdded(MobEffectEvent.Added event) { + LivingEntity living = event.getEntity(); + + MobEffectInstance instance = event.getEffectInstance(); + if (instance != null && !instance.getEffect().value().equals(ModMobEffects.BURN.value())) { + return; + } + + living.hurt(new DamageSource(living.level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolderOrThrow(DamageTypes.IN_FIRE), event.getEffectSource()), 0.6f + (0.3f * instance.getAmplifier())); + living.invulnerableTime = 0; + + if (event.getEffectSource() instanceof LivingEntity source) { + living.getPersistentData().putInt("BurnAttacker", source.getId()); + } + } + + @SubscribeEvent + public static void onEffectExpired(MobEffectEvent.Expired event) { + LivingEntity living = event.getEntity(); + + MobEffectInstance instance = event.getEffectInstance(); + if (instance == null) { + return; + } + + if (instance.getEffect().equals(ModMobEffects.BURN.get())) { + living.getPersistentData().remove("BurnAttacker"); + } + } + + @SubscribeEvent + public static void onEffectRemoved(MobEffectEvent.Remove event) { + LivingEntity living = event.getEntity(); + + MobEffectInstance instance = event.getEffectInstance(); + if (instance == null) { + return; + } + + if (instance.getEffect().equals(ModMobEffects.BURN.get())) { + living.getPersistentData().remove("BurnAttacker"); + } + } + + // TODO tick event? +// @SubscribeEvent +// public static void onLivingTick(LivingEvent.LivingTickEvent event) { +// LivingEntity living = event.getEntity(); +// +// if (living.hasEffect(ModMobEffects.BURN.get())) { +// living.setRemainingFireTicks(2); +// } +// +// if (living.isInWater()) { +// living.removeEffect(ModMobEffects.BURN.get()); +// } +// } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/mobeffect/ShockMobEffect.java b/src/main/java/com/atsuishio/superbwarfare/mobeffect/ShockMobEffect.java new file mode 100644 index 000000000..648fc5e94 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/mobeffect/ShockMobEffect.java @@ -0,0 +1,135 @@ +package com.atsuishio.superbwarfare.mobeffect; + +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModMobEffects; +import com.atsuishio.superbwarfare.init.ModSounds; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectCategory; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingDamageEvent; +import net.neoforged.neoforge.event.entity.living.MobEffectEvent; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.GAME) +public class ShockMobEffect extends MobEffect { + + public ShockMobEffect() { + super(MobEffectCategory.HARMFUL, -256); + addAttributeModifier(Attributes.MOVEMENT_SPEED, ResourceLocation.withDefaultNamespace("effect.speed"), -10.0F, AttributeModifier.Operation.ADD_VALUE); + } + + @Override + public boolean applyEffectTick(LivingEntity entity, int amplifier) { + Entity attacker; + if (!entity.getPersistentData().contains("TargetShockAttacker")) { + attacker = null; + } else { + attacker = entity.level().getEntity(entity.getPersistentData().getInt("TargetShockAttacker")); + } + + entity.hurt(ModDamageTypes.causeShockDamage(entity.level().registryAccess(), attacker), 2 + (1.25f * amplifier)); + entity.level().playSound(null, entity.getOnPos(), ModSounds.ELECTRIC.get(), SoundSource.PLAYERS, 1, 1); + + if (attacker instanceof ServerPlayer player) { + player.level().playSound(null, player.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + // TODO indicator message + // ModUtils.PACKET_HANDLER.send(PacketDistributor.PLAYER.with(() -> player), new ClientIndicatorMessage(0, 5)); + } + return false; + } + + @Override + public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) { + return duration % 20 == 0; + } + + + @SubscribeEvent + public static void onEffectAdded(MobEffectEvent.Added event) { + LivingEntity living = event.getEntity(); + + MobEffectInstance instance = event.getEffectInstance(); + if (instance == null || !ModMobEffects.SHOCK.get().equals(instance.getEffect())) { + return; + } + + if (living instanceof Player) { + if (!living.level().isClientSide()) { + living.level().playSound(null, BlockPos.containing(living.getX(), living.getY(), living.getZ()), ModSounds.SHOCK.get(), SoundSource.HOSTILE, 1, 1); + } else { + living.level().playLocalSound(living.getX(), living.getY(), living.getZ(), ModSounds.SHOCK.get(), SoundSource.HOSTILE, 1, 1, false); + } + } + + living.hurt(ModDamageTypes.causeShockDamage(living.level().registryAccess(), + event.getEffectSource()), 2 + (1.25f * instance.getAmplifier())); + + if (event.getEffectSource() instanceof LivingEntity source) { + living.getPersistentData().putInt("TargetShockAttacker", source.getId()); + } + } + + @SubscribeEvent + public static void onEffectExpired(MobEffectEvent.Expired event) { + LivingEntity living = event.getEntity(); + + MobEffectInstance instance = event.getEffectInstance(); + if (instance == null) { + return; + } + + if (instance.getEffect().value().equals(ModMobEffects.SHOCK.value())) { + living.getPersistentData().remove("TargetShockAttacker"); + } + } + + @SubscribeEvent + public static void onEffectRemoved(MobEffectEvent.Remove event) { + LivingEntity living = event.getEntity(); + + MobEffectInstance instance = event.getEffectInstance(); + if (instance == null) { + return; + } + + if (instance.getEffect().equals(ModMobEffects.SHOCK.get())) { + living.getPersistentData().remove("TargetShockAttacker"); + } + } + + // TODO tick event? +// @SubscribeEvent +// public static void onLivingTick(LivingEvent.LivingTickEvent event) { +// LivingEntity living = event.getEntity(); +// +// if (living.hasEffect(ModMobEffects.SHOCK)) { +// living.setXRot((float) Mth.nextDouble(RandomSource.create(), -23, -36)); +// living.xRotO = living.getXRot(); +// } +// } + + @SubscribeEvent + public static void onEntityAttacked(LivingDamageEvent.Pre event) { + if (event == null) return; + + DamageSource source = event.getSource(); + Entity entity = source.getDirectEntity(); + if (entity == null) return; + + if (entity instanceof LivingEntity living && living.hasEffect(ModMobEffects.SHOCK)) { + // TODO how to cancel? +// event.setCanceled(true); + } + } +}