Bumped mod version to 0.1.4. Refactored crop harvesting and armor effects.

This commit is contained in:
IM23a-spirgif
2025-06-07 17:06:01 +02:00
parent 0e220c9371
commit 6c7f997fcb
5 changed files with 114 additions and 132 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ mod_name=Stalinium
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=MIT mod_license=MIT
# The mod version. See https://semver.org/ # The mod version. See https://semver.org/
mod_version=0.1.3 mod_version=0.1.4
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources. # This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html # See https://maven.apache.org/guides/mini/guide-naming-conventions.html
@@ -158,7 +158,6 @@ public class ComradeHandler {
}) })
) )
) )
// /comrade accept <leader>
.then(Commands.literal("accept") .then(Commands.literal("accept")
.then(Commands.argument("leader", EntityArgument.player()) .then(Commands.argument("leader", EntityArgument.player())
.executes(ctx -> { .executes(ctx -> {
@@ -196,7 +195,6 @@ public class ComradeHandler {
}) })
) )
) )
// /comrade remove <player>
.then(Commands.literal("remove") .then(Commands.literal("remove")
.then(Commands.argument("player", EntityArgument.player()) .then(Commands.argument("player", EntityArgument.player())
.executes(ctx -> { .executes(ctx -> {
@@ -1,8 +1,10 @@
package net.krituximon.stalinium.item.custom; package net.krituximon.stalinium.item.custom;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import net.krituximon.stalinium.event.ComradeHandler;
import net.krituximon.stalinium.item.ModArmorMaterials; import net.krituximon.stalinium.item.ModArmorMaterials;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects; import net.minecraft.world.effect.MobEffects;
@@ -12,14 +14,15 @@ import net.minecraft.world.item.ArmorItem;
import net.minecraft.world.item.ArmorMaterial; import net.minecraft.world.item.ArmorMaterial;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.UUID;
public class ModArmorItem extends ArmorItem { public class ModArmorItem extends ArmorItem {
private static final Map<Holder<ArmorMaterial>, List<MobEffectInstance>> MATERIAL_TO_EFFECT_MAP = private static final Map<Holder<ArmorMaterial>, List<MobEffectInstance>> MATERIAL_TO_EFFECT_MAP =
(new ImmutableMap.Builder<Holder<ArmorMaterial>, List<MobEffectInstance>>()) new ImmutableMap.Builder<Holder<ArmorMaterial>, List<MobEffectInstance>>()
.put(ModArmorMaterials.STALINIUM_ARMOR_MATERIAL, .put(ModArmorMaterials.STALINIUM_ARMOR_MATERIAL,
List.of(new MobEffectInstance(MobEffects.HEALTH_BOOST, 100, 0, false, false))) List.of(new MobEffectInstance(MobEffects.HEALTH_BOOST, 100, 0, false, false)))
.build(); .build();
@@ -29,65 +32,71 @@ public class ModArmorItem extends ArmorItem {
} }
@Override @Override
public void inventoryTick(ItemStack stack, Level level, Entity entity, int slotId, boolean isSelected) { public void inventoryTick(ItemStack stack,
if (entity instanceof Player player && !level.isClientSide() && hasFullSuitOfArmorOn(player)) { Level level,
evaluateArmorEffects(player); Entity entity,
} int slotId,
boolean isSelected) {
if (!(entity instanceof Player player) || level.isClientSide()) return;
if (!hasFullSuitOfArmorOn(player)) return;
evaluateArmorEffects(player);
} }
private void evaluateArmorEffects(Player player) { private void evaluateArmorEffects(Player player) {
for (Map.Entry<Holder<ArmorMaterial>, List<MobEffectInstance>> entry : MATERIAL_TO_EFFECT_MAP.entrySet()) { for (var entry : MATERIAL_TO_EFFECT_MAP.entrySet()) {
Holder<ArmorMaterial> mapArmorMaterial = entry.getKey(); Holder<ArmorMaterial> mat = entry.getKey();
List<MobEffectInstance> mapEffect = entry.getValue(); List<MobEffectInstance> effects = entry.getValue();
if (!hasPlayerCorrectArmorOn(mat, player)) continue;
if (hasPlayerCorrectArmorOn(mapArmorMaterial, player)) { addEffectToPlayer(player, effects);
addEffectToPlayer(player, mapEffect);
}
} }
} }
private void addEffectToPlayer(Player player, List<MobEffectInstance> mapEffect) { private void addEffectToPlayer(Player player, List<MobEffectInstance> baseEffects) {
AABB box = player.getBoundingBox().inflate(20.0); int nearbyComrades = 0;
int playersInBox = player.level().getEntitiesOfClass( Optional<ComradeHandler.Party> partyOpt = ComradeHandler.findPartyOf(player.getUUID());
Player.class, if (partyOpt.isPresent() && player.level() instanceof ServerLevel serverLevel) {
box, for (UUID memberUuid : partyOpt.get().members) {
p -> p instanceof ServerPlayer && player.isAlliedTo(p) if (memberUuid.equals(player.getUUID())) continue;
).size(); ServerPlayer online = serverLevel.getServer()
.getPlayerList()
for (MobEffectInstance effect : mapEffect) { .getPlayer(memberUuid);
int newAmplifier = Math.min(4, effect.getAmplifier() + playersInBox); if (online != null && online.distanceTo(player) <= 20.0) {
nearbyComrades++;
}
}
}
for (var base : baseEffects) {
int newAmp = Math.min(4, base.getAmplifier() + nearbyComrades);
player.addEffect(new MobEffectInstance( player.addEffect(new MobEffectInstance(
effect.getEffect(), base.getEffect(),
effect.getDuration(), base.getDuration(),
newAmplifier, newAmp,
effect.isAmbient(), base.isAmbient(),
effect.isVisible() base.isVisible()
)); ));
} }
} }
private boolean hasPlayerCorrectArmorOn(Holder<ArmorMaterial> mapArmorMaterial, Player player) { private boolean hasPlayerCorrectArmorOn(Holder<ArmorMaterial> mat, Player player) {
for (ItemStack armorStack : player.getArmorSlots()) { for (ItemStack armorStack : player.getArmorSlots()) {
if (!(armorStack.getItem() instanceof ArmorItem)) { if (!(armorStack.getItem() instanceof ArmorItem ai)
|| ai.getMaterial() != mat) {
return false; return false;
} }
} }
return true;
ArmorItem boots = ((ArmorItem) player.getInventory().getArmor(0).getItem());
ArmorItem leggings = ((ArmorItem) player.getInventory().getArmor(1).getItem());
ArmorItem chestplate = ((ArmorItem) player.getInventory().getArmor(2).getItem());
ArmorItem helmet = ((ArmorItem) player.getInventory().getArmor(3).getItem());
return boots.getMaterial() == mapArmorMaterial && leggings.getMaterial() == mapArmorMaterial
&& chestplate.getMaterial() == mapArmorMaterial && helmet.getMaterial() == mapArmorMaterial;
} }
private boolean hasFullSuitOfArmorOn(Player player) { private boolean hasFullSuitOfArmorOn(Player player) {
ItemStack boots = player.getInventory().getArmor(0); for (ItemStack armor : player.getArmorSlots()) {
ItemStack leggings = player.getInventory().getArmor(1); if (armor.isEmpty()) return false;
ItemStack chestplate = player.getInventory().getArmor(2); }
ItemStack helmet = player.getInventory().getArmor(3); return true;
return !boots.isEmpty() && !leggings.isEmpty() && !chestplate.isEmpty() && !helmet.isEmpty();
} }
@Override
public boolean isDamageable(ItemStack stack) { return false; }
@Override
public boolean isDamaged(ItemStack stack) { return false; }
} }
@@ -26,6 +26,7 @@ import java.util.*;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.tags.BlockTags; import net.minecraft.tags.BlockTags;
import org.jetbrains.annotations.NotNull;
public class StaliniumAxeItem extends AxeItem { public class StaliniumAxeItem extends AxeItem {
public StaliniumAxeItem(Tier tier, Properties properties) { public StaliniumAxeItem(Tier tier, Properties properties) {
@@ -33,20 +34,20 @@ public class StaliniumAxeItem extends AxeItem {
} }
@Override @Override
public boolean mineBlock(ItemStack stack, public boolean mineBlock(@NotNull ItemStack stack,
Level level, Level level,
BlockState state, @NotNull BlockState state,
BlockPos pos, @NotNull BlockPos pos,
LivingEntity miningEntity) { @NotNull LivingEntity miningEntity) {
if (!level.isClientSide() && state.is(BlockTags.LOGS) && miningEntity instanceof Player) { if (!level.isClientSide() && state.is(BlockTags.LOGS) && miningEntity instanceof Player) {
cutDownTree(level, pos, (Player) miningEntity, stack); cutDownTree(level, pos, (Player) miningEntity, stack);
return true; return true;
} }
return true; // allow the chain to continue return true;
} }
@Override @Override
public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { public boolean hurtEnemy(@NotNull ItemStack stack, LivingEntity target, LivingEntity attacker) {
return true; return true;
} }
@@ -1,118 +1,92 @@
package net.krituximon.stalinium.item.custom; package net.krituximon.stalinium.item.custom;
import net.krituximon.stalinium.event.ComradeHandler; import net.krituximon.stalinium.event.ComradeHandler;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.*; import net.minecraft.world.item.HoeItem;
import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Tier;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.CropBlock; import net.minecraft.world.level.block.CropBlock;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
public class StaliniumHoeItem extends HoeItem { public class StaliniumHoeItem extends HoeItem {
public StaliniumHoeItem(Tier tier, Item.Properties properties) { public StaliniumHoeItem(Tier tier, Properties props) {
super(tier, properties); super(tier, props);
} }
@Override @Override
public InteractionResult useOn(UseOnContext ctx) { public boolean mineBlock(ItemStack stack,
Level level = ctx.getLevel(); Level level,
BlockPos pos = ctx.getClickedPos(); BlockState state,
BlockState state = level.getBlockState(pos); BlockPos pos,
Player player = ctx.getPlayer(); LivingEntity miner) {
if (level.isClientSide || !(miner instanceof Player player))
return super.mineBlock(stack, level, state, pos, miner);
// Only run on server side and if it's raining at this position and the block is a CropBlock // only for fully grown crops:
if (!level.isClientSide() if (state.getBlock() instanceof CropBlock) {
&& level.isRaining()
&& level.isRainingAt(pos)
&& state.getBlock() instanceof CropBlock) {
// Collect that blocks drops
List<ItemStack> drops = Block.getDrops( List<ItemStack> drops = Block.getDrops(
state, state,
(ServerLevel) level, (ServerLevel) level,
pos, pos,
null, // no block entity null,
player, player,
ctx.getItemInHand() stack
); );
// Double each drops count and spawn them // break the crop:
for (ItemStack drop : drops) {
ItemStack doubled = drop.copy();
doubled.setCount(drop.getCount() * 2);
Block.popResource(level, pos, doubled);
}
// Destroy the block
level.setBlock(pos, Blocks.AIR.defaultBlockState(), 3); level.setBlock(pos, Blocks.AIR.defaultBlockState(), 3);
return InteractionResult.SUCCESS;
}
if (!level.isClientSide() && player != null) {
Optional<ComradeHandler.Party> partyOpt = ComradeHandler.findPartyOf(player.getUUID());
if (partyOpt.isPresent()) {
ComradeHandler.Party party = partyOpt.get();
List<Player> comrades = new ArrayList<>();
ServerLevel serverLevel = (ServerLevel) level;
for (UUID memberUuid : party.members) {
if (memberUuid.equals(player.getUUID())) continue;
ServerPlayer online = serverLevel.getServer()
.getPlayerList()
.getPlayer(memberUuid);
if (online != null) {
// Check distance (8 blocks)
if (online.distanceTo(player) <= 8.0) {
comrades.add(online);
}
}
}
// 50% chance to send normal block drops to those comrades // 1) give base drops to the harvester:
if (level.getRandom().nextFloat() < 0.5f) { for (ItemStack drop : drops) {
for (ItemStack drop : Block.getDrops(state, (ServerLevel) level, pos, null)) { player.addItem(drop.copy());
for (Player buddy : comrades) { }
buddy.addItem(drop.copy());
// 2) if raining here, give them a second batch:
if (level.isRaining() && level.isRainingAt(pos)) {
for (ItemStack drop : drops) {
ItemStack extra = drop.copy();
extra.setCount(drop.getCount());
player.addItem(extra);
}
}
// 3) 50% chance to also duplicate to each ally in range:
if (!level.isClientSide() && level.getRandom().nextFloat() < 0.5f) {
Optional<ComradeHandler.Party> partyOpt = ComradeHandler.findPartyOf(player.getUUID());
if (partyOpt.isPresent()) {
ComradeHandler.Party party = partyOpt.get();
ServerLevel sl = (ServerLevel) level;
for (UUID member : party.members) {
if (member.equals(player.getUUID())) continue;
ServerPlayer ally = sl.getServer()
.getPlayerList()
.getPlayer(member);
if (ally != null && ally.distanceTo(player) <= 8.0) {
for (ItemStack drop : drops) {
ally.addItem(drop.copy());
}
} }
} }
} }
} }
return true;
} }
return super.useOn(ctx); return super.mineBlock(stack, level, state, pos, miner);
} }
@Override @Override public boolean isDamageable(ItemStack stack) { return false; }
public boolean isDamageable(ItemStack stack) { @Override public boolean isDamaged(ItemStack stack) { return false; }
return false;
}
@Override
public boolean isDamaged(ItemStack stack) {
return false;
}
@Override
public void appendHoverText(ItemStack stack,
TooltipContext context,
List<Component> tooltipComponents,
TooltipFlag tooltipFlag) {
if (Screen.hasShiftDown()) {
tooltipComponents.add(Component.translatable("item.stalinium_hoe.tooltip_shift"));
} else {
tooltipComponents.add(Component.translatable("item.stalinium_hoe.tooltip"));
}
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
}
} }