Add particles

Add missing Textures
Add client functionality
This commit is contained in:
Bruno Rybársky 2024-08-02 15:42:51 +02:00
parent 3bd5e3d3ba
commit ec90a2e292
29 changed files with 492 additions and 71 deletions

@ -48,12 +48,14 @@ processResources {
inputs.property "version", project.version
inputs.property "minecraft_version", project.minecraft_version
inputs.property "loader_version", project.loader_version
inputs.property "trinkets_version", project.trinkets_version
filteringCharset "UTF-8"
filesMatching("fabric.mod.json") {
expand "version": project.version,
"minecraft_version": project.minecraft_version,
"loader_version": project.loader_version
"loader_version": project.loader_version,
"trinkets_version": project.trinkets_version
}
}

@ -6,7 +6,7 @@ minecraft_version=1.21
yarn_mappings=1.21+build.9
loader_version=0.16.0
# Mod Properties
mod_version=1.7
mod_version=1.9
maven_group=systems.brn
archives_base_name=plasticgun
# Dependencies

@ -3,26 +3,39 @@ package systems.brn.plasticgun;
import eu.pb4.polymer.core.api.entity.PolymerEntityUtils;
import eu.pb4.polymer.resourcepack.api.PolymerResourcePackUtils;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.player.UseItemCallback;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import systems.brn.plasticgun.bullets.BulletEntity;
import systems.brn.plasticgun.bullets.BulletItem;
import systems.brn.plasticgun.defence.WeaponArmor;
import systems.brn.plasticgun.effects.FlashbangEffect;
import systems.brn.plasticgun.effects.StunEffect;
import systems.brn.plasticgun.grenades.GrenadeEntity;
import systems.brn.plasticgun.grenades.GrenadeItem;
import systems.brn.plasticgun.guns.Gun;
import systems.brn.plasticgun.lib.CraftingItem;
import systems.brn.plasticgun.lib.EventHandler;
import systems.brn.plasticgun.lib.ItemGroups;
import systems.brn.plasticgun.packets.ModDetect;
import systems.brn.plasticgun.packets.Reload;
import systems.brn.plasticgun.packets.Shoot;
import systems.brn.plasticgun.shurikens.ShurikenEntity;
import systems.brn.plasticgun.shurikens.ShurikenItem;
import systems.brn.plasticgun.testing.DamageTester;
@ -30,8 +43,7 @@ import systems.brn.plasticgun.testing.DamageTester;
import java.util.ArrayList;
import java.util.Map;
import static systems.brn.plasticgun.lib.Util.generateItemMap;
import static systems.brn.plasticgun.lib.Util.id;
import static systems.brn.plasticgun.lib.Util.*;
public class PlasticGun implements ModInitializer {
@ -64,6 +76,13 @@ public class PlasticGun implements ModInitializer {
public static final Logger logger = LoggerFactory.getLogger(MOD_ID);
public static final ArrayList<ServerPlayerEntity> clientsWithMod = new ArrayList<>();
public static final ArrayList<Item> clickEventItems = new ArrayList<>();
public static final RegistryEntry.Reference<StatusEffect> flashbangEffect = Registry.registerReference(Registries.STATUS_EFFECT, id("flashbang"), new FlashbangEffect());
public static final RegistryEntry.Reference<StatusEffect> stunEffect = Registry.registerReference(Registries.STATUS_EFFECT, id("stun"), new StunEffect());
@Override
public void onInitialize() {
@ -91,7 +110,7 @@ public class PlasticGun implements ModInitializer {
guns.add(new Gun("forcegun", 0, 4, 5, 10, 10, 888, 5, 0, 2, 0f, 0f, 5f, 10f, 0, 0)); // 0
guns.add(new Gun("p2022", 0.2, 12, 5, 10, 41, 9, 10, 0, 0, 1f, 4, 0.1f, 0.25f, -1, 1)); // 1.8
guns.add(new Gun("colt_1903", 0.3, 10, 5, 8, 38, 32, 10, 0, 0, 1, 3, 0.1f, 0.3f, -1, 1)); // 3
guns.add(new Gun("ak_47", 0.2, 4, 5, 30, 45, 762, 1, 0, 0, 1f, 2, 0.2f, 0.4f, -1, 1)); // 9
guns.add(new Gun("ak_47", 0.2, 4, 5, 30, 45, 762, 0, 0, 0, 1f, 2, 0.2f, 0.4f, -1, 1)); // 9
guns.add(new Gun("colt_45", 0.4, 9, 5, 7, 48, 45, 10, 0, 0, 1.5f, 2, 0.15f, 0.4f, -1, 1)); // 3.6
guns.add(new Gun("snub_nosed_revolver", 0.4, 7, 3, 5, 36, 38, 20, 0, 0, 1f, 2, 0.2f, 0.45f, -1, 1)); // 2.8
guns.add(new Gun("colt_peacemaker", 0.6, 8, 5, 6, 43, 45, 10, 0, 0, 0.9f, 2, 0.2f, 0.5f, -1, 1)); // 4.8
@ -155,6 +174,10 @@ public class PlasticGun implements ModInitializer {
itemGrenadeItemMap = generateItemMap(grenades);
itemShurikenItemMap = generateItemMap(shurikens);
registerIntoClickEvents(guns);
registerIntoClickEvents(grenades);
registerIntoClickEvents(shurikens);
GRENADE_ENTITY_TYPE = Registry.register(
Registries.ENTITY_TYPE,
id("grenade"),
@ -194,8 +217,19 @@ public class PlasticGun implements ModInitializer {
ServerEntityEvents.ENTITY_LOAD.register(EventHandler::onEntityLoad);
ServerPlayConnectionEvents.DISCONNECT.register(EventHandler::disconnect);
ItemGroups.register();
PayloadTypeRegistry.playC2S().register(ModDetect.PACKET_ID, ModDetect.PACKET_CODEC);
PayloadTypeRegistry.playC2S().register(Reload.PACKET_ID, Reload.PACKET_CODEC);
PayloadTypeRegistry.playC2S().register(Shoot.PACKET_ID, Shoot.PACKET_CODEC);
// Register the global receiver
ServerPlayNetworking.registerGlobalReceiver(ModDetect.PACKET_ID, EventHandler::onClientConfirm);
ServerPlayNetworking.registerGlobalReceiver(Reload.PACKET_ID, EventHandler::onClientReload);
ServerPlayNetworking.registerGlobalReceiver(Shoot.PACKET_ID, EventHandler::onClientShoot);
PolymerResourcePackUtils.addModAssets(MOD_ID);
PolymerResourcePackUtils.markAsRequired();
logger.info("Guns are loaded");

@ -16,6 +16,7 @@ import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.hit.HitResult;
import eu.pb4.polymer.core.api.entity.PolymerEntity;
import net.minecraft.world.World;
import systems.brn.plasticgun.grenades.GrenadeExplosionBehavior;
import systems.brn.plasticgun.guns.Gun;
import systems.brn.plasticgun.lib.WeaponDamageType;
@ -95,7 +96,7 @@ public class BulletEntity extends PersistentProjectileEntity implements PolymerE
this.setPosition(blockHitResult.getPos());
if (blockHitResult.getType() == HitResult.Type.BLOCK) {
BlockState block = this.getWorld().getBlockState(blockHitResult.getBlockPos());
blockHitParticles(this.getPos(), block, this.getWorld(), this.getDamage() * this.getVelocity().length());
SoundEvent soundEvent = block.getSoundGroup().getHitSound();
setSilent(false);
playSound(soundEvent, 4.0F, 1.0F);
@ -104,7 +105,7 @@ public class BulletEntity extends PersistentProjectileEntity implements PolymerE
this.setOnFire(true);
super.onBlockHit(blockHitResult);
this.setOnFire(false);
hitDamage(blockHitResult.getPos(), explosionPower, repulsionPower, getWorld(), this, isIncendiary, null);
hitDamage(blockHitResult.getPos(), explosionPower, repulsionPower, getWorld(), this, isIncendiary, new GrenadeExplosionBehavior());
this.discard();
}
@ -114,12 +115,14 @@ public class BulletEntity extends PersistentProjectileEntity implements PolymerE
setSilent(false);
playSound(SoundEvents.BLOCK_BAMBOO_HIT, 4.0F, 1.0F);
setSilent(true);
if (entityHitResult.getEntity() instanceof LivingEntity livingEntity) {
this.setDamage(getFinalDamage(livingEntity, WeaponDamageType.BULLET, this.getDamage()));
entityHitParticles(livingEntity, this.getDamage() * this.getVelocity().length());
}
super.onEntityHit(entityHitResult);
hitDamage(entityHitResult.getPos(), explosionPower, repulsionPower, getWorld(), this, isIncendiary, null);
hitDamage(entityHitResult.getPos(), explosionPower, repulsionPower, getWorld(), this, isIncendiary, new GrenadeExplosionBehavior());
this.discard();
}

@ -0,0 +1,50 @@
package systems.brn.plasticgun.companion;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.render.RenderTickCounter;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.ColorHelper;
import systems.brn.plasticgun.packets.ModDetect;
import systems.brn.plasticgun.packets.Reload;
import systems.brn.plasticgun.packets.Shoot;
import java.util.UUID;
import static systems.brn.plasticgun.PlasticGun.flashbangEffect;
import static systems.brn.plasticgun.lib.Util.shouldSendClickEvents;
public class ClientEvents {
public static void tick(MinecraftClient minecraftClient) {
if (minecraftClient.options.useKey.isPressed() && minecraftClient.player != null) {
if (shouldSendClickEvents(minecraftClient.player)) {
UUID reloadUUID = UUID.randomUUID();
ClientPlayNetworking.send(new Reload(reloadUUID));
}
}
if (minecraftClient.options.attackKey.isPressed() && minecraftClient.player != null) {
if (shouldSendClickEvents(minecraftClient.player)) {
UUID shootUUID = UUID.randomUUID();
ClientPlayNetworking.send(new Shoot(shootUUID));
}
}
}
public static void join(ClientPlayNetworkHandler clientPlayNetworkHandler, PacketSender packetSender, MinecraftClient minecraftClient) {
UUID joinUUID = UUID.randomUUID();
packetSender.sendPacket(new ModDetect(joinUUID));
}
public static void HUDDraw(DrawContext drawContext, RenderTickCounter renderTickCounter) {
if (MinecraftClient.getInstance().player != null) {
if (MinecraftClient.getInstance().player.hasStatusEffect(flashbangEffect)) {
int width = drawContext.getScaledWindowWidth();
int height = drawContext.getScaledWindowHeight();
drawContext.fill(0, 0, width, height, ColorHelper.Argb.fromFloats(1, 1, 1, 1));
}
}
}
}

@ -0,0 +1,15 @@
package systems.brn.plasticgun.companion;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
public class PlasticGunClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
ClientTickEvents.END_CLIENT_TICK.register(ClientEvents::tick);
ClientPlayConnectionEvents.JOIN.register(ClientEvents::join);
HudRenderCallback.EVENT.register(ClientEvents::HUDDraw);
}
}

@ -0,0 +1,40 @@
package systems.brn.plasticgun.effects;
import eu.pb4.polymer.core.api.other.PolymerStatusEffect;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectCategory;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.server.network.ServerPlayerEntity;
import systems.brn.plasticgun.PlasticGun;
import static systems.brn.plasticgun.PlasticGun.flashbangEffect;
public class FlashbangEffect extends StatusEffect implements PolymerStatusEffect {
public FlashbangEffect() {
// category: StatusEffectCategory - describes if the effect is helpful (BENEFICIAL), harmful (HARMFUL) or useless (NEUTRAL)
// color: int - Color is the color assigned to the effect (in RGB)
super(StatusEffectCategory.HARMFUL, 0xe9b8b3);
}
// Called every tick to check if the effect can be applied or not
@Override
public boolean canApplyUpdateEffect(int duration, int amplifier) {
// In our case, we just make it return true so that it applies the effect every tick
return true;
}
// Called when the effect is applied.
@Override
public boolean applyUpdateEffect(LivingEntity entity, int amplifier) {
return super.applyUpdateEffect(entity, amplifier);
}
@Override
public StatusEffect getPolymerReplacement(ServerPlayerEntity player){
if (PlasticGun.clientsWithMod.contains(player)){
return flashbangEffect.value();
}
return StatusEffects.BLINDNESS.value();
}
}

@ -0,0 +1,52 @@
package systems.brn.plasticgun.effects;
import eu.pb4.polymer.core.api.other.PolymerStatusEffect;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectCategory;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.server.network.ServerPlayerEntity;
import systems.brn.plasticgun.PlasticGun;
import static systems.brn.plasticgun.PlasticGun.flashbangEffect;
import static systems.brn.plasticgun.PlasticGun.stunEffect;
public class StunEffect extends StatusEffect implements PolymerStatusEffect {
public boolean applied = false;
public int stunDuration = 0;
public StunEffect() {
// category: StatusEffectCategory - describes if the effect is helpful (BENEFICIAL), harmful (HARMFUL) or useless (NEUTRAL)
// color: int - Color is the color assigned to the effect (in RGB)
super(StatusEffectCategory.HARMFUL, 0xf02566);
}
// Called every tick to check if the effect can be applied or not
@Override
public boolean canApplyUpdateEffect(int duration, int amplifier) {
// In our case, we just make it return true so that it applies the effect every tick
if (!applied) {
stunDuration = duration;
return true;
}
return false;
}
// Called when the effect is applied.
@Override
public boolean applyUpdateEffect(LivingEntity entity, int amplifier) {
applied = true;
entity.addStatusEffect(new StatusEffectInstance(StatusEffects.SLOWNESS, stunDuration, 255, true, false));
entity.addStatusEffect(new StatusEffectInstance(StatusEffects.JUMP_BOOST, stunDuration, 255, true, false));
return super.applyUpdateEffect(entity, amplifier);
}
@Override
public StatusEffect getPolymerReplacement(ServerPlayerEntity player) {
if (PlasticGun.clientsWithMod.contains(player)){
return stunEffect.value();
}
return null;
}
}

@ -13,6 +13,7 @@ import systems.brn.plasticgun.lib.WeaponDamageType;
import java.util.ArrayList;
import static systems.brn.plasticgun.lib.Util.entityHitParticles;
import static systems.brn.plasticgun.lib.Util.getFinalDamage;
public class FragmentationExplosionBehavior extends ExplosionBehavior {
@ -66,6 +67,9 @@ public class FragmentationExplosionBehavior extends ExplosionBehavior {
float original = super.calculateDamage(explosion, entity);
if (entity instanceof LivingEntity livingEntity) {
original = (float) getFinalDamage(livingEntity, WeaponDamageType.FRAGMENTATION_GRENADE, original);
if (original > 0) {
entityHitParticles(livingEntity, original);
}
}
return original;
}

@ -14,11 +14,12 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.random.Random;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.World;
import systems.brn.plasticgun.effects.FlashbangEffect;
import systems.brn.plasticgun.throwables.ThrowableProjectile;
import java.util.List;
import static systems.brn.plasticgun.PlasticGun.GRENADE_ENTITY_TYPE;
import static systems.brn.plasticgun.PlasticGun.*;
import static systems.brn.plasticgun.lib.Util.*;
public class GrenadeEntity extends ThrowableProjectile implements PolymerEntity {
@ -118,8 +119,7 @@ public class GrenadeEntity extends ThrowableProjectile implements PolymerEntity
if (stunDuration > 0) {
for (Entity entity : nearbyEntities) {
if (entity instanceof LivingEntity livingEntity) {
livingEntity.addStatusEffect(new StatusEffectInstance(StatusEffects.SLOWNESS, stunDuration, 255, true, false));
livingEntity.addStatusEffect(new StatusEffectInstance(StatusEffects.JUMP_BOOST, stunDuration, 255, true, false));
livingEntity.addStatusEffect(new StatusEffectInstance(stunEffect, flashBangDuration, 255, true, false));
}
}
stunDuration = 0;
@ -128,7 +128,7 @@ public class GrenadeEntity extends ThrowableProjectile implements PolymerEntity
if (flashBangDuration > 0) {
for (Entity entity : nearbyEntities) {
if (entity instanceof LivingEntity livingEntity) {
livingEntity.addStatusEffect(new StatusEffectInstance(StatusEffects.BLINDNESS, flashBangDuration, 255, true, false));
livingEntity.addStatusEffect(new StatusEffectInstance(flashbangEffect, flashBangDuration, 255, true, false));
}
}
flashBangDuration = 0;

@ -6,6 +6,7 @@ import net.minecraft.world.explosion.Explosion;
import net.minecraft.world.explosion.ExplosionBehavior;
import systems.brn.plasticgun.lib.WeaponDamageType;
import static systems.brn.plasticgun.lib.Util.entityHitParticles;
import static systems.brn.plasticgun.lib.Util.getFinalDamage;
public class GrenadeExplosionBehavior extends ExplosionBehavior {
@ -16,6 +17,9 @@ public class GrenadeExplosionBehavior extends ExplosionBehavior {
float original = super.calculateDamage(explosion, entity);
if (entity instanceof LivingEntity livingEntity) {
original = (float) getFinalDamage(livingEntity, WeaponDamageType.GRENADE, original);
if (original > 0) {
entityHitParticles(livingEntity, original);
}
}
return original;
}

@ -49,7 +49,7 @@ public class GrenadeItem extends SimpleItem implements PolymerItem {
Text.translatable("gun.description.repulsion_power", repulsionPower),
Text.translatable("gun.description.explosion_time", explosionTarget),
Text.translatable("gun.description.speed", speed),
Text.translatable(isIncendiary ? "gun.description.incendiary_yes" : "gun.description.incendiary_no"),
Text.translatable(isIncendiary ? "gun.description.incendiary_yes" : "gun.description.incendiary_no"),
Text.translatable("gun.description.fragmentation_grenade", isFragmentation),
Text.translatable("gun.description.flashbang_duration", flashBangDuration),
Text.translatable("gun.description.stun_duration", stunDuration),
@ -104,8 +104,9 @@ public class GrenadeItem extends SimpleItem implements PolymerItem {
if (!player.isCreative()) {
stack.decrement(1);
}
if (!stack.isEmpty()) {
if (!stack.isEmpty()) {
stack.setDamage(0);
user.setStackInHand(hand, stack);
}
}
}

@ -63,6 +63,17 @@ public class Gun extends SimpleItem implements PolymerItem {
.component(GUN_AMMO_COMPONENT, ItemStack.EMPTY)
.component(GUN_COOLDOWN_COMPONENT, 0)
.component(GUN_RELOAD_COOLDOWN_COMPONENT, 0)
.component(DataComponentTypes.LORE, new LoreComponent(List.of(
Text.translatable("gun.description.caliber", caliber),
Text.translatable("gun.description.damage_absolute", damage),
Text.translatable("gun.description.speed", speed),
Text.translatable("gun.description.clip_size", clipSize),
Text.translatable("gun.description.reload_cooldown", reloadTarget),
Text.translatable("gun.description.reload_cycles", reloadCount),
Text.translatable("gun.description.shoot_cooldown", cooldownTarget),
Text.translatable("gun.description.explosion_power", explosionPowerGun),
Text.translatable("gun.description.repulsion_power", repulsionPowerGun)
)))
.maxDamage(clipSize + 1)
, id(path), Items.WOODEN_SWORD
);
@ -118,7 +129,7 @@ public class Gun extends SimpleItem implements PolymerItem {
stack.remove(GUN_AMMO_COMPONENT);
} else {
stack.set(GUN_AMMO_COMPONENT, chamber);
stack.set(GUN_LAST_LOADED_AMMO, bulletStack);
stack.set(GUN_LAST_LOADED_AMMO, chamber);
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.BLOCK_LEVER_CLICK, SoundCategory.PLAYERS, 0.5f, 1.0f);
}
stack.set(GUN_LOADING_COMPONENT, 1);
@ -133,7 +144,7 @@ public class Gun extends SimpleItem implements PolymerItem {
stack.remove(GUN_AMMO_COMPONENT);
} else {
stack.set(GUN_AMMO_COMPONENT, chamber);
stack.set(GUN_LAST_LOADED_AMMO, bulletStack);
stack.set(GUN_LAST_LOADED_AMMO, chamber);
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.BLOCK_LEVER_CLICK, SoundCategory.PLAYERS, 1f, 2.5f);
}
bulletStack.decrement(targetCount);
@ -143,12 +154,11 @@ public class Gun extends SimpleItem implements PolymerItem {
}
}
if (player.isCreative()) {
stack.set(GUN_AMMO_COMPONENT, new ItemStack(ammo.getFirst(), clipSize)); // Ensure ammo.get(0) is a valid item
stack.set(GUN_LAST_LOADED_AMMO, bulletStack);
ItemStack stackOfBullet = new ItemStack(ammo.getFirst(), clipSize);
stack.set(GUN_AMMO_COMPONENT, stackOfBullet);
stack.set(GUN_LAST_LOADED_AMMO, stackOfBullet);
}
updateDamage(stack);
} else {
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.PLAYERS, 1.0f, 2.0f);
}
}
}
@ -277,8 +287,6 @@ public class Gun extends SimpleItem implements PolymerItem {
} else {
stack.set(GUN_AMMO_COMPONENT, chamber);
}
} else if (cooldownTarget > 0) {
world.playSound(null, user.getX(), user.getY(), user.getZ(), SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.PLAYERS, 1.0f, 2.0f);
} else if (currentReload > 1) {
world.playSound(null, user.getX(), user.getY(), user.getZ(), SoundEvents.UI_BUTTON_CLICK.value(), SoundCategory.PLAYERS, 1.0f, 2.0f);
}

@ -1,5 +1,6 @@
package systems.brn.plasticgun.lib;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.ItemEntity;
@ -8,6 +9,8 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory;
@ -18,67 +21,85 @@ import net.minecraft.world.World;
import systems.brn.plasticgun.grenades.GrenadeEntity;
import systems.brn.plasticgun.grenades.GrenadeItem;
import systems.brn.plasticgun.guns.Gun;
import systems.brn.plasticgun.packets.ModDetect;
import systems.brn.plasticgun.packets.Reload;
import systems.brn.plasticgun.packets.Shoot;
import systems.brn.plasticgun.shurikens.ShurikenItem;
import java.util.function.Predicate;
import static systems.brn.plasticgun.PlasticGun.*;
import static systems.brn.plasticgun.lib.GunComponents.*;
public class EventHandler {
public static TypedActionResult<ItemStack> onItemUse(PlayerEntity playerEntity, World world, Hand hand) {
ItemStack stack = playerEntity.getStackInHand(hand);
if (!world.isClient) {
Item stackInHand = playerEntity.getStackInHand(hand).getItem();
if (itemGunMap.containsKey(stackInHand)) {
itemGunMap.get(stackInHand).reload(world, playerEntity, hand);
if (playerEntity instanceof ServerPlayerEntity serverPlayerEntity) {
if (!world.isClient && !clientsWithMod.contains(serverPlayerEntity)) {
rightClickWithItem(serverPlayerEntity, hand);
}
if (itemGrenadeItemMap.containsKey(stackInHand)) {
itemGrenadeItemMap.get(stackInHand).unpin(world, playerEntity, hand);
}
if (itemShurikenItemMap.containsKey(stackInHand)) {
itemShurikenItemMap.get(stackInHand).chuck(world, playerEntity, hand);
}
}
return TypedActionResult.pass(stack);
}
public static void rightClickWithItem(ServerPlayerEntity serverPlayerEntity, Hand hand) {
if (serverPlayerEntity.getEntityWorld() instanceof ServerWorld world) {
Item stackInHand = serverPlayerEntity.getStackInHand(hand).getItem();
if (itemGunMap.containsKey(stackInHand)) {
itemGunMap.get(stackInHand).reload(world, serverPlayerEntity, hand);
}
if (itemGrenadeItemMap.containsKey(stackInHand)) {
itemGrenadeItemMap.get(stackInHand).unpin(world, serverPlayerEntity, hand);
}
if (itemShurikenItemMap.containsKey(stackInHand)) {
itemShurikenItemMap.get(stackInHand).chuck(world, serverPlayerEntity, hand);
}
}
public static void onServerWorldTick(ServerWorld world) {
// Iterate through all players to detect hand swings or item interactions
for (PlayerEntity player : world.getPlayers()) {
if (!world.isClient) {
Hand hand = player.getActiveHand();
ItemStack stackInHand = player.getStackInHand(hand);
Item itemInHand = stackInHand.getItem();
}
if (itemGunMap.containsKey(itemInHand)) {
decrementComponent(GUN_COOLDOWN_COMPONENT, stackInHand);
decrementComponent(GUN_RELOAD_COOLDOWN_COMPONENT, stackInHand);
if (player.handSwinging && player.handSwingTicks == -1) {
itemGunMap.get(itemInHand).shoot(world, player, hand);
}
}
if (itemGrenadeItemMap.containsKey(itemInHand)) {
itemGrenadeItemMap.get(itemInHand).chuck(world, player, hand);
}
if (itemShurikenItemMap.containsKey(itemInHand)) {
itemShurikenItemMap.get(itemInHand).chuck(world, player, hand);
}
public static void leftClickWithItem(ServerPlayerEntity serverPlayerEntity, Hand hand) {
if (serverPlayerEntity.getEntityWorld() instanceof ServerWorld world) {
ItemStack stackInHand = serverPlayerEntity.getStackInHand(hand);
Item itemInHand = stackInHand.getItem();
if (itemGrenadeItemMap.containsKey(itemInHand)) {
itemGrenadeItemMap.get(itemInHand).chuck(world, serverPlayerEntity, hand);
} else if (itemShurikenItemMap.containsKey(itemInHand)) {
itemShurikenItemMap.get(itemInHand).chuck(world, serverPlayerEntity, hand);
} else if (itemGunMap.containsKey(itemInHand)) {
itemGunMap.get(itemInHand).shoot(world, serverPlayerEntity, hand);
}
}
}
PlayerInventory playerInventory = player.getInventory();
for (int i = 1; i < playerInventory.main.size(); i++) {
ItemStack stackInSlot = playerInventory.main.get(i);
Item itemInSlot = stackInSlot.getItem();
if (itemGrenadeItemMap.containsKey(itemInSlot)) {
decrementComponent(GRENADE_TIMER_COMPONENT, stackInSlot);
GrenadeItem grenadeItem = itemGrenadeItemMap.get(itemInSlot);
GrenadeItem.updateDamage(stackInSlot, grenadeItem);
grenadeItem.checkExplosions(world, player, stackInSlot);
}
public static void tickItemUpdate(ServerPlayerEntity serverPlayerEntity) {
if (serverPlayerEntity.getEntityWorld() instanceof ServerWorld world) {
Hand hand = serverPlayerEntity.getActiveHand();
ItemStack stackInHand = serverPlayerEntity.getStackInHand(hand);
Item itemInHand = stackInHand.getItem();
if (itemGunMap.containsKey(itemInHand)) {
decrementComponent(GUN_COOLDOWN_COMPONENT, stackInHand);
decrementComponent(GUN_RELOAD_COOLDOWN_COMPONENT, stackInHand);
}
PlayerInventory playerInventory = serverPlayerEntity.getInventory();
for (int i = 1; i < playerInventory.main.size(); i++) {
ItemStack stackInSlot = playerInventory.main.get(i);
Item itemInSlot = stackInSlot.getItem();
if (itemGrenadeItemMap.containsKey(itemInSlot)) {
decrementComponent(GRENADE_TIMER_COMPONENT, stackInSlot);
GrenadeItem grenadeItem = itemGrenadeItemMap.get(itemInSlot);
GrenadeItem.updateDamage(stackInSlot, grenadeItem);
grenadeItem.checkExplosions(world, serverPlayerEntity, stackInSlot);
}
}
}
for (SkeletonEntity skeletonEntity : world.getEntitiesByType(EntityType.SKELETON, entity -> true)) {
}
public static void mobTickUpdate(ServerWorld world) {
Predicate<Entity> allEntities = entity -> true;
for (SkeletonEntity skeletonEntity : world.getEntitiesByType(EntityType.SKELETON, allEntities)) {
for (ItemStack itemStack : skeletonEntity.getEquippedItems()) {
if (itemGunMap.containsKey(itemStack.getItem())) {
decrementComponent(GUN_COOLDOWN_COMPONENT, itemStack);
@ -88,6 +109,22 @@ public class EventHandler {
}
}
public static void onServerWorldTick(ServerWorld world) {
// Iterate through all players to detect hand swings or item interactions
if (!world.isClient) {
for (ServerPlayerEntity player : world.getPlayers()) {
Hand hand = player.getActiveHand();
if (!clientsWithMod.contains(player)) {
if (player.handSwinging && player.handSwingTicks == -1) {
leftClickWithItem(player, hand);
}
}
tickItemUpdate(player);
}
mobTickUpdate(world);
}
}
public static void onEntityLoad(Entity entity, ServerWorld world) {
if (entity instanceof ItemEntity itemEntity) {
ItemStack entityStack = itemEntity.getStack();
@ -112,4 +149,30 @@ public class EventHandler {
}
}
}
public static void disconnect(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer
minecraftServer) {
ServerPlayerEntity player = serverPlayNetworkHandler.getPlayer();
clientsWithMod.remove(player);
}
public static void onClientConfirm(ModDetect modDetect, ServerPlayNetworking.Context context) {
ServerPlayerEntity player = context.player();
if (!clientsWithMod.contains(player)) {
clientsWithMod.add(player);
}
}
public static void onClientReload(Reload reload, ServerPlayNetworking.Context context) {
ServerPlayerEntity player = context.player();
Hand hand = player.getActiveHand();
rightClickWithItem(player, hand);
}
public static void onClientShoot(Shoot shoot, ServerPlayNetworking.Context context) {
ServerPlayerEntity player = context.player();
Hand hand = player.getActiveHand();
leftClickWithItem(player, hand);
}
}

@ -8,6 +8,7 @@ import net.minecraft.item.*;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import systems.brn.plasticgun.PlasticGun;
public abstract class SimpleItem extends SimplePolymerItem implements PolymerItem {
private final PolymerModelData polymerModel;
@ -21,6 +22,9 @@ public abstract class SimpleItem extends SimplePolymerItem implements PolymerIte
@Override
public Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player) {
if (PlasticGun.clientsWithMod.contains(player)) {
return this;
}
return this.polymerModel.item();
}

@ -5,6 +5,10 @@ import dev.emi.trinkets.api.TrinketComponent;
import dev.emi.trinkets.api.TrinketInventory;
import dev.emi.trinkets.api.TrinketsApi;
import eu.pb4.polymer.virtualentity.api.tracker.DisplayTrackedData;
import net.fabricmc.loader.impl.lib.sat4j.core.Vec;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.particle.BlockDustParticle;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
@ -12,10 +16,14 @@ import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.decoration.DisplayEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.particle.BlockStateParticleEffect;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.particle.ParticleType;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.registry.Registries;
import net.minecraft.registry.tag.BlockTags;
@ -44,8 +52,7 @@ import java.util.function.Function;
import static net.minecraft.entity.projectile.AbstractWindChargeEntity.EXPLOSION_BEHAVIOR;
import static net.minecraft.world.explosion.Explosion.getExposure;
import static systems.brn.plasticgun.PlasticGun.MOD_ID;
import static systems.brn.plasticgun.PlasticGun.weaponArmors;
import static systems.brn.plasticgun.PlasticGun.*;
public class Util {
@ -209,6 +216,16 @@ public class Util {
return itemMap;
}
public static void registerIntoClickEvents(Collection<? extends Item> items) {
clickEventItems.addAll(items);
}
public static boolean shouldSendClickEvents(PlayerEntity player) {
Item mainItem = player.getMainHandStack().getItem();
Item offItem = player.getOffHandStack().getItem();
return clickEventItems.contains(mainItem) || clickEventItems.contains(offItem);
}
public static int getDifficultyAdjustedChance(LocalDifficulty localDifficulty, World world) {
Difficulty worldDifficulty = world.getDifficulty();
@ -239,4 +256,61 @@ public class Util {
// Ensure index is within bounds
return Math.min(index, size - 1);
}
public static void blockHitParticles(Vec3d pos, BlockState blockState, World worldTemp, double damage) {
if (worldTemp instanceof ServerWorld world) {
int particleCount = (int) damage * 4; // Number of particles
double radius = 1;
double heightOffset = 1;
for (int i = 0; i < particleCount; i++) {
double angle = (2 * Math.PI / particleCount) * i;
double xOffset = radius * Math.cos(angle);
double zOffset = radius * Math.sin(angle);
BlockStateParticleEffect blockStateParticleEffect = new BlockStateParticleEffect(ParticleTypes.BLOCK, blockState);
world.spawnParticles(
blockStateParticleEffect,
pos.x,
pos.y,
pos.z,
1, // Number of particles to spawn per location
xOffset, // Offset in the x-direction
(heightOffset / particleCount) * i, // Offset in the y-direction
zOffset, // Offset in the z-direction
4 // Speed of particles
);
}
}
}
public static void entityHitParticles(LivingEntity livingEntity, double damage) {
if (livingEntity.getEntityWorld() instanceof ServerWorld world) {
Vec3d pos = livingEntity.getPos();
int particleCount = (int) damage * 4; // Number of particles
double radius = livingEntity.getWidth() / 2 + 0.5; // Radius of the circle
double heightOffset = livingEntity.getHeight(); // Height offset from the entity's position
for (int i = 0; i < particleCount; i++) {
double angle = (2 * Math.PI / particleCount) * i;
double xOffset = radius * Math.cos(angle);
double zOffset = radius * Math.sin(angle);
BlockStateParticleEffect blockStateParticleEffect = new BlockStateParticleEffect(ParticleTypes.BLOCK, Blocks.REDSTONE_BLOCK.getDefaultState());
world.spawnParticles(
blockStateParticleEffect,
pos.x,
pos.y,
pos.z,
1, // Number of particles to spawn per location
xOffset, // Offset in the x-direction
(heightOffset / particleCount) * i, // Offset in the y-direction
zOffset, // Offset in the z-direction
4 // Speed of particles
);
}
}
}
}

@ -0,0 +1,21 @@
package systems.brn.plasticgun.packets;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.packet.CustomPayload;
import net.minecraft.util.Identifier;
import net.minecraft.util.Uuids;
import java.util.UUID;
public record ModDetect(UUID slapped) implements CustomPayload {
public static final CustomPayload.Id<ModDetect> PACKET_ID = new CustomPayload.Id<>(CustomPayload.id("moddetect").id());
public static final PacketCodec<RegistryByteBuf, ModDetect> PACKET_CODEC = Uuids.PACKET_CODEC.xmap(ModDetect::new, ModDetect::slapped).cast();
@Override
public Id<? extends CustomPayload> getId() {
return PACKET_ID;
}
}

@ -0,0 +1,19 @@
package systems.brn.plasticgun.packets;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.packet.CustomPayload;
import net.minecraft.util.Uuids;
import java.util.UUID;
public record Reload(UUID slapped) implements CustomPayload {
public static final Id<Reload> PACKET_ID = new Id<>(CustomPayload.id("reload").id());
public static final PacketCodec<RegistryByteBuf, Reload> PACKET_CODEC = Uuids.PACKET_CODEC.xmap(Reload::new, Reload::slapped).cast();
@Override
public Id<? extends CustomPayload> getId() {
return PACKET_ID;
}
}

@ -0,0 +1,19 @@
package systems.brn.plasticgun.packets;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.packet.CustomPayload;
import net.minecraft.util.Uuids;
import java.util.UUID;
public record Shoot(UUID slapped) implements CustomPayload {
public static final Id<Shoot> PACKET_ID = new Id<>(CustomPayload.id("shoot").id());
public static final PacketCodec<RegistryByteBuf, Shoot> PACKET_CODEC = Uuids.PACKET_CODEC.xmap(Shoot::new, Shoot::slapped).cast();
@Override
public Id<? extends CustomPayload> getId() {
return PACKET_ID;
}
}

@ -16,7 +16,7 @@ import systems.brn.plasticgun.lib.WeaponDamageType;
import systems.brn.plasticgun.throwables.ThrowableProjectile;
import static systems.brn.plasticgun.PlasticGun.*;
import static systems.brn.plasticgun.lib.Util.getFinalDamage;
import static systems.brn.plasticgun.lib.Util.*;
public class ShurikenEntity extends ThrowableProjectile implements PolymerEntity {
public ShurikenEntity(ServerPlayerEntity player, ItemStack itemStack, float speed, double damage) {
@ -33,6 +33,7 @@ public class ShurikenEntity extends ThrowableProjectile implements PolymerEntity
if (blockHitResult.getType() == HitResult.Type.BLOCK) {
BlockState block = this.getWorld().getBlockState(blockHitResult.getBlockPos());
blockHitParticles(this.getPos(), block, this.getWorld(), this.getDamage() * this.getVelocity().length());
SoundEvent soundEvent = block.getSoundGroup().getHitSound();
setSilent(false);
playSound(soundEvent, 4.0F, 1.0F);
@ -54,6 +55,7 @@ public class ShurikenEntity extends ThrowableProjectile implements PolymerEntity
protected void onEntityHit(EntityHitResult entityHitResult) {
if (entityHitResult.getEntity() instanceof LivingEntity livingEntity) {
this.setDamage(getFinalDamage(livingEntity, WeaponDamageType.SHURIKEN, this.getDamage()));
entityHitParticles(livingEntity, this.getDamage());
}
super.onEntityHit(entityHitResult);

@ -9,6 +9,7 @@ import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
@ -43,7 +44,7 @@ public class ShurikenItem extends SimpleItem implements PolymerItem {
}
public void chuck(World world, PlayerEntity user, Hand hand) {
public void chuck(ServerWorld world, PlayerEntity user, Hand hand) {
if (user instanceof ServerPlayerEntity player && !world.isClient()) {
ItemStack stack = user.getStackInHand(hand);
ShurikenEntity ShurikenEntity = new ShurikenEntity(player, stack, speed, damage);

@ -75,6 +75,8 @@
"item.plasticgun.netherite_shuriken": "Netherite Shuriken",
"item.plasticgun.kevlar_vest": "Kevlar vest",
"item.plasticgun.flak_vest": "Flak vest",
"effect.plasticgun.stun": "Stun",
"effect.plasticgun.flashbang": "Flashbang",
"trinkets.slot.chest.vest": "Vest",
"tag.item.trinkets.chest.vest": "Vest slot compatible",
"gun.description.damage_coefficient": "Damage coefficient: %d",

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

@ -7,7 +7,7 @@
"authors": [],
"contact": {},
"license": "MIT",
"icon": "assets/plasticgun/icon.png",
"icon": "assets/plasticgun/textures/icon.png",
"accessWidener" : "plasticgun.accesswidener",
"mixins": [
"plasticgun.mixins.json"
@ -16,11 +16,15 @@
"entrypoints": {
"main": [
"systems.brn.plasticgun.PlasticGun"
],
"client": [
"systems.brn.plasticgun.companion.PlasticGunClient"
]
},
"depends": {
"fabricloader": ">=${loader_version}",
"fabric": "*",
"minecraft": "${minecraft_version}"
"minecraft": "${minecraft_version}",
"trinkets": ">=${trinkets_version}"
}
}

@ -7,7 +7,6 @@
"AbstractSkeletonEntityGunMixin",
"ZombieGrenadeMixin"
],
"client": [],
"server": [],
"injectors": {
"defaultRequire": 1