diff --git a/src/main/java/xyz/nucleoid/extras/lobby/NEBlocks.java b/src/main/java/xyz/nucleoid/extras/lobby/NEBlocks.java index fcd604e8..25d6c791 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/NEBlocks.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/NEBlocks.java @@ -11,9 +11,11 @@ import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.piston.PistonBehavior; import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.particle.BlockStateParticleEffect; import net.minecraft.particle.DustParticleEffect; +import net.minecraft.particle.ItemStackParticleEffect; import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleTypes; import net.minecraft.registry.Registries; @@ -27,8 +29,10 @@ import xyz.nucleoid.extras.NucleoidExtras; import xyz.nucleoid.extras.lobby.block.*; import xyz.nucleoid.extras.lobby.block.tater.*; +import xyz.nucleoid.extras.lobby.particle.*; import java.util.function.Function; +import com.mojang.serialization.MapCodec; public class NEBlocks { public static final Block NUCLEOID_LOGO = registerTaterBlock("nucleoid_logo", ParticleTypes.GLOW_SQUID_INK, "bac7400dfcb9a387361a3ad7c296943eb841a9bda13ad89558e2d6efebf167bc"); @@ -80,7 +84,7 @@ public class NEBlocks { public static final Block TRANSIENT_WARPED_DOOR = register("transient_warped_door", AbstractBlock.Settings.copy(Blocks.WARPED_DOOR), settings -> new TransientDoorBlock(Blocks.WARPED_DOOR, settings)); // pale oak - public static final Block NUCLE_PAST_LOGO = registerTaterBlock("nucle_past_logo", new DustParticleEffect(0x52C471, 1), "65ed3e4d6ec42bd84d2b5e452087d454aac141a978540f6d200bd8aa863d4db8"); + public static final Block NUCLE_PAST_LOGO = registerColorTaterBlock("nucle_past_logo", 0x52C471, "65ed3e4d6ec42bd84d2b5e452087d454aac141a978540f6d200bd8aa863d4db8"); public static final Block TINY_POTATO = registerTaterBlock("tiny_potato", ParticleTypes.HEART, "573514a23245f15dbad5fb4e622163020864cce4c15d56de3adb90fa5a7137fd"); public static final Block BOTANICAL_TINY_POTATO = registerBotanicTaterBlock("botanical_potato", ParticleTypes.HEART, @@ -208,7 +212,7 @@ public class NEBlocks { public static final Block LAPIS_TATER = registerTaterBlock("lapis_tater", Blocks.LAPIS_BLOCK, "58d5cbda5c5046bf0b0f0d447c2fcc5e468707b6a4837c083af8e109aba9ce1c"); public static final Block NETHERITE_TATER = registerTaterBlock("netherite_tater", Blocks.NETHERITE_BLOCK, "664dce4fade8e5f352001eff6900d9d4b142935ebed303106539f7ad0193621f"); public static final Block QUARTZ_TATER = registerTaterBlock("quartz_tater", Blocks.QUARTZ_BLOCK, "7e7b4561d09d1a726fec3607706c9e3c77e8fc9b8c7e9c3637ca80ea0c86be21"); - public static final Block REDSTONE_TATER = registerRedstoneTaterBlock("redstone_tater", new DustParticleEffect(DustParticleEffect.RED, 1), "c47dd2536f5a5eb2bdb1ea4389d3af8ca2fd9d5d2c97c660fc5bf4d970c974de"); + public static final Block REDSTONE_TATER = registerRedstoneTaterBlock("redstone_tater", DustParticleEffect.RED, "c47dd2536f5a5eb2bdb1ea4389d3af8ca2fd9d5d2c97c660fc5bf4d970c974de"); public static final Block COPPER_TATER = registerTaterBlock("copper_tater", ParticleTypes.SCRAPE, "18207c7cf4007222691750b0783d6959261ddf72980483f7c9fcf96c2cba85b1"); public static final Block EXPOSED_COPPER_TATER = registerTaterBlock("exposed_copper_tater", ParticleTypes.SCRAPE, "bd5020090643edb5ec25d87cb1f408aad4f6018ec4bbe83d25a031ef1e705e4d"); @@ -427,7 +431,7 @@ public class NEBlocks { public static final Block SILVER_CAPSULE_TATER = registerCapsuleTaterBlock("silver_capsule_tater", 0xBFBFBF, 9, "afdce3ea1399dd0b738faaecf89cc5bdcf179b8dc4f3d7964c8cd45c89257fd1"); public static final Block GOLD_CAPSULE_TATER = registerCapsuleTaterBlock("gold_capsule_tater", 0xF1A00E, 1, "db5388834578ccb906e97d3e54aeb33edcc12d821f081b7eb04830cbd260ad81"); - public static final Block CORRUPTATER = register("corruptater", createTaterBlockSettings(), settings -> new CorruptaterBlock(settings, 2)); + public static final Block CORRUPTATER = register("corruptater", createTaterBlockSettings(), settings -> new CorruptaterBlock(settings)); public static final BlockEntityType LAUNCH_PAD_ENTITY = FabricBlockEntityTypeBuilder.create(LaunchPadBlockEntity::new, GOLD_LAUNCH_PAD, IRON_LAUNCH_PAD).build(); public static final BlockEntityType CONTRIBUTOR_STATUE_ENTITY = FabricBlockEntityTypeBuilder.create(ContributorStatueBlockEntity::new, CONTRIBUTOR_STATUE).build(); @@ -444,31 +448,37 @@ private static AbstractBlock.Settings createTaterBlockSettings() { } private static Block registerBotanicTaterBlock(String id, ParticleEffect effect, String textureUp, String textureDown) { - return register(id, createTaterBlockSettings(), settings -> new BotanicalPotatoBlock(settings, textureUp, textureDown, effect, 2)); + return register(id, createTaterBlockSettings(), settings -> new BotanicalPotatoBlock(settings, new SimpleTaterParticleSpawner(effect), textureUp, textureDown)); + } + + private static Block registerTaterBlock(String id, TaterParticleSpawner particleSpawner, String texture) { + return register(id, createTaterBlockSettings(), settings -> new CubicPotatoBlock(settings, particleSpawner, texture)); } private static Block registerTaterBlock(String id, ParticleEffect effect, String texture) { - return register(id, createTaterBlockSettings(), settings -> new CubicPotatoBlock(settings, effect, texture)); + return registerTaterBlock(id, new SimpleTaterParticleSpawner(effect), texture); } private static Block registerTaterBlock(String id, Block particleBlock, String texture) { - return register(id, createTaterBlockSettings(), settings -> new CubicPotatoBlock(settings, particleBlock, texture)); + var effect = new BlockStateParticleEffect(ParticleTypes.BLOCK, particleBlock.getDefaultState()); + return registerTaterBlock(id, effect, texture); } private static Block registerTaterBlock(String id, Item particleItem, String texture) { - return register(id, createTaterBlockSettings(), settings -> new CubicPotatoBlock(settings, particleItem, texture)); + var effect = new ItemStackParticleEffect(ParticleTypes.ITEM, new ItemStack(particleItem)); + return registerTaterBlock(id, effect, texture); } private static Block registerTaterBlock(String id, ParticleEffect effect, String texture, int particleRate) { - return register(id, createTaterBlockSettings(), settings -> new CubicPotatoBlock(settings, effect, texture, particleRate)); + return registerTaterBlock(id, new SimpleTaterParticleSpawner(effect, particleRate), texture); } private static Block registerColorPatternTaterBlock(String id, int[] pattern, String texture) { - return register(id, createTaterBlockSettings(), settings -> new ColorPatternTaterBlock(settings, pattern, texture)); + return registerTaterBlock(id, new ColorPatternTaterParticleSpawner(pattern), texture); } private static Block registerEntityEffectTaterBlock(String id, String texture) { - return register(id, createTaterBlockSettings(), settings -> new EntityEffectTaterBlock(settings, texture)); + return registerTaterBlock(id, EntityEffectTaterParticleSpawner.DEFAULT, texture); } private static Block registerLuckyTaterBlock(String id, String texture, String cooldownTexture) { @@ -476,23 +486,27 @@ private static Block registerLuckyTaterBlock(String id, String texture, String c } private static Block registerWardenTaterBlock(String id, String texture) { - return register(id, createTaterBlockSettings(), settings -> new WardenTaterBlock(settings, texture)); + return registerTaterBlock(id, new WardenTaterParticleSpawner(), texture); } private static Block registerDiceTaterBlock(String id) { return register(id, createTaterBlockSettings(), settings -> new DiceTaterBlock(settings)); } - private static Block registerTateroidBlock(String id, RegistryEntry defaultSound, double particleColor, String texture) { - return register(id, createTaterBlockSettings(), settings -> new TateroidBlock(settings, defaultSound, particleColor, texture)); + private static Block registerTateroidBlock(String id, RegistryEntry defaultSound, double defaultParticleColor, String texture) { + return register(id, createTaterBlockSettings(), settings -> new TateroidBlock(settings, defaultSound, defaultParticleColor, texture)); + } + + private static Block registerColorTaterBlock(String id, int color, String texture) { + return registerTaterBlock(id, SimpleTaterParticleSpawner.ofDust(color), texture); } private static Block registerColorTaterBlock(String id, DyeColor color, String texture) { - return register(id, createTaterBlockSettings(), settings -> new ColorTaterBlock(settings, color, texture)); + return registerTaterBlock(id, SimpleTaterParticleSpawner.ofDust(color), texture); } - private static Block registerRedstoneTaterBlock(String id, ParticleEffect effect, String texture) { - return register(id, createTaterBlockSettings(), settings -> new RedstoneTaterBlock(settings, effect, texture)); + private static Block registerRedstoneTaterBlock(String id, int color, String texture) { + return register(id, createTaterBlockSettings(), settings -> new RedstoneTaterBlock(settings, SimpleTaterParticleSpawner.ofDust(color), texture)); } private static Block registerDaylightDetectorTaterBlock(String id, String texture, boolean inverted) { @@ -508,22 +522,36 @@ private static Block registerBellTaterBlock(String id, String texture) { } private static Block registerElderGuardianParticleTaterBlock(String id, String texture) { - return register(id, createTaterBlockSettings(), settings -> new ElderGuardianParticleTater(settings, texture)); + return registerTaterBlock(id, new SimpleTaterParticleSpawner(ParticleTypes.ELDER_GUARDIAN, 10000, 50), texture); } private static Block registerCapsuleTaterBlock(String id, int color, int weight, String texture) { - return register(id, createTaterBlockSettings(), settings -> new CapsuleTaterBlock(settings, color, weight, texture)); + return register(id, createTaterBlockSettings(), settings -> new CapsuleTaterBlock(settings, RingTaterParticleSpawner.ofDust(color), weight, texture)); } private static Block registerMarkerTaterBlock(String id, Block particleBlock, String texture) { - return register(id, createTaterBlockSettings(), settings -> new MarkerTaterBlock(settings, particleBlock, texture)); + return registerTaterBlock(id, new SimpleMarkerTaterParticleSpawner(particleBlock, MarkerTaterParticleSpawner.MARKER_PLAYER_PARTICLE_RATE, SimpleMarkerTaterParticleSpawner.DEFAULT_BLOCK_PARTICLE_CHANCE), texture); } private static Block registerLightTaterBlock(String id, String texture) { - return register(id, createTaterBlockSettings(), settings -> new LightTaterBlock(settings, texture)); + return registerTaterBlock(id, LightTaterParticleSpawner.DEFAULT, texture); } public static void register() { + TaterParticleSpawnerTypes.register(); + + registerBlockType("bell_tater", BellTaterBlock.CODEC); + registerBlockType("botantical_tater", BotanicalPotatoBlock.CODEC); + registerBlockType("capsule_tater", CapsuleTaterBlock.CODEC); + registerBlockType("corruptater", CorruptaterBlock.CODEC); + registerBlockType("cubic_tater", CubicPotatoBlock.CODEC); + registerBlockType("daylight_detector_tater", DaylightDetectorTaterBlock.CODEC); + registerBlockType("dice_tater", DiceTaterBlock.CODEC); + registerBlockType("lucky_tater", LuckyTaterBlock.CODEC); + registerBlockType("redstone_tater", RedstoneTaterBlock.CODEC); + registerBlockType("target_tater", TargetTaterBlock.CODEC); + registerBlockType("tateroid", TateroidBlock.CODEC); + registerBlockEntity("launch_pad", LAUNCH_PAD_ENTITY); registerBlockEntity("contributor_statue", CONTRIBUTOR_STATUE_ENTITY); registerBlockEntity("tateroid", TATEROID_ENTITY); @@ -538,6 +566,10 @@ private static T register(String id, Block.Settings settings, return Registry.register(Registries.BLOCK, key, block); } + private static MapCodec registerBlockType(String id, MapCodec codec) { + return Registry.register(Registries.BLOCK_TYPE, NucleoidExtras.identifier(id), codec); + } + private static BlockEntityType registerBlockEntity(String id, BlockEntityType type) { Registry.register(Registries.BLOCK_ENTITY_TYPE, NucleoidExtras.identifier(id), type); PolymerBlockUtils.registerBlockEntity(type); diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/BellTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/BellTaterBlock.java index 17c991cb..f926b374 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/BellTaterBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/BellTaterBlock.java @@ -2,8 +2,14 @@ import org.jetbrains.annotations.Nullable; import xyz.nucleoid.extras.lobby.NEBlocks; +import xyz.nucleoid.extras.lobby.particle.SimpleTaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawnerTypes; import xyz.nucleoid.extras.mixin.BlockWithEntityAccessor; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockState; @@ -31,11 +37,23 @@ public class BellTaterBlock extends CubicPotatoBlock implements BlockEntityProvider { public static final BooleanProperty POWERED = Properties.POWERED; - public BellTaterBlock(Settings settings, String texture) { - super(settings, ParticleTypes.NOTE, texture); + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + createSettingsCodec(), + TaterParticleSpawnerTypes.CODEC.fieldOf("particle_spawner").forGetter(BellTaterBlock::getParticleSpawner), + Codec.STRING.fieldOf("texture").forGetter(BellTaterBlock::getItemTexture) + ).apply(instance, BellTaterBlock::new) + ); + + public BellTaterBlock(Settings settings, TaterParticleSpawner particleSpawner, String texture) { + super(settings, particleSpawner, texture); this.setDefaultState(this.stateManager.getDefaultState().with(POWERED, false)); } + public BellTaterBlock(Settings settings, String texture) { + this(settings, new SimpleTaterParticleSpawner(ParticleTypes.NOTE), texture); + } + @Override public void neighborUpdate(BlockState state, World world, BlockPos pos, Block sourceBlock, WireOrientation wireOrientation, boolean notify) { boolean bl = world.isReceivingRedstonePower(pos); @@ -101,6 +119,11 @@ public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { return new BellTaterBlockEntity(pos, state); } + @Override + public MapCodec getCodec() { + return CODEC; + } + @Override @Nullable public BlockEntityTicker getTicker(World world, BlockState state, BlockEntityType type) { diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/BotanicalPotatoBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/BotanicalPotatoBlock.java index b76d1680..c437d8c5 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/BotanicalPotatoBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/BotanicalPotatoBlock.java @@ -1,5 +1,8 @@ package xyz.nucleoid.extras.lobby.block.tater; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import eu.pb4.polymer.core.api.utils.PolymerUtils; import eu.pb4.polymer.virtualentity.api.BlockWithElementHolder; import eu.pb4.polymer.virtualentity.api.ElementHolder; @@ -13,7 +16,6 @@ import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemStack; import net.minecraft.item.ModelTransformationMode; -import net.minecraft.particle.ParticleEffect; import net.minecraft.server.world.ServerWorld; import net.minecraft.state.StateManager; import net.minecraft.state.property.Properties; @@ -26,15 +28,31 @@ import net.minecraft.world.World; import org.joml.Matrix4f; import org.joml.Vector3f; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawnerTypes; import xyz.nucleoid.extras.util.SkinEncoder; import xyz.nucleoid.packettweaker.PacketContext; public class BotanicalPotatoBlock extends TinyPotatoBlock implements BlockWithElementHolder { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + createSettingsCodec(), + TaterParticleSpawnerTypes.CODEC.fieldOf("particle_spawner").forGetter(BotanicalPotatoBlock::getParticleSpawner), + Codec.STRING.fieldOf("upper_texture").forGetter(BotanicalPotatoBlock::getItemTexture), + Codec.STRING.fieldOf("lower_texture").forGetter(b -> b.lowerTexture) + ).apply(instance, BotanicalPotatoBlock::new) + ); + + private final String lowerTexture; + private final ItemStack upStack; private final ItemStack downStack; - public BotanicalPotatoBlock(Settings settings, String upperTexture, String lowerTexture, ParticleEffect particleEffect, int particleRate) { - super(settings.nonOpaque(), upperTexture, particleEffect, particleRate); + public BotanicalPotatoBlock(Settings settings, TaterParticleSpawner particleSpawner, String upperTexture, String lowerTexture) { + super(settings.nonOpaque(), particleSpawner, upperTexture); + + this.lowerTexture = lowerTexture; + this.upStack = PolymerUtils.createPlayerHead(this.getItemTexture()); this.downStack = PolymerUtils.createPlayerHead(SkinEncoder.encode(lowerTexture)); } @@ -75,6 +93,11 @@ public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEnt return super.onUse(state, world, pos, player, hit); } + @Override + public MapCodec getCodec() { + return CODEC; + } + private class Model extends ElementHolder { private final ItemDisplayElement upPart; private final ItemDisplayElement downPart; diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CapsuleTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CapsuleTaterBlock.java index a83c43f4..38551e3b 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CapsuleTaterBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CapsuleTaterBlock.java @@ -1,53 +1,33 @@ package xyz.nucleoid.extras.lobby.block.tater; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.block.AbstractBlock; -import net.minecraft.particle.ParticleEffect; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; +import net.minecraft.util.collection.Weight; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawnerTypes; -public class CapsuleTaterBlock extends ColorTaterBlock implements LuckyTaterDrop { - private static final int PARTICLE_COUNT = 8; +public class CapsuleTaterBlock extends CubicPotatoBlock implements LuckyTaterDrop { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + createSettingsCodec(), + TaterParticleSpawnerTypes.CODEC.fieldOf("particle_spawner").forGetter(CapsuleTaterBlock::getParticleSpawner), + Weight.CODEC.fieldOf("weight").forGetter(tater -> tater.weight), + Codec.STRING.fieldOf("texture").forGetter(CapsuleTaterBlock::getItemTexture) + ).apply(instance, CapsuleTaterBlock::new) + ); - private static final double BLOCK_PARTICLE_RADIUS = 0.8; - private static final double PLAYER_PARTICLE_RADIUS = 0.5; + private final Weight weight; - private final int weight; - - public CapsuleTaterBlock(AbstractBlock.Settings settings, int color, int weight, String texture) { - super(settings, color, texture); + public CapsuleTaterBlock(AbstractBlock.Settings settings, TaterParticleSpawner particleSpawner, Weight weight, String texture) { + super(settings, particleSpawner, texture); this.weight = weight; } - @Override - public void spawnBlockParticles(ServerWorld world, BlockPos pos, ParticleEffect particleEffect) { - if (particleEffect != null && world.getRandom().nextInt(getBlockParticleChance()) == 0) { - this.spawnParticlesAround(world, particleEffect, pos.getX() + 0.5, BLOCK_PARTICLE_RADIUS, pos.getY() + 0.5, pos.getZ() + 0.5, BLOCK_PARTICLE_RADIUS, 0); - } - } - - @Override - public void spawnPlayerParticles(ServerPlayerEntity player) { - ParticleEffect particleEffect = this.getPlayerParticleEffect(player); - if (particleEffect != null) { - double radius = player.getWidth() / 2 + PLAYER_PARTICLE_RADIUS; - double y = player.getBodyY(0.5); - double centerAngle = player.getYaw() * Math.PI / 180; - - this.spawnParticlesAround(player.getServerWorld(), particleEffect, player.getX(), radius, y, player.getZ(), radius, centerAngle); - } - } - - private void spawnParticlesAround(ServerWorld world, ParticleEffect particleEffect, double centerX, double radiusX, double y, double centerZ, double radiusZ, double centerAngle) { - for (int i = 0; i < PARTICLE_COUNT; i++) { - double angle = i / (double) PARTICLE_COUNT * Math.PI * 2 + centerAngle; - - double x = centerX + Math.cos(angle) * radiusX; - double z = centerZ + Math.sin(angle) * radiusZ; - - world.spawnParticles(particleEffect, x, y, z, 1, 0, 0, 0, 0); - } + public CapsuleTaterBlock(AbstractBlock.Settings settings, TaterParticleSpawner particleSpawner, int weight, String texture) { + this(settings, particleSpawner, Weight.of(weight), texture); } @Override @@ -57,6 +37,11 @@ public boolean isFickle() { @Override public int getWeight() { - return this.weight; + return this.weight.getValue(); + } + + @Override + public MapCodec getCodec() { + return CODEC; } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/ColorPatternTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/ColorPatternTaterBlock.java deleted file mode 100644 index dda3ca24..00000000 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/ColorPatternTaterBlock.java +++ /dev/null @@ -1,23 +0,0 @@ -package xyz.nucleoid.extras.lobby.block.tater; - -import net.minecraft.particle.DustParticleEffect; -import net.minecraft.particle.ParticleEffect; - -import java.util.Arrays; - -public class ColorPatternTaterBlock extends CubicPotatoBlock { - private final ParticleEffect[] particleEffects; - - public ColorPatternTaterBlock(Settings settings, int[] pattern, String texture) { - super(settings, (ParticleEffect) null, texture); - - this.particleEffects = Arrays.stream(pattern).mapToObj(color -> - new DustParticleEffect(color, 1) - ).toArray(ParticleEffect[]::new); - } - - @Override - public ParticleEffect getParticleEffect(int time) { - return this.particleEffects[(time / 10) % this.particleEffects.length]; - } -} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/ColorTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/ColorTaterBlock.java deleted file mode 100644 index 79de1df5..00000000 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/ColorTaterBlock.java +++ /dev/null @@ -1,14 +0,0 @@ -package xyz.nucleoid.extras.lobby.block.tater; - -import net.minecraft.particle.DustParticleEffect; -import net.minecraft.util.DyeColor; - -public class ColorTaterBlock extends CubicPotatoBlock { - public ColorTaterBlock(Settings settings, int color, String texture) { - super(settings, new DustParticleEffect(color, 1), texture); - } - - public ColorTaterBlock(Settings settings, DyeColor color, String texture) { - this(settings, color.getSignColor(), texture); - } -} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CorruptaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CorruptaterBlock.java index 4370403f..f9a1c73b 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CorruptaterBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CorruptaterBlock.java @@ -1,37 +1,53 @@ package xyz.nucleoid.extras.lobby.block.tater; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import eu.pb4.polymer.core.api.utils.PolymerUtils; import net.minecraft.block.AbstractBlock; import net.minecraft.block.BlockState; -import net.minecraft.particle.ParticleEffect; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.random.Random; +import xyz.nucleoid.extras.lobby.particle.RandomTaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawnerTypes; import xyz.nucleoid.packettweaker.PacketContext; -import java.util.Random; - public final class CorruptaterBlock extends CubicPotatoBlock { - private final Random random = new Random(); - public CorruptaterBlock(AbstractBlock.Settings settings, int particleRate) { - super(settings, null, PolymerUtils.NO_TEXTURE_HEAD_VALUE, particleRate); + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + createSettingsCodec(), + TaterParticleSpawnerTypes.CODEC.fieldOf("particle_spawner").forGetter(CorruptaterBlock::getParticleSpawner) + ).apply(instance, CorruptaterBlock::new) + ); + + private final Random random = Random.createLocal(); + + public CorruptaterBlock(AbstractBlock.Settings settings, TaterParticleSpawner particleSpawner) { + super(settings, particleSpawner, PolymerUtils.NO_TEXTURE_HEAD_VALUE); } - @Override - public ParticleEffect getParticleEffect(int time) { - return getTater().getParticleEffect(time); + public CorruptaterBlock(AbstractBlock.Settings settings) { + this(settings, new RandomTaterParticleSpawner(CorruptaterBlock::getTater, RandomTaterParticleSpawner.DEFAULT_PLAYER_PARTICLE_RATE, RandomTaterParticleSpawner.DEFAULT_BLOCK_PARTICLE_CHANCE)); } @Override public String getPolymerSkinValue(BlockState state, BlockPos pos, PacketContext context) { - var tater = getTater(); + var player = context.getPlayer(); + var tater = getTater(player == null ? random : player.getRandom()); return tater.getPolymerSkinValue(tater.getDefaultState(), pos, context); } - private CubicPotatoBlock getTater() { - return CubicPotatoBlock.CUBIC_TATERS.get(random.nextInt(CubicPotatoBlock.CUBIC_TATERS.size())); - } - @Override public String getTranslationKey() { return super.getTranslationKey() + "." + random.nextInt(7); } + + @Override + public MapCodec getCodec() { + return CODEC; + } + + public static CubicPotatoBlock getTater(Random random) { + return CubicPotatoBlock.CUBIC_TATERS.get(random.nextInt(CubicPotatoBlock.CUBIC_TATERS.size())); + } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CubicPotatoBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CubicPotatoBlock.java index db7f2f52..9306d244 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CubicPotatoBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/CubicPotatoBlock.java @@ -1,55 +1,41 @@ package xyz.nucleoid.extras.lobby.block.tater; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import eu.pb4.polymer.core.api.block.PolymerHeadBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; -import net.minecraft.item.Item; import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemStack; -import net.minecraft.particle.BlockStateParticleEffect; -import net.minecraft.particle.ItemStackParticleEffect; -import net.minecraft.particle.ParticleEffect; -import net.minecraft.particle.ParticleTypes; import net.minecraft.state.StateManager; import net.minecraft.state.property.Properties; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RotationPropertyHelper; -import xyz.nucleoid.extras.util.SkinEncoder; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawnerTypes; import xyz.nucleoid.packettweaker.PacketContext; import java.util.ArrayList; import java.util.List; public class CubicPotatoBlock extends TinyPotatoBlock implements PolymerHeadBlock { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + createSettingsCodec(), + TaterParticleSpawnerTypes.CODEC.fieldOf("particle_spawner").forGetter(CubicPotatoBlock::getParticleSpawner), + Codec.STRING.fieldOf("texture").forGetter(CubicPotatoBlock::getItemTexture) + ).apply(instance, CubicPotatoBlock::new) + ); + protected static final List CUBIC_TATERS = new ArrayList<>(); - public CubicPotatoBlock(Settings settings, ParticleEffect particleEffect, String texture, int particleRate) { - super(settings, texture, particleEffect, particleRate); + public CubicPotatoBlock(Settings settings, TaterParticleSpawner particleSpawner, String texture) { + super(settings, particleSpawner, texture); CUBIC_TATERS.add(this); } - public CubicPotatoBlock(Settings settings, ParticleEffect particleEffect, String texture) { - this(settings, particleEffect, texture, 2); - } - - public CubicPotatoBlock(Settings settings, BlockState particleState, String texture) { - this(settings, new BlockStateParticleEffect(ParticleTypes.BLOCK, particleState), texture); - } - - public CubicPotatoBlock(Settings settings, Block particleBlock, String texture) { - this(settings, particleBlock.getDefaultState(), texture); - } - - public CubicPotatoBlock(Settings settings, ItemStack particleStack, String texture) { - this(settings, new ItemStackParticleEffect(ParticleTypes.ITEM, particleStack), texture); - } - - public CubicPotatoBlock(Settings settings, Item particleItem, String texture) { - this(settings, new ItemStack(particleItem), texture); - } - @Override public String getPolymerSkinValue(BlockState state, BlockPos pos, PacketContext context) { return this.getItemTexture(); @@ -69,4 +55,9 @@ public BlockState getPlacementState(ItemPlacementContext ctx) { public BlockState getPolymerBlockState(BlockState state, PacketContext context) { return Blocks.PLAYER_HEAD.getDefaultState().with(Properties.ROTATION, state.get(Properties.ROTATION)); } + + @Override + public MapCodec getCodec() { + return CODEC; + } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/DaylightDetectorTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/DaylightDetectorTaterBlock.java index 321979d9..82c81ffd 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/DaylightDetectorTaterBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/DaylightDetectorTaterBlock.java @@ -1,7 +1,13 @@ package xyz.nucleoid.extras.lobby.block.tater; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import org.jetbrains.annotations.Nullable; import xyz.nucleoid.extras.lobby.NEBlocks; +import xyz.nucleoid.extras.lobby.particle.SimpleTaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawnerTypes; import xyz.nucleoid.extras.mixin.BlockWithEntityAccessor; import net.minecraft.block.Block; @@ -11,6 +17,8 @@ import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.particle.BlockStateParticleEffect; +import net.minecraft.particle.ParticleTypes; import net.minecraft.state.StateManager; import net.minecraft.state.property.IntProperty; import net.minecraft.state.property.Properties; @@ -22,16 +30,29 @@ import net.minecraft.world.World; public class DaylightDetectorTaterBlock extends CubicPotatoBlock implements BlockEntityProvider { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + createSettingsCodec(), + TaterParticleSpawnerTypes.CODEC.fieldOf("particle_spawner").forGetter(DaylightDetectorTaterBlock::getParticleSpawner), + Codec.STRING.fieldOf("texture").forGetter(DaylightDetectorTaterBlock::getItemTexture), + Codec.BOOL.fieldOf("inverted").forGetter(tater -> tater.inverted) + ).apply(instance, DaylightDetectorTaterBlock::new) + ); + public static final IntProperty POWER = Properties.POWER; public final boolean inverted; - public DaylightDetectorTaterBlock(Settings settings, String texture, boolean inverted) { - super(settings, Blocks.DAYLIGHT_DETECTOR.getDefaultState().with(Properties.INVERTED, inverted), texture); + public DaylightDetectorTaterBlock(Settings settings, TaterParticleSpawner particleSpawner, String texture, boolean inverted) { + super(settings, particleSpawner, texture); this.inverted = inverted; this.setDefaultState(this.stateManager.getDefaultState().with(POWER, 0)); } + public DaylightDetectorTaterBlock(Settings settings, String texture, boolean inverted) { + this(settings, new SimpleTaterParticleSpawner(new BlockStateParticleEffect(ParticleTypes.BLOCK, Blocks.DAYLIGHT_DETECTOR.getDefaultState().with(Properties.INVERTED, inverted))), texture, inverted); + } + @Override public boolean emitsRedstonePower(BlockState state) { return true; @@ -84,4 +105,9 @@ protected void appendProperties(StateManager.Builder builder) super.appendProperties(builder); builder.add(POWER); } + + @Override + public MapCodec getCodec() { + return CODEC; + } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/DiceTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/DiceTaterBlock.java index 8b948a6c..da49d01e 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/DiceTaterBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/DiceTaterBlock.java @@ -1,5 +1,7 @@ package xyz.nucleoid.extras.lobby.block.tater; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -15,10 +17,20 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.random.Random; import net.minecraft.world.World; +import xyz.nucleoid.extras.lobby.particle.SimpleTaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawnerTypes; import xyz.nucleoid.extras.util.SkinEncoder; import xyz.nucleoid.packettweaker.PacketContext; public class DiceTaterBlock extends CubicPotatoBlock { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + createSettingsCodec(), + TaterParticleSpawnerTypes.CODEC.fieldOf("particle_spawner").forGetter(DiceTaterBlock::getParticleSpawner) + ).apply(instance, DiceTaterBlock::new) + ); + private static final int ROLLING_FACE = 0; private static final int MAX_FACE = 6; private static final int ROLLING_TICKS = 8; @@ -33,12 +45,16 @@ public class DiceTaterBlock extends CubicPotatoBlock { SkinEncoder.encode("9c40bf70f1648b7ee438a6a22904228ab5fbbd4926af30ae8ade4df01b8d7413"), }; - public DiceTaterBlock(Settings settings) { - super(settings, ParticleTypes.POOF, TEXTURES[6]); + public DiceTaterBlock(Settings settings, TaterParticleSpawner particleSpawner) { + super(settings, particleSpawner, TEXTURES[6]); this.setDefaultState(this.stateManager.getDefaultState().with(FACE, 1)); } + public DiceTaterBlock(Settings settings) { + this(settings, new SimpleTaterParticleSpawner(ParticleTypes.POOF)); + } + private boolean isRolling(BlockState state) { return state.get(FACE) == ROLLING_FACE; } @@ -90,4 +106,9 @@ public String getPolymerSkinValue(BlockState state, BlockPos pos, PacketContext int face = state.get(FACE); return TEXTURES[face]; } + + @Override + public MapCodec getCodec() { + return CODEC; + } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/ElderGuardianParticleTater.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/ElderGuardianParticleTater.java deleted file mode 100644 index 863a6c10..00000000 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/ElderGuardianParticleTater.java +++ /dev/null @@ -1,14 +0,0 @@ -package xyz.nucleoid.extras.lobby.block.tater; - -import net.minecraft.particle.ParticleTypes; - -public class ElderGuardianParticleTater extends CubicPotatoBlock { - public ElderGuardianParticleTater(Settings settings, String texture) { - super(settings, ParticleTypes.ELDER_GUARDIAN, texture, 10000); - } - - @Override - public int getBlockParticleChance() { - return 50; - } -} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/EntityEffectTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/EntityEffectTaterBlock.java deleted file mode 100644 index 2cc0c31e..00000000 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/EntityEffectTaterBlock.java +++ /dev/null @@ -1,23 +0,0 @@ -package xyz.nucleoid.extras.lobby.block.tater; - -import net.minecraft.particle.EntityEffectParticleEffect; -import net.minecraft.particle.ParticleEffect; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.util.math.random.Random; - -public class EntityEffectTaterBlock extends CubicPotatoBlock { - private final Random random = Random.createLocal(); - - public EntityEffectTaterBlock(Settings settings, String texture) { - super(settings, (ParticleEffect) null, texture); - } - - @Override - public ParticleEffect getParticleEffect(int time) { - float r = (float) (this.random.nextGaussian() * 0.2); - float g = (float) (this.random.nextGaussian() * 0.2); - float b = (float) (this.random.nextGaussian() * 0.2); - - return EntityEffectParticleEffect.create(ParticleTypes.ENTITY_EFFECT, r, g, b); - } -} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/LightTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/LightTaterBlock.java deleted file mode 100644 index 7df616eb..00000000 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/LightTaterBlock.java +++ /dev/null @@ -1,44 +0,0 @@ -package xyz.nucleoid.extras.lobby.block.tater; - -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.LightBlock; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.particle.BlockStateParticleEffect; -import net.minecraft.particle.ParticleEffect; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; - -public class LightTaterBlock extends MarkerTaterBlock { - public LightTaterBlock(Settings settings, String texture) { - super(settings, Blocks.LIGHT, texture); - } - - @Override - public ParticleEffect getBlockParticleEffect(BlockState state, ServerWorld world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { - return getLightParticle(world.getLightLevel(pos)); - } - - @Override - public double getPlayerParticleYOffset() { - return 3; - } - - @Override - public ParticleEffect getPlayerParticleEffect(ServerPlayerEntity player) { - BlockPos pos = BlockPos.ofFloored(player.getX(), player.getY() + this.getPlayerParticleYOffset(), player.getZ()); - - return getLightParticle(player.getWorld().getLightLevel(pos)); - } - - private static BlockState getLightState(int level) { - return Blocks.LIGHT.getDefaultState().with(LightBlock.LEVEL_15, level); - } - - private static ParticleEffect getLightParticle(int level) { - return new BlockStateParticleEffect(ParticleTypes.BLOCK_MARKER, getLightState(level)); - } -} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/LuckyTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/LuckyTaterBlock.java index 094f073f..98836457 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/LuckyTaterBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/LuckyTaterBlock.java @@ -1,14 +1,14 @@ package xyz.nucleoid.extras.lobby.block.tater; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.SharedConstants; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.particle.DustColorTransitionParticleEffect; -import net.minecraft.particle.ParticleEffect; import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; @@ -22,11 +22,24 @@ import net.minecraft.util.math.Direction; import net.minecraft.util.math.random.Random; import net.minecraft.world.World; +import xyz.nucleoid.extras.lobby.particle.LuckyTaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleContext; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawnerTypes; import xyz.nucleoid.extras.tag.NEBlockTags; import xyz.nucleoid.extras.util.SkinEncoder; import xyz.nucleoid.packettweaker.PacketContext; public class LuckyTaterBlock extends CubicPotatoBlock { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + createSettingsCodec(), + TaterParticleSpawnerTypes.CODEC.fieldOf("particle_spawner").forGetter(LuckyTaterBlock::getParticleSpawner), + Codec.STRING.fieldOf("texture").forGetter(LuckyTaterBlock::getItemTexture), + Codec.STRING.fieldOf("cooldown_texture").forGetter(tater -> tater.cooldownTexture) + ).apply(instance, LuckyTaterBlock::new) + ); + private static final EnumProperty PHASE = EnumProperty.of("phase", LuckyTaterPhase.class); private static final int COURAGE_TICKS = 5; @@ -34,20 +47,18 @@ public class LuckyTaterBlock extends CubicPotatoBlock { private final String cooldownTexture; - public LuckyTaterBlock(Settings settings, String texture, String cooldownTexture) { - super(settings, (ParticleEffect) null, texture); + public LuckyTaterBlock(Settings settings, TaterParticleSpawner particleSpawner, String texture, String cooldownTexture) { + super(settings, particleSpawner, texture); this.cooldownTexture = SkinEncoder.encode(cooldownTexture); this.setDefaultState(this.stateManager.getDefaultState().with(PHASE, LuckyTaterPhase.READY)); } - @Override - public ParticleEffect getPlayerParticleEffect(ServerPlayerEntity player) { - int fromColor = LuckyTaterBlock.getRandomColor(player.getRandom()); - int toColor = LuckyTaterBlock.getRandomColor(player.getRandom()); + public LuckyTaterBlock(Settings settings, String texture, String cooldownTexture) { + super(settings, LuckyTaterParticleSpawner.DEFAULT, texture); + this.cooldownTexture = SkinEncoder.encode(cooldownTexture); - int scale = player.getRandom().nextInt(3); - return new DustColorTransitionParticleEffect(fromColor, toColor, scale); + this.setDefaultState(this.stateManager.getDefaultState().with(PHASE, LuckyTaterPhase.READY)); } @Override @@ -76,8 +87,7 @@ public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEnt world.setBlockState(allowed.pos(), dropState); // Spawn particles - ParticleEffect particleEffect = taterDrop.getBlockParticleEffect(taterDrop.getDefaultState(), serverWorld, pos, player, hit); - this.spawnBlockParticles(serverWorld, pos, particleEffect); + taterDrop.getParticleSpawner().trySpawn(new TaterParticleContext.Block(pos, serverWorld)); // Play sound float pitch = 0.5f + world.getRandom().nextFloat() * 0.4f; @@ -176,7 +186,8 @@ public String getPolymerSkinValue(BlockState state, BlockPos pos, PacketContext return state.get(PHASE) == LuckyTaterPhase.COOLDOWN ? this.cooldownTexture : super.getPolymerSkinValue(state, pos, context); } - private static int getRandomColor(Random random) { - return random.nextInt() * 0xFFFFFF; + @Override + public MapCodec getCodec() { + return CODEC; } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/MarkerTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/MarkerTaterBlock.java deleted file mode 100644 index 2fc88ea3..00000000 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/MarkerTaterBlock.java +++ /dev/null @@ -1,48 +0,0 @@ -package xyz.nucleoid.extras.lobby.block.tater; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.particle.BlockStateParticleEffect; -import net.minecraft.particle.ParticleEffect; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; - -public class MarkerTaterBlock extends CubicPotatoBlock { - public MarkerTaterBlock(Settings settings, BlockState particleState, String texture) { - super(settings, new BlockStateParticleEffect(ParticleTypes.BLOCK_MARKER, particleState), texture, 12); - } - - public MarkerTaterBlock(Settings settings, Block particleBlock, String texture) { - this(settings, particleBlock.getDefaultState(), texture); - } - - public double getPlayerParticleYOffset() { - return 0.5; - } - - @Override - public void spawnPlayerParticles(ServerPlayerEntity player) { - ParticleEffect particleEffect = this.getPlayerParticleEffect(player); - - if (particleEffect != null) { - double x = player.getX(); - double y = player.getY() + this.getPlayerParticleYOffset(); - double z = player.getZ(); - - player.getServerWorld().spawnParticles(particleEffect, x, y, z, 1, 0, 0, 0, 0); - } - } - - @Override - public void spawnBlockParticles(ServerWorld world, BlockPos pos, ParticleEffect particleEffect) { - if (particleEffect != null && world.getRandom().nextInt(getBlockParticleChance()) == 0) { - double x = pos.getX() + 0.5; - double y = pos.getY() + 1.15; - double z = pos.getZ() + 0.5; - - world.spawnParticles(particleEffect, x, y, z, 1, 0, 0, 0, 0); - } - } -} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/RedstoneTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/RedstoneTaterBlock.java index c9db4335..f761e60e 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/RedstoneTaterBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/RedstoneTaterBlock.java @@ -1,14 +1,26 @@ package xyz.nucleoid.extras.lobby.block.tater; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.block.BlockState; -import net.minecraft.particle.ParticleEffect; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.BlockView; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawnerTypes; public class RedstoneTaterBlock extends CubicPotatoBlock { - public RedstoneTaterBlock(Settings settings, ParticleEffect particleEffect, String texture) { - super(settings, particleEffect, texture); + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + createSettingsCodec(), + TaterParticleSpawnerTypes.CODEC.fieldOf("particle_spawner").forGetter(RedstoneTaterBlock::getParticleSpawner), + Codec.STRING.fieldOf("texture").forGetter(RedstoneTaterBlock::getItemTexture) + ).apply(instance, RedstoneTaterBlock::new) + ); + + public RedstoneTaterBlock(Settings settings, TaterParticleSpawner particleSpawner, String texture) { + super(settings, particleSpawner, texture); } @Override @@ -20,4 +32,9 @@ public boolean emitsRedstonePower(BlockState state) { public int getWeakRedstonePower(BlockState state, BlockView world, BlockPos pos, Direction direction) { return 15; } + + @Override + public MapCodec getCodec() { + return CODEC; + } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TargetTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TargetTaterBlock.java index 83d63c86..ac3841a3 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TargetTaterBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TargetTaterBlock.java @@ -1,5 +1,8 @@ package xyz.nucleoid.extras.lobby.block.tater; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.advancement.criterion.Criteria; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -7,6 +10,8 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.projectile.PersistentProjectileEntity; import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.particle.BlockStateParticleEffect; +import net.minecraft.particle.ParticleTypes; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.stat.Stats; @@ -22,17 +27,32 @@ import net.minecraft.world.BlockView; import net.minecraft.world.World; import net.minecraft.world.WorldAccess; +import xyz.nucleoid.extras.lobby.particle.SimpleTaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawnerTypes; public class TargetTaterBlock extends CubicPotatoBlock { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + createSettingsCodec(), + TaterParticleSpawnerTypes.CODEC.fieldOf("particle_spawner").forGetter(TargetTaterBlock::getParticleSpawner), + Codec.STRING.fieldOf("texture").forGetter(TargetTaterBlock::getItemTexture) + ).apply(instance, TargetTaterBlock::new) + ); + private static final IntProperty POWER = Properties.POWER; private static final int RECOVERABLE_POWER_DELAY = 20; private static final int REGULAR_POWER_DELAY = 8; - public TargetTaterBlock(Settings settings, String texture) { - super(settings, Blocks.TARGET, texture); + public TargetTaterBlock(Settings settings, TaterParticleSpawner particleSpawner, String texture) { + super(settings, particleSpawner, texture); this.setDefaultState(this.stateManager.getDefaultState().with(POWER, 0)); } + public TargetTaterBlock(Settings settings, String texture) { + this(settings, new SimpleTaterParticleSpawner(new BlockStateParticleEffect(ParticleTypes.BLOCK, Blocks.TARGET.getDefaultState())), texture); + } + @Override public void onProjectileHit(World world, BlockState state, BlockHitResult hit, ProjectileEntity projectile) { int power = TargetTaterBlock.trigger(world, state, hit, projectile); @@ -99,4 +119,9 @@ public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState world.setBlockState(pos, state.with(POWER, 0), Block.NOTIFY_LISTENERS | Block.FORCE_STATE); } } + + @Override + public MapCodec getCodec() { + return CODEC; + } } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TateroidBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TateroidBlock.java index f051eb83..77b2006f 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TateroidBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TateroidBlock.java @@ -1,5 +1,8 @@ package xyz.nucleoid.extras.lobby.block.tater; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.SharedConstants; import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; @@ -8,11 +11,8 @@ import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleTypes; import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundEvent; import net.minecraft.state.StateManager.Builder; import net.minecraft.state.property.BooleanProperty; @@ -20,29 +20,42 @@ import net.minecraft.util.ActionResult; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.minecraft.world.block.WireOrientation; import xyz.nucleoid.extras.lobby.NEBlocks; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawnerTypes; +import xyz.nucleoid.extras.lobby.particle.TateroidParticleSpawner; import xyz.nucleoid.extras.mixin.BlockWithEntityAccessor; public class TateroidBlock extends CubicPotatoBlock implements BlockEntityProvider { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + createSettingsCodec(), + SoundEvent.ENTRY_CODEC.fieldOf("default_sound").forGetter(TateroidBlock::getDefaultSound), + TaterParticleSpawnerTypes.CODEC.fieldOf("particle_spawner").forGetter(TateroidBlock::getParticleSpawner), + Codec.STRING.fieldOf("texture").forGetter(TateroidBlock::getItemTexture) + ).apply(instance, TateroidBlock::new) + ); + private static final BooleanProperty POWERED = Properties.POWERED; private static final int FULL_DURATION = 15 * SharedConstants.TICKS_PER_SECOND; private final RegistryEntry defaultSound; - private final double particleColor; - public TateroidBlock(Settings settings, RegistryEntry defaultSound, double particleColor, String texture) { - super(settings, ParticleTypes.NOTE, texture); + public TateroidBlock(Settings settings, RegistryEntry defaultSound, TaterParticleSpawner particleSpawner, String texture) { + super(settings, particleSpawner, texture); this.defaultSound = defaultSound; - this.particleColor = particleColor; this.setDefaultState(this.stateManager.getDefaultState().with(POWERED, false)); } + public TateroidBlock(Settings settings, RegistryEntry defaultSound, double defaultParticleColor, String texture) { + this(settings, defaultSound, new TateroidParticleSpawner(ParticleTypes.NOTE, TateroidParticleSpawner.DEFAULT_PLAYER_PARTICLE_RATE, TateroidParticleSpawner.DEFAULT_BLOCK_PARTICLE_CHANCE, defaultParticleColor), texture); + } + private void activate(World world, BlockPos pos, int duration) { var optional = world.getBlockEntity(pos, NEBlocks.TATEROID_ENTITY); if (optional.isPresent()) { @@ -63,38 +76,6 @@ private int getDurationFromPower(int power) { return (int) (FULL_DURATION * (power / (float) Properties.LEVEL_15_MAX)); } - @Override - public void spawnBlockParticles(ServerWorld world, BlockPos pos, ParticleEffect particleEffect) { - if (particleEffect != null && world.getRandom().nextInt(getBlockParticleChance()) == 0) { - world.getBlockEntity(pos, NEBlocks.TATEROID_ENTITY).ifPresent(blockEntity -> { - world.spawnParticles(particleEffect, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 0, 1, 0, 0, blockEntity.getParticleSpeed()); - }); - } - } - - @Override - public void spawnPlayerParticles(ServerPlayerEntity player) { - if (this.particleColor == -1) { - super.spawnPlayerParticles(player); - return; - } - - Box box = player.getBoundingBox(); - - double deltaX = box.getLengthX() / 2d; - double deltaY = box.getLengthY() / 2d; - double deltaZ = box.getLengthZ() / 2d; - - double x = player.getX() + (player.getRandom().nextGaussian() * deltaX); - double y = player.getY() + (player.getRandom().nextGaussian() * deltaY); - double z = player.getZ() + (player.getRandom().nextGaussian() * deltaZ); - - ParticleEffect particleEffect = this.getPlayerParticleEffect(player); - if (particleEffect != null) { - player.getServerWorld().spawnParticles(particleEffect, x, y, z, 0, 1, 0, 0, this.particleColor); - } - } - @Override public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { ActionResult result = super.onUse(state, world, pos, player, hit); @@ -150,6 +131,11 @@ public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { return new TateroidBlockEntity(pos, state); } + @Override + public MapCodec getCodec() { + return CODEC; + } + @Override public BlockEntityTicker getTicker(World world, BlockState state, BlockEntityType type) { return world.isClient() ? null : BlockWithEntityAccessor.validateTicker(type, NEBlocks.TATEROID_ENTITY, TateroidBlockEntity::serverTick); diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TinyPotatoBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TinyPotatoBlock.java index 2ac7bade..faa7acbc 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TinyPotatoBlock.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/TinyPotatoBlock.java @@ -2,20 +2,20 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.MapCodec; import eu.pb4.polymer.core.api.block.PolymerBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.particle.ParticleEffect; import net.minecraft.registry.Registries; import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.ActionResult; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; import net.minecraft.world.World; +import xyz.nucleoid.extras.lobby.particle.TaterParticleContext; +import xyz.nucleoid.extras.lobby.particle.TaterParticleSpawner; import xyz.nucleoid.extras.util.SkinEncoder; import java.util.ArrayList; @@ -32,60 +32,18 @@ public abstract class TinyPotatoBlock extends Block implements PolymerBlock { public static final List TATERS = new ArrayList<>(); - private final ParticleEffect particleEffect; - private final int particleRate; + private final TaterParticleSpawner particleSpawner; private final String texture; - public TinyPotatoBlock(Settings settings, String texture, ParticleEffect particleEffect, int particleRate) { + public TinyPotatoBlock(Settings settings, TaterParticleSpawner particleSpawner, String texture) { super(settings); - this.particleEffect = particleEffect; - this.particleRate = particleRate; + this.particleSpawner = particleSpawner; this.texture = SkinEncoder.encode(texture); TATERS.add(this); } - public ParticleEffect getParticleEffect(int time) { - return this.particleEffect; - } - - public ParticleEffect getBlockParticleEffect(BlockState state, ServerWorld world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { - return this.getParticleEffect(world.getServer().getTicks()); - } - - public void spawnBlockParticles(ServerWorld world, BlockPos pos, ParticleEffect particleEffect) { - if (particleEffect != null && world.getRandom().nextInt(getBlockParticleChance()) == 0) { - world.spawnParticles(particleEffect, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, - 1, 0.5, 0.5, 0.5, 0.2); - } - } - - public ParticleEffect getPlayerParticleEffect(ServerPlayerEntity player) { - return this.getParticleEffect(player.getServer().getTicks()); - } - - public int getBlockParticleChance() { - return 1; - } - - public int getPlayerParticleRate(ServerPlayerEntity player) { - return particleRate; - } - - public void spawnPlayerParticles(ServerPlayerEntity player) { - Box box = player.getBoundingBox(); - - double deltaX = box.getLengthX() / 2d; - double deltaY = box.getLengthY() / 2d; - double deltaZ = box.getLengthZ() / 2d; - - double x = player.getX(); - double y = player.getY(); - double z = player.getZ(); - - ParticleEffect particleEffect = this.getPlayerParticleEffect(player); - if (particleEffect != null) { - player.getServerWorld().spawnParticles(particleEffect, x, y, z, 1, deltaX, deltaY, deltaZ, 0.2); - } + public TaterParticleSpawner getParticleSpawner() { + return this.particleSpawner; } /** @@ -103,10 +61,11 @@ public final String getItemTexture() { @Override public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { if (world instanceof ServerWorld serverWorld) { - ParticleEffect particleEffect = this.getBlockParticleEffect(state, serverWorld, pos, player, hit); - this.spawnBlockParticles(serverWorld, pos, particleEffect); + this.particleSpawner.trySpawn(new TaterParticleContext.Block(pos, serverWorld)); } return ActionResult.SUCCESS_SERVER; } + + public abstract MapCodec getCodec(); } diff --git a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/WardenTaterBlock.java b/src/main/java/xyz/nucleoid/extras/lobby/block/tater/WardenTaterBlock.java deleted file mode 100644 index cdac0502..00000000 --- a/src/main/java/xyz/nucleoid/extras/lobby/block/tater/WardenTaterBlock.java +++ /dev/null @@ -1,83 +0,0 @@ -package xyz.nucleoid.extras.lobby.block.tater; - -import it.unimi.dsi.fastutil.longs.LongArrayList; -import it.unimi.dsi.fastutil.longs.LongList; -import net.minecraft.SharedConstants; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.particle.ParticleEffect; -import net.minecraft.particle.VibrationParticleEffect; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.event.BlockPositionSource; -import xyz.nucleoid.extras.tag.NEBlockTags; - -public class WardenTaterBlock extends CubicPotatoBlock { - private static final int BOX_SIZE = 16; - private static final int ARRIVAL_TICKS = SharedConstants.TICKS_PER_SECOND; - - public WardenTaterBlock(Settings settings, String texture) { - super(settings, (ParticleEffect) null, texture); - } - - @Override - public ParticleEffect getBlockParticleEffect(BlockState state, ServerWorld world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { - return getTaterVibrationParticleEffect(pos, world); - } - - public void spawnBlockParticles(ServerWorld world, BlockPos pos, ParticleEffect particleEffect) { - if (particleEffect != null && world.getRandom().nextInt(getBlockParticleChance()) == 0) { - world.spawnParticles(particleEffect, pos.getX() + 0.5, pos.getY() + 0.25, pos.getZ() + 0.5, 1, 0, 0, 0, 0); - } - } - - @Override - public ParticleEffect getPlayerParticleEffect(ServerPlayerEntity player) { - BlockPos pos = BlockPos.ofFloored(player.getX(), player.getEyeY() - 0.2, player.getZ()); - return getTaterVibrationParticleEffect(pos, player.getServerWorld()); - } - - @Override - public int getPlayerParticleRate(ServerPlayerEntity player) { - return ARRIVAL_TICKS; - } - - @Override - public void spawnPlayerParticles(ServerPlayerEntity player) {; - double x = player.getX(); - double y = player.getEyeY() - 0.2; - double z = player.getZ(); - - ParticleEffect particleEffect = this.getPlayerParticleEffect(player); - if (particleEffect != null) { - player.getServerWorld().spawnParticles(particleEffect, x, y, z, 1, 0, 0, 0, 0); - } - } - - private static ParticleEffect getTaterVibrationParticleEffect(BlockPos pos, ServerWorld world) { - LongList taters = new LongArrayList(); - - int range = (int) (BOX_SIZE / 2d); - for (BlockPos taterPos : BlockPos.iterateOutwards(pos, range, range, range)) { - BlockState state = world.getBlockState(taterPos); - if (isVibrationTater(state)) { - taters.add(taterPos.asLong()); - } - } - - if (taters.isEmpty()) { - return null; - } - - int index = world.getRandom().nextInt(taters.size()); - BlockPos taterPos = BlockPos.fromLong(taters.getLong(index)); - - return new VibrationParticleEffect(new BlockPositionSource(taterPos), (int) Math.floor(Math.sqrt(pos.getSquaredDistance(taterPos)))); - } - - private static boolean isVibrationTater(BlockState state) { - return state.getBlock() instanceof TinyPotatoBlock && !state.isIn(NEBlockTags.NON_VIBRATING_TATERS); - } -} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/ColorPatternTaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/ColorPatternTaterParticleSpawner.java new file mode 100644 index 00000000..0ecd442e --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/ColorPatternTaterParticleSpawner.java @@ -0,0 +1,47 @@ +package xyz.nucleoid.extras.lobby.particle; + +import java.util.stream.IntStream; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.particle.DustParticleEffect; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleTypes; +import xyz.nucleoid.codecs.MoreCodecs; + +public class ColorPatternTaterParticleSpawner extends DynamicTaterParticleSpawner { + private static final Codec PARTICLES_CODEC = MoreCodecs.listToArray(ParticleTypes.TYPE_CODEC.listOf(), ParticleEffect[]::new); + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + PARTICLES_CODEC.fieldOf("particles").forGetter(spawner -> spawner.particleEffects), + PLAYER_PARTICLE_RATE_CODEC.forGetter(ColorPatternTaterParticleSpawner::getPlayerParticleRate), + BLOCK_PARTICLE_CHANCE_CODEC.forGetter(ColorPatternTaterParticleSpawner::getBlockParticleChance) + ).apply(instance, ColorPatternTaterParticleSpawner::new) + ); + + private final ParticleEffect[] particleEffects; + + public ColorPatternTaterParticleSpawner(ParticleEffect[] particleEffects, int playerParticleRate, int blockParticleChance) { + super(playerParticleRate, blockParticleChance); + + this.particleEffects = particleEffects; + } + + public ColorPatternTaterParticleSpawner(int[] pattern) { + this(IntStream.of(pattern).mapToObj(color -> + new DustParticleEffect(color, 1) + ).toArray(ParticleEffect[]::new), DEFAULT_PLAYER_PARTICLE_RATE, DEFAULT_BLOCK_PARTICLE_CHANCE); + } + + @Override + public ParticleEffect getParticleEffect(TaterParticleContext context) { + return this.particleEffects[(context.getTime() / 10) % this.particleEffects.length]; + } + + @Override + public MapCodec getCodec() { + return CODEC; + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/DynamicTaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/DynamicTaterParticleSpawner.java new file mode 100644 index 00000000..840cdc48 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/DynamicTaterParticleSpawner.java @@ -0,0 +1,41 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.MapCodec; +import net.minecraft.util.dynamic.Codecs; + +public abstract class DynamicTaterParticleSpawner extends TaterParticleSpawner { + public static final int DEFAULT_PLAYER_PARTICLE_RATE = 2; + public static final int DEFAULT_BLOCK_PARTICLE_CHANCE = 1; + + protected static final MapCodec PLAYER_PARTICLE_RATE_CODEC = Codecs.POSITIVE_INT.optionalFieldOf("player_particle_rate", DEFAULT_PLAYER_PARTICLE_RATE); + protected static final MapCodec BLOCK_PARTICLE_CHANCE_CODEC = Codecs.POSITIVE_INT.optionalFieldOf("block_particle_chance", DEFAULT_BLOCK_PARTICLE_CHANCE); + + private final int playerParticleRate; + private final int blockParticleChance; + + public DynamicTaterParticleSpawner(int playerParticleRate, int blockParticleChance) { + this.playerParticleRate = playerParticleRate; + this.blockParticleChance = blockParticleChance; + } + + protected final int getPlayerParticleRate() { + return this.playerParticleRate; + } + + protected final int getBlockParticleChance() { + return this.blockParticleChance; + } + + @Override + public boolean shouldSpawn(TaterParticleContext context) { + if (context instanceof TaterParticleContext.Player playerContext) { + return playerContext.player().age % this.playerParticleRate == 0; + } else if (context instanceof TaterParticleContext.Block) { + return context.world().getRandom().nextInt(this.blockParticleChance) == 0; + } + + return super.shouldSpawn(context); + } + @Override + public abstract MapCodec getCodec(); +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/EntityEffectTaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/EntityEffectTaterParticleSpawner.java new file mode 100644 index 00000000..0f4b6915 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/EntityEffectTaterParticleSpawner.java @@ -0,0 +1,39 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.particle.EntityEffectParticleEffect; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.util.math.random.Random; + +public class EntityEffectTaterParticleSpawner extends DynamicTaterParticleSpawner { + public static final EntityEffectTaterParticleSpawner DEFAULT = new EntityEffectTaterParticleSpawner(DEFAULT_PLAYER_PARTICLE_RATE, DEFAULT_BLOCK_PARTICLE_CHANCE); + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + PLAYER_PARTICLE_RATE_CODEC.forGetter(EntityEffectTaterParticleSpawner::getPlayerParticleRate), + BLOCK_PARTICLE_CHANCE_CODEC.forGetter(EntityEffectTaterParticleSpawner::getBlockParticleChance) + ).apply(instance, EntityEffectTaterParticleSpawner::new) + ); + + private final Random random = Random.createLocal(); + + public EntityEffectTaterParticleSpawner(int playerParticleRate, int blockParticleChance) { + super(playerParticleRate, blockParticleChance); + } + + @Override + public ParticleEffect getParticleEffect(TaterParticleContext context) { + float r = (float) (this.random.nextGaussian() * 0.2); + float g = (float) (this.random.nextGaussian() * 0.2); + float b = (float) (this.random.nextGaussian() * 0.2); + + return EntityEffectParticleEffect.create(ParticleTypes.ENTITY_EFFECT, r, g, b); + } + + @Override + public MapCodec getCodec() { + return CODEC; + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/LightTaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/LightTaterParticleSpawner.java new file mode 100644 index 00000000..99614633 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/LightTaterParticleSpawner.java @@ -0,0 +1,59 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.LightBlock; +import net.minecraft.particle.BlockStateParticleEffect; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.util.math.BlockPos; + +public class LightTaterParticleSpawner extends MarkerTaterParticleSpawner { + public static final LightTaterParticleSpawner DEFAULT = new LightTaterParticleSpawner(MARKER_PLAYER_PARTICLE_RATE, DEFAULT_BLOCK_PARTICLE_CHANCE); + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + PLAYER_PARTICLE_RATE_CODEC.forGetter(LightTaterParticleSpawner::getPlayerParticleRate), + BLOCK_PARTICLE_CHANCE_CODEC.forGetter(LightTaterParticleSpawner::getBlockParticleChance) + ).apply(instance, LightTaterParticleSpawner::new) + ); + + public LightTaterParticleSpawner(int playerParticleRate, int blockParticleChance) { + super(playerParticleRate, blockParticleChance); + } + + @Override + protected double getPlayerParticleOffsetY() { + return 3; + } + + private BlockPos getLightSamplePos(TaterParticleContext context) { + var pos = context.getPos(); + double offsetY = context instanceof TaterParticleContext.Player ? this.getPlayerParticleOffsetY() : 0; + + return BlockPos.ofFloored(pos.getX(), pos.getY() + offsetY, pos.getZ()); + } + + @Override + public ParticleEffect getParticleEffect(TaterParticleContext context) { + var pos = this.getLightSamplePos(context); + int level = context.world().getLightLevel(pos); + + return getLightParticle(level); + } + + @Override + public MapCodec getCodec() { + return CODEC; + } + + private static BlockState getLightState(int level) { + return Blocks.LIGHT.getDefaultState().with(LightBlock.LEVEL_15, level); + } + + private static ParticleEffect getLightParticle(int level) { + return new BlockStateParticleEffect(ParticleTypes.BLOCK_MARKER, getLightState(level)); + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/LuckyTaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/LuckyTaterParticleSpawner.java new file mode 100644 index 00000000..59c33875 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/LuckyTaterParticleSpawner.java @@ -0,0 +1,42 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.particle.DustColorTransitionParticleEffect; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.util.math.random.Random; + +public class LuckyTaterParticleSpawner extends DynamicTaterParticleSpawner { + public static final LuckyTaterParticleSpawner DEFAULT = new LuckyTaterParticleSpawner(DEFAULT_PLAYER_PARTICLE_RATE, DEFAULT_BLOCK_PARTICLE_CHANCE); + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + PLAYER_PARTICLE_RATE_CODEC.forGetter(LuckyTaterParticleSpawner::getPlayerParticleRate), + BLOCK_PARTICLE_CHANCE_CODEC.forGetter(LuckyTaterParticleSpawner::getBlockParticleChance) + ).apply(instance, LuckyTaterParticleSpawner::new) + ); + + public LuckyTaterParticleSpawner(int playerParticleRate, int blockParticleChance) { + super(playerParticleRate, blockParticleChance); + } + + @Override + protected ParticleEffect getParticleEffect(TaterParticleContext context) { + var random = context.world().getRandom(); + + int fromColor = getRandomColor(random); + int toColor = getRandomColor(random); + + int scale = random.nextInt(3); + return new DustColorTransitionParticleEffect(fromColor, toColor, scale); + } + + @Override + public MapCodec getCodec() { + return CODEC; + } + + private static int getRandomColor(Random random) { + return random.nextInt() * 0xFFFFFF; + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/MarkerTaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/MarkerTaterParticleSpawner.java new file mode 100644 index 00000000..d2cb5050 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/MarkerTaterParticleSpawner.java @@ -0,0 +1,34 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.MapCodec; + +public abstract class MarkerTaterParticleSpawner extends DynamicTaterParticleSpawner { + public static final int MARKER_PLAYER_PARTICLE_RATE = 12; + + public MarkerTaterParticleSpawner(int playerParticleRate, int blockParticleChance) { + super(playerParticleRate, blockParticleChance); + } + + protected double getPlayerParticleOffsetY() { + return 0.5; + } + + @Override + protected void spawn(TaterParticleContext context) { + var pos = context.getPos(); + double offsetY = context instanceof TaterParticleContext.Player ? this.getPlayerParticleOffsetY() : 0.65; + + double x = pos.getX(); + double y = pos.getY() + offsetY; + double z = pos.getZ(); + + var particleEffect = this.getParticleEffect(context); + + if (particleEffect != null) { + context.world().spawnParticles(particleEffect, x, y, z, 1, 0, 0, 0, 0); + } + } + + @Override + public abstract MapCodec getCodec(); +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/RandomTaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/RandomTaterParticleSpawner.java new file mode 100644 index 00000000..b9a4f7b7 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/RandomTaterParticleSpawner.java @@ -0,0 +1,41 @@ +package xyz.nucleoid.extras.lobby.particle; + +import java.util.function.Function; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.util.math.random.Random; +import xyz.nucleoid.extras.lobby.block.tater.CorruptaterBlock; +import xyz.nucleoid.extras.lobby.block.tater.CubicPotatoBlock; + +public class RandomTaterParticleSpawner extends DynamicTaterParticleSpawner { + private static final MapCodec> TATER_SUPPLIER_CODEC = MapCodec.unit(CorruptaterBlock::getTater); + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + TATER_SUPPLIER_CODEC.forGetter(spawner -> spawner.taterSupplier), + PLAYER_PARTICLE_RATE_CODEC.forGetter(RandomTaterParticleSpawner::getPlayerParticleRate), + BLOCK_PARTICLE_CHANCE_CODEC.forGetter(RandomTaterParticleSpawner::getBlockParticleChance) + ).apply(instance, RandomTaterParticleSpawner::new) + ); + + private final Function taterSupplier; + + public RandomTaterParticleSpawner(Function taterSupplier, int playerParticleRate, int blockParticleChance) { + super(playerParticleRate, blockParticleChance); + + this.taterSupplier = taterSupplier; + } + + @Override + public ParticleEffect getParticleEffect(TaterParticleContext context) { + var tater = this.taterSupplier.apply(context.world().getRandom()); + return tater.getParticleSpawner().getParticleEffect(context); + } + + @Override + public MapCodec getCodec() { + return CODEC; + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/RingTaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/RingTaterParticleSpawner.java new file mode 100644 index 00000000..a8651688 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/RingTaterParticleSpawner.java @@ -0,0 +1,62 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.particle.DustParticleEffect; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.MathHelper; + +public class RingTaterParticleSpawner extends SimpleTaterParticleSpawner { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + PARTICLE_CODEC.forGetter(RingTaterParticleSpawner::getParticleEffect), + PLAYER_PARTICLE_RATE_CODEC.forGetter(RingTaterParticleSpawner::getPlayerParticleRate), + BLOCK_PARTICLE_CHANCE_CODEC.forGetter(RingTaterParticleSpawner::getBlockParticleChance) + ).apply(instance, RingTaterParticleSpawner::new) + ); + + private static final int PARTICLE_COUNT = 8; + + private static final double BLOCK_PARTICLE_RADIUS = 0.8; + private static final double PLAYER_PARTICLE_RADIUS = 0.5; + + public RingTaterParticleSpawner(ParticleEffect particleEffect, int playerParticleRate, int blockParticleChance) { + super(particleEffect, playerParticleRate, blockParticleChance); + } + + @Override + protected void spawn(TaterParticleContext context) { + var pos = context.getPos(); + double y = context instanceof TaterParticleContext.Player playerContext ? playerContext.player().getBodyY(0.5) : pos.getY(); + + double radius = context instanceof TaterParticleContext.Player playerContext ? (playerContext.player().getWidth() / 2 + PLAYER_PARTICLE_RADIUS) : BLOCK_PARTICLE_RADIUS; + double centerAngle = context instanceof TaterParticleContext.Player playerContext ? (playerContext.player().getYaw() * MathHelper.RADIANS_PER_DEGREE) : 0; + + var particleEffect = this.getParticleEffect(context); + + if (particleEffect != null) { + this.spawnParticlesAround(context.world(), particleEffect, pos.getX(), radius, y, pos.getZ(), radius, centerAngle); + } + } + + @Override + public MapCodec getCodec() { + return CODEC; + } + + private void spawnParticlesAround(ServerWorld world, ParticleEffect particleEffect, double centerX, double radiusX, double y, double centerZ, double radiusZ, double centerAngle) { + for (int i = 0; i < PARTICLE_COUNT; i++) { + double angle = i / (double) PARTICLE_COUNT * Math.PI * 2 + centerAngle; + + double x = centerX + Math.cos(angle) * radiusX; + double z = centerZ + Math.sin(angle) * radiusZ; + + world.spawnParticles(particleEffect, x, y, z, 1, 0, 0, 0, 0); + } + } + + public static TaterParticleSpawner ofDust(int color) { + return new RingTaterParticleSpawner(new DustParticleEffect(color, 1), SimpleTaterParticleSpawner.DEFAULT_PLAYER_PARTICLE_RATE, SimpleTaterParticleSpawner.DEFAULT_BLOCK_PARTICLE_CHANCE); + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/SimpleMarkerTaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/SimpleMarkerTaterParticleSpawner.java new file mode 100644 index 00000000..24a40cb0 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/SimpleMarkerTaterParticleSpawner.java @@ -0,0 +1,39 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.block.Block; +import net.minecraft.particle.BlockStateParticleEffect; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.registry.Registries; + +public class SimpleMarkerTaterParticleSpawner extends MarkerTaterParticleSpawner { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + Registries.BLOCK.getCodec().fieldOf("block").forGetter(spawner -> spawner.block), + PLAYER_PARTICLE_RATE_CODEC.forGetter(SimpleMarkerTaterParticleSpawner::getPlayerParticleRate), + BLOCK_PARTICLE_CHANCE_CODEC.forGetter(SimpleMarkerTaterParticleSpawner::getBlockParticleChance) + ).apply(instance, SimpleMarkerTaterParticleSpawner::new) + ); + + private final Block block; + private final ParticleEffect particleEffect; + + public SimpleMarkerTaterParticleSpawner(Block block, int playerParticleRate, int blockParticleChance) { + super(playerParticleRate, blockParticleChance); + + this.block = block; + this.particleEffect = new BlockStateParticleEffect(ParticleTypes.BLOCK_MARKER, block.getDefaultState()); + } + + @Override + protected ParticleEffect getParticleEffect(TaterParticleContext context) { + return this.particleEffect; + } + + @Override + public MapCodec getCodec() { + return CODEC; + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/SimpleTaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/SimpleTaterParticleSpawner.java new file mode 100644 index 00000000..99104d39 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/SimpleTaterParticleSpawner.java @@ -0,0 +1,58 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.particle.DustParticleEffect; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.util.DyeColor; + +public class SimpleTaterParticleSpawner extends DynamicTaterParticleSpawner { + protected static final MapCodec PARTICLE_CODEC = ParticleTypes.TYPE_CODEC.fieldOf("particle"); + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + PARTICLE_CODEC.forGetter(SimpleTaterParticleSpawner::getParticleEffect), + PLAYER_PARTICLE_RATE_CODEC.forGetter(SimpleTaterParticleSpawner::getPlayerParticleRate), + BLOCK_PARTICLE_CHANCE_CODEC.forGetter(SimpleTaterParticleSpawner::getBlockParticleChance) + ).apply(instance, SimpleTaterParticleSpawner::new) + ); + + private final ParticleEffect particleEffect; + + public SimpleTaterParticleSpawner(ParticleEffect particleEffect, int playerParticleRate, int blockParticleChance) { + super(playerParticleRate, blockParticleChance); + + this.particleEffect = particleEffect; + } + + public SimpleTaterParticleSpawner(ParticleEffect particleEffect, int playerParticleRate) { + this(particleEffect, playerParticleRate, DEFAULT_BLOCK_PARTICLE_CHANCE); + } + + public SimpleTaterParticleSpawner(ParticleEffect particleEffect) { + this(particleEffect, DEFAULT_PLAYER_PARTICLE_RATE); + } + + protected final ParticleEffect getParticleEffect() { + return this.particleEffect; + } + + @Override + public ParticleEffect getParticleEffect(TaterParticleContext context) { + return this.particleEffect; + } + + @Override + public MapCodec getCodec() { + return CODEC; + } + + public static TaterParticleSpawner ofDust(int color) { + return new SimpleTaterParticleSpawner(new DustParticleEffect(color, 1)); + } + + public static TaterParticleSpawner ofDust(DyeColor color) { + return ofDust(color.getSignColor()); + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/TaterParticleContext.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/TaterParticleContext.java new file mode 100644 index 00000000..11274450 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/TaterParticleContext.java @@ -0,0 +1,76 @@ +package xyz.nucleoid.extras.lobby.particle; + +import java.util.Optional; + +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; + +public sealed interface TaterParticleContext { + ServerWorld world(); + + Vec3d getPos(); + + Vec3d getEyePos(); + + Box getBox(); + + Optional getBlockEntity(BlockEntityType type); + + default int getTime() { + return this.world().getServer().getTicks(); + } + + record Player(ServerPlayerEntity player) implements TaterParticleContext { + @Override + public ServerWorld world() { + return this.player.getServerWorld(); + } + + @Override + public Vec3d getPos() { + return this.player.getPos(); + } + + @Override + public Vec3d getEyePos() { + return new Vec3d(player.getX(), player.getEyeY() - 0.2, player.getZ()); + } + + @Override + public Box getBox() { + return this.player.getBoundingBox(); + } + + @Override + public Optional getBlockEntity(BlockEntityType type) { + return Optional.empty(); + } + } + + record Block(BlockPos blockPos, ServerWorld world) implements TaterParticleContext { + @Override + public Vec3d getPos() { + return this.blockPos.toCenterPos(); + } + + @Override + public Vec3d getEyePos() { + return Vec3d.ofCenter(this.blockPos, 0.25); + } + + @Override + public Box getBox() { + return new Box(this.blockPos); + } + + @Override + public Optional getBlockEntity(BlockEntityType type) { + return this.world.getBlockEntity(this.blockPos, type); + } + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/TaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/TaterParticleSpawner.java new file mode 100644 index 00000000..ac96c50d --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/TaterParticleSpawner.java @@ -0,0 +1,46 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.MapCodec; +import org.jetbrains.annotations.Nullable; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.util.math.MathHelper; + +public abstract class TaterParticleSpawner { + protected boolean shouldSpawn(TaterParticleContext context) { + return true; + } + + @Nullable + protected abstract ParticleEffect getParticleEffect(TaterParticleContext context); + + protected double getParticleSpeed(TaterParticleContext context) { + return 0.2; + } + + public final void trySpawn(TaterParticleContext context) { + if (this.shouldSpawn(context)) { + this.spawn(context); + } + } + + protected void spawn(TaterParticleContext context) { + var box = context.getBox(); + + double deltaX = box.getLengthX() / 2d; + double deltaY = box.getLengthY() / 2d; + double deltaZ = box.getLengthZ() / 2d; + + double x = MathHelper.lerp(0.5, box.minX, box.maxX); + double y = MathHelper.lerp(0.5, box.minY, box.maxY); + double z = MathHelper.lerp(0.5, box.minZ, box.maxZ); + + var particleEffect = this.getParticleEffect(context); + double particleSpeed = this.getParticleSpeed(context); + + if (particleEffect != null) { + context.world().spawnParticles(particleEffect, x, y, z, 1, deltaX, deltaY, deltaZ, particleSpeed); + } + } + + public abstract MapCodec getCodec(); +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/TaterParticleSpawnerTypes.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/TaterParticleSpawnerTypes.java new file mode 100644 index 00000000..86017c5b --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/TaterParticleSpawnerTypes.java @@ -0,0 +1,33 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.MapCodec; +import xyz.nucleoid.extras.NucleoidExtras; +import xyz.nucleoid.plasmid.api.util.TinyRegistry; + +import java.util.function.Function; + +public final class TaterParticleSpawnerTypes { + public static final TinyRegistry> REGISTRY = TinyRegistry.create(); + + public static final MapCodec CODEC = TaterParticleSpawnerTypes.REGISTRY.dispatchMap(TaterParticleSpawner::getCodec, Function.identity()); + + private TaterParticleSpawnerTypes() { + } + + public static void register() { + register("color_pattern", ColorPatternTaterParticleSpawner.CODEC); + register("entity_effect", EntityEffectTaterParticleSpawner.CODEC); + register("light", LightTaterParticleSpawner.CODEC); + register("lucky", LuckyTaterParticleSpawner.CODEC); + register("random", RandomTaterParticleSpawner.CODEC); + register("ring", RingTaterParticleSpawner.CODEC); + register("simple_marker", SimpleMarkerTaterParticleSpawner.CODEC); + register("simple", SimpleTaterParticleSpawner.CODEC); + register("tateroid", TateroidParticleSpawner.CODEC); + register("warden", WardenTaterParticleSpawner.CODEC); + } + + private static void register(String id, MapCodec codec) { + REGISTRY.register(NucleoidExtras.identifier(id), codec); + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/TateroidParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/TateroidParticleSpawner.java new file mode 100644 index 00000000..c0f20ac7 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/TateroidParticleSpawner.java @@ -0,0 +1,75 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.util.math.Vec3d; +import xyz.nucleoid.extras.lobby.NEBlocks; + +public class TateroidParticleSpawner extends SimpleTaterParticleSpawner { + public static final MapCodec DEFAULT_PARTICLE_COLOR_CODEC = Codec.DOUBLE.fieldOf("default_particle_color"); + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + PARTICLE_CODEC.forGetter(TateroidParticleSpawner::getParticleEffect), + PLAYER_PARTICLE_RATE_CODEC.forGetter(TateroidParticleSpawner::getPlayerParticleRate), + BLOCK_PARTICLE_CHANCE_CODEC.forGetter(TateroidParticleSpawner::getBlockParticleChance), + DEFAULT_PARTICLE_COLOR_CODEC.forGetter(spawner -> spawner.defaultParticleColor) + ).apply(instance, TateroidParticleSpawner::new) + ); + + private final double defaultParticleColor; + + public TateroidParticleSpawner(ParticleEffect particleEffect, int playerParticleRate, int blockParticleChance, double defaultParticleColor) { + super(particleEffect, playerParticleRate, blockParticleChance); + + this.defaultParticleColor = defaultParticleColor; + } + + @Override + protected double getParticleSpeed(TaterParticleContext context) { + return context.getBlockEntity(NEBlocks.TATEROID_ENTITY) + .map(blockEntity -> blockEntity.getParticleSpeed()) + .orElse(this.defaultParticleColor); + } + + private Vec3d getPos(TaterParticleContext context) { + var pos = context.getPos(); + + if (context instanceof TaterParticleContext.Block) { + return pos; + } + + var box = context.getBox(); + var random = context.world().getRandom(); + + double deltaX = box.getLengthX() / 2d; + double deltaY = box.getLengthY() / 2d; + double deltaZ = box.getLengthZ() / 2d; + + return pos.add(random.nextGaussian() * deltaX, random.nextGaussian() * deltaY, random.nextGaussian() * deltaZ); + } + + @Override + protected void spawn(TaterParticleContext context) { + double particleSpeed = this.getParticleSpeed(context); + + if (particleSpeed < 0) { + super.spawn(context); + return; + } + + var pos = this.getPos(context); + var particleEffect = this.getParticleEffect(context); + + if (particleEffect != null) { + context.world().spawnParticles(particleEffect, pos.getX(), pos.getY(), pos.getZ(), 0, 1, 0, 0, particleSpeed); + } + } + + @Override + public MapCodec getCodec() { + return CODEC; + } +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/particle/WardenTaterParticleSpawner.java b/src/main/java/xyz/nucleoid/extras/lobby/particle/WardenTaterParticleSpawner.java new file mode 100644 index 00000000..64588d15 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/particle/WardenTaterParticleSpawner.java @@ -0,0 +1,89 @@ +package xyz.nucleoid.extras.lobby.particle; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import org.jetbrains.annotations.Nullable; +import it.unimi.dsi.fastutil.longs.LongArrayList; +import net.minecraft.SharedConstants; +import net.minecraft.block.BlockState; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.VibrationParticleEffect; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.event.BlockPositionSource; +import xyz.nucleoid.extras.lobby.block.tater.TinyPotatoBlock; +import xyz.nucleoid.extras.tag.NEBlockTags; + +public class WardenTaterParticleSpawner extends DynamicTaterParticleSpawner { + public static final int WARDEN_PLAYER_PARTICLE_RATE = SharedConstants.TICKS_PER_SECOND; + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + PLAYER_PARTICLE_RATE_CODEC.forGetter(WardenTaterParticleSpawner::getPlayerParticleRate), + BLOCK_PARTICLE_CHANCE_CODEC.forGetter(WardenTaterParticleSpawner::getBlockParticleChance) + ).apply(instance, WardenTaterParticleSpawner::new) + ); + + private static final int BOX_SIZE = 16; + + public WardenTaterParticleSpawner(int playerParticleRate, int blockParticleChance) { + super(playerParticleRate, blockParticleChance); + } + + public WardenTaterParticleSpawner() { + this(WARDEN_PLAYER_PARTICLE_RATE, DEFAULT_BLOCK_PARTICLE_CHANCE); + } + + @Override + public ParticleEffect getParticleEffect(TaterParticleContext context) { + return getTaterVibrationParticleEffect(BlockPos.ofFloored(context.getEyePos()), context.world()); + } + + @Override + protected double getParticleSpeed(TaterParticleContext context) { + return 0; + } + + @Override + protected void spawn(TaterParticleContext context) { + var pos = context.getEyePos(); + + var particleEffect = this.getParticleEffect(context); + double particleSpeed = this.getParticleSpeed(context); + + if (particleEffect != null) { + context.world().spawnParticles(particleEffect, pos.getX(), pos.getY(), pos.getZ(), 1, 0, 0, 0, particleSpeed); + } + } + + @Override + public MapCodec getCodec() { + return CODEC; + } + + @Nullable + private static ParticleEffect getTaterVibrationParticleEffect(BlockPos pos, ServerWorld world) { + var taters = new LongArrayList(); + + int range = (int) (BOX_SIZE / 2d); + for (var taterPos : BlockPos.iterateOutwards(pos, range, range, range)) { + var state = world.getBlockState(taterPos); + if (isVibrationTater(state)) { + taters.add(taterPos.asLong()); + } + } + + if (taters.isEmpty()) { + return null; + } + + int index = world.getRandom().nextInt(taters.size()); + var taterPos = BlockPos.fromLong(taters.getLong(index)); + + return new VibrationParticleEffect(new BlockPositionSource(taterPos), (int) Math.floor(Math.sqrt(pos.getSquaredDistance(taterPos)))); + } + + private static boolean isVibrationTater(BlockState state) { + return state.getBlock() instanceof TinyPotatoBlock && !state.isIn(NEBlockTags.NON_VIBRATING_TATERS); + } +} diff --git a/src/main/java/xyz/nucleoid/extras/mixin/lobby/ServerPlayerEntityMixin.java b/src/main/java/xyz/nucleoid/extras/mixin/lobby/ServerPlayerEntityMixin.java index 20cdc984..5933441f 100644 --- a/src/main/java/xyz/nucleoid/extras/mixin/lobby/ServerPlayerEntityMixin.java +++ b/src/main/java/xyz/nucleoid/extras/mixin/lobby/ServerPlayerEntityMixin.java @@ -16,6 +16,7 @@ import xyz.nucleoid.extras.lobby.NECriteria; import xyz.nucleoid.extras.lobby.PlayerLobbyState; import xyz.nucleoid.extras.lobby.block.tater.CubicPotatoBlock; +import xyz.nucleoid.extras.lobby.particle.TaterParticleContext; @Mixin(ServerPlayerEntity.class) public abstract class ServerPlayerEntityMixin extends PlayerEntity { @@ -32,9 +33,7 @@ public ServerPlayerEntityMixin(World world, BlockPos pos, float yaw, GameProfile ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; NECriteria.WEAR_TATER.trigger(player, tinyPotatoBlock); NECriteria.TATER_COLLECTED.trigger(player, tinyPotatoBlock, PlayerLobbyState.get(this).collectedTaters.size()); - if (this.age % tinyPotatoBlock.getPlayerParticleRate(player) == 0) { - tinyPotatoBlock.spawnPlayerParticles(player); - } + tinyPotatoBlock.getParticleSpawner().trySpawn(new TaterParticleContext.Player(player)); } } }