diff --git a/CHANGELOG.md b/CHANGELOG.md index f1405a06f1..d20c9f34cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Added - Updated to Minecraft 1.21.1 ([#985](https://github.com/FallingColors/HexMod/pull/985)) @SuperKnux @slava110 +- Added Smelt, Freeze, Gravitate Block, Particles, and Factorial Purification, all of which were previously in Hexal ([#1183](https://github.com/FallingColors/HexMod/pull/1183)) @Robotgiggle + - Freeze now supports data-driven recipes for freezing liquids as well as blocks + - Smelt and Freeze now mishap if the target does not have a valid smelting/freezing recipe + - Factorial Purification now works on vectors as well as numbers, applying element-wise - Added Simulate, which causes the next pattern drawn to be simulated (to check for mishaps) rather than executed ([#1194](https://github.com/FallingColors/HexMod/pull/1194)) @Robotgiggle - Added the `hex_unbreakable` tag for blocks that should be immune to Break Block regardless of the configured mining tier ([#1186](https://github.com/FallingColors/HexMod/pull/1186)) @Robotgiggle @slava110 diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/blue_ice.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/blue_ice.json new file mode 100644 index 0000000000..04774bbe17 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/blue_ice.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:blue_ice" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:blue_ice" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/cobblestone.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/cobblestone.json new file mode 100644 index 0000000000..ea73b2f9b7 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/cobblestone.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:cobblestone" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:cobblestone" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/ice.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/ice.json new file mode 100644 index 0000000000..3ab7d63276 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/ice.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:ice" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:ice" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/obsidian.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/obsidian.json new file mode 100644 index 0000000000..0373519388 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/obsidian.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:obsidian" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:obsidian" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/packed_ice.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/packed_ice.json new file mode 100644 index 0000000000..4ebdafe90f --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/packed_ice.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:packed_ice" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:packed_ice" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/powder_snow_cauldron.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/powder_snow_cauldron.json new file mode 100644 index 0000000000..3f16e3b8fe --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/powder_snow_cauldron.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:powder_snow_cauldron" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:powder_snow_cauldron" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/snow_block.json b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/snow_block.json new file mode 100644 index 0000000000..acb66f14da --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/advancement/recipes/freeze/snow_block.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:snow_block" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:snow_block" + ] + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/freeze/blue_ice.json b/Common/src/generated/resources/data/hexcasting/recipe/freeze/blue_ice.json new file mode 100644 index 0000000000..8106c7878e --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/freeze/blue_ice.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:block", + "block": "minecraft:packed_ice" + }, + "result": { + "Name": "minecraft:blue_ice" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/freeze/cobblestone.json b/Common/src/generated/resources/data/hexcasting/recipe/freeze/cobblestone.json new file mode 100644 index 0000000000..62eb26ee5e --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/freeze/cobblestone.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:flowing_lava" + }, + "result": { + "Name": "minecraft:cobblestone" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/freeze/ice.json b/Common/src/generated/resources/data/hexcasting/recipe/freeze/ice.json new file mode 100644 index 0000000000..8cc38bd0e4 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/freeze/ice.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:water" + }, + "result": { + "Name": "minecraft:ice" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/freeze/obsidian.json b/Common/src/generated/resources/data/hexcasting/recipe/freeze/obsidian.json new file mode 100644 index 0000000000..02e435b8a4 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/freeze/obsidian.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:lava" + }, + "result": { + "Name": "minecraft:obsidian" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/freeze/packed_ice.json b/Common/src/generated/resources/data/hexcasting/recipe/freeze/packed_ice.json new file mode 100644 index 0000000000..cc60d06374 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/freeze/packed_ice.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:block", + "block": "minecraft:ice" + }, + "result": { + "Name": "minecraft:packed_ice" + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/freeze/powder_snow_cauldron.json b/Common/src/generated/resources/data/hexcasting/recipe/freeze/powder_snow_cauldron.json new file mode 100644 index 0000000000..da6f3a7d38 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/freeze/powder_snow_cauldron.json @@ -0,0 +1,13 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:block", + "block": "minecraft:water_cauldron" + }, + "result": { + "Name": "minecraft:powder_snow_cauldron", + "Properties": { + "level": "1" + } + } +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/freeze/snow_block.json b/Common/src/generated/resources/data/hexcasting/recipe/freeze/snow_block.json new file mode 100644 index 0000000000..24aa4e0ecc --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/freeze/snow_block.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:flowing_water" + }, + "result": { + "Name": "minecraft:snow_block" + } +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt index d67e0693b4..266e5f791b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt @@ -271,6 +271,25 @@ fun List.getNumOrVec(idx: Int, argc: Int = 0): Either { } } +fun List.getVecOrVecList(idx: Int, argc: Int = 0): Either> { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + return when (x) { + is Vec3Iota -> Either.left(x.vec3) + is ListIota -> { + val out = mutableListOf() + for (v in x.list) { + if (v is Vec3Iota) { + out.add(v.vec3) + } else { + throw MishapInvalidIota.of(x, if (argc == 0) idx else argc - (idx + 1), "vec_or_veclist") + } + } + Either.right(out) + } + else -> throw MishapInvalidIota.of(x, if (argc == 0) idx else argc - (idx + 1), "vec_or_veclist") + } +} + fun List.getLongOrList(idx: Int, argc: Int = 0): Either { val datum = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } if (datum is DoubleIota) { diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/Arithmetic.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/Arithmetic.java index 10f9f9cd6e..cecd0cc8f3 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/Arithmetic.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/Arithmetic.java @@ -41,6 +41,7 @@ public interface Arithmetic { HexPattern ARCTAN2 = HexPattern.fromAngles("deadeeeeewd", HexDir.WEST); HexPattern LOG = HexPattern.fromAngles("eqaqe", HexDir.NORTH_WEST); HexPattern MOD = HexPattern.fromAngles("addwaad", HexDir.NORTH_EAST); + HexPattern FACT = HexPattern.fromAngles("wawdedwaw", HexDir.SOUTH_EAST); // Vecs diff --git a/Common/src/main/java/at/petrak/hexcasting/api/pigment/ColorProvider.java b/Common/src/main/java/at/petrak/hexcasting/api/pigment/ColorProvider.java index 8c0611db2e..1131473a2d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/pigment/ColorProvider.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/pigment/ColorProvider.java @@ -2,6 +2,7 @@ import at.petrak.hexcasting.api.addldata.ADPigment; import net.minecraft.util.FastColor; +import net.minecraft.util.RandomSource; import net.minecraft.world.phys.Vec3; public abstract class ColorProvider { @@ -41,6 +42,14 @@ public final int getColor(float time, Vec3 position) { return 0xff_000000 | (r << 16) | (g << 8) | b; } + public final int getRandomColor(RandomSource random) { + return getColor( + random.nextFloat() * 16384, + new Vec3(random.nextFloat(),random.nextFloat(),random.nextFloat()) + .scale((random.nextFloat() * 3)) + ); + } + public static final ColorProvider MISSING = new ColorProvider() { @Override protected int getRawColor(float time, Vec3 position) { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpFallingBlock.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpFallingBlock.kt new file mode 100644 index 0000000000..1d4ab7bb56 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpFallingBlock.kt @@ -0,0 +1,113 @@ +package at.petrak.hexcasting.common.casting.actions.spells + +import at.petrak.hexcasting.api.mod.HexConfig +import at.petrak.hexcasting.api.casting.* +import at.petrak.hexcasting.api.casting.castables.SpellAction +import at.petrak.hexcasting.api.casting.eval.CastingEnvironment +import at.petrak.hexcasting.api.casting.iota.Iota +import at.petrak.hexcasting.api.misc.MediaConstants +import at.petrak.hexcasting.xplat.IXplatAbstractions +import net.minecraft.core.BlockPos +import net.minecraft.core.particles.BlockParticleOption +import net.minecraft.core.particles.ParticleTypes +import net.minecraft.core.registries.Registries +import net.minecraft.server.level.ServerLevel +import net.minecraft.server.level.ServerPlayer +import net.minecraft.tags.BlockTags +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.item.FallingBlockEntity +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraft.world.item.Tier +import net.minecraft.world.item.Tiers +import net.minecraft.world.item.enchantment.Enchantments +import net.minecraft.world.level.block.Block +import net.minecraft.world.level.block.FallingBlock +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.phys.Vec3 +import kotlin.math.roundToLong + +// https://github.com/VazkiiMods/Botania/blob/1.21.1-porting/Xplat/src/main/java/vazkii/botania/common/item/lens/WeightLens.java +object OpFallingBlock : SpellAction { + override val argc = 1 + + override fun execute(args: List, env: CastingEnvironment): SpellAction.Result { + val pos = args.getBlockPos(0, argc) + env.assertPosInRangeForEditing(pos) + + return SpellAction.Result( + Spell(pos), + (1.5 * MediaConstants.DUST_UNIT).roundToLong(), + listOf(ParticleSpray.burst(Vec3.atCenterOf(pos), 1.0)) + ) + } + + private data class Spell(val pos: BlockPos) : RenderedSpell { + override fun cast(env: CastingEnvironment) { + val blockstate = env.world.getBlockState(pos) + if (!IXplatAbstractions.INSTANCE.isBreakingAllowed(env.world, pos, blockstate, env.castingEntity as? ServerPlayer)) + return + + val tier = HexConfig.server().opBreakHarvestLevel() + + val stateBelow = env.world.getBlockState(pos.below()) + + if (( + FallingBlock.isFree(stateBelow) + || !stateBelow.canOcclude() + || stateBelow.`is`(BlockTags.SLABS) + ) + && !blockstate.isAir + && blockstate.getDestroySpeed(env.world, pos) >= 0f // fix being able to break bedrock &c + && env.world.getBlockEntity(pos) == null + && IXplatAbstractions.INSTANCE.isCorrectTierForDrops(tier, blockstate) + && canSilkTouch(env.world, pos, blockstate, tier, env.castingEntity as? ServerPlayer) + ) { + val falling: FallingBlockEntity = FallingBlockEntity.fall(env.world, pos, blockstate) + falling.time = 1 + env.world.sendParticles( + BlockParticleOption(ParticleTypes.FALLING_DUST, blockstate), + pos.x + 0.5, + pos.y + 0.5, + pos.z + 0.5, + 10, + 0.45, + 0.45, + 0.45, + 5.0 + ) + } + } + + companion object { + fun canSilkTouch(level: ServerLevel, pos: BlockPos, state: BlockState, harvestTier: Tier, owner: Entity?): Boolean { + // need to use .copy() here or the stack in HARVEST_TOOLS_BY_TIER will get enchanted + val harvestToolStack: ItemStack = getTool(harvestTier, state).copy() + if (harvestToolStack.isEmpty) return false + harvestToolStack.enchant(level.holderLookup(Registries.ENCHANTMENT).getOrThrow(Enchantments.SILK_TOUCH), 1) + val drops: List = Block.getDrops(state, level, pos, null, owner, harvestToolStack) + val blockItem: Item = state.block.asItem() + return drops.any { s -> s.item === blockItem } + } + + private fun getTool(harvestTier: Tier, state: BlockState): ItemStack { + val toolsForTier = HARVEST_TOOLS_BY_TIER.getOrElse(harvestTier) { return ItemStack.EMPTY } + if (!state.requiresCorrectToolForDrops()) return toolsForTier[0] + return toolsForTier.firstOrNull { it.isCorrectToolForDrops(state) } ?: ItemStack.EMPTY + } + + private val HARVEST_TOOLS_BY_TIER: Map> = mapOf( + Tiers.WOOD to stacks(Items.WOODEN_PICKAXE, Items.WOODEN_AXE, Items.WOODEN_HOE, Items.WOODEN_SHOVEL), + Tiers.STONE to stacks(Items.STONE_PICKAXE, Items.STONE_AXE, Items.STONE_HOE, Items.STONE_SHOVEL), + Tiers.IRON to stacks(Items.IRON_PICKAXE, Items.IRON_AXE, Items.IRON_HOE, Items.IRON_SHOVEL), + Tiers.DIAMOND to stacks(Items.DIAMOND_PICKAXE, Items.DIAMOND_AXE, Items.DIAMOND_HOE, Items.DIAMOND_SHOVEL), + Tiers.NETHERITE to stacks(Items.NETHERITE_PICKAXE, Items.NETHERITE_AXE, Items.NETHERITE_HOE, Items.NETHERITE_SHOVEL) + ) + + private fun stacks(vararg items: Item): List { + return items.map { item -> ItemStack(item) } + } + } + } +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpFreeze.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpFreeze.kt new file mode 100644 index 0000000000..9a83eb749a --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpFreeze.kt @@ -0,0 +1,47 @@ +package at.petrak.hexcasting.common.casting.actions.spells + +import at.petrak.hexcasting.api.casting.* +import at.petrak.hexcasting.api.casting.castables.SpellAction +import at.petrak.hexcasting.api.casting.eval.CastingEnvironment +import at.petrak.hexcasting.api.casting.iota.Iota +import at.petrak.hexcasting.api.casting.mishaps.MishapBadBlock +import at.petrak.hexcasting.api.misc.MediaConstants +import at.petrak.hexcasting.common.recipe.CopyProperties +import at.petrak.hexcasting.common.recipe.HexRecipeStuffRegistry +import at.petrak.hexcasting.xplat.IXplatAbstractions +import net.minecraft.core.BlockPos +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.level.block.Blocks +import net.minecraft.world.level.block.LiquidBlock +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.level.material.Fluids +import net.minecraft.world.phys.Vec3 + +object OpFreeze : SpellAction { + override val argc = 1 + + override fun execute(args: List, env: CastingEnvironment): SpellAction.Result { + val pos = args.getBlockPos(0, argc) + + env.assertPosInRangeForEditing(pos) + + val blockState = env.world.getBlockState(pos) + val recipes = env.world.recipeManager.getAllRecipesFor(HexRecipeStuffRegistry.FREEZE_TYPE).map{ holder -> holder.value } + val recipe = recipes.find{ it.matches(blockState) } ?: throw MishapBadBlock.of(pos, "freezable") + + return SpellAction.Result( + Spell(pos, blockState, recipe.result), + MediaConstants.DUST_UNIT, + listOf(ParticleSpray.burst(Vec3.atCenterOf(pos), 1.0)) + ) + } + + private data class Spell(val pos: BlockPos, val oldState: BlockState, val newState: BlockState) : RenderedSpell { + override fun cast(env: CastingEnvironment) { + if (!IXplatAbstractions.INSTANCE.isBreakingAllowed(env.world, pos, oldState, env.castingEntity as? ServerPlayer)) + return + + env.world.setBlockAndUpdate(pos, CopyProperties.copyProperties(oldState, newState)) + } + } +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpParticles.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpParticles.kt new file mode 100644 index 0000000000..9c79de3a36 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpParticles.kt @@ -0,0 +1,62 @@ +package at.petrak.hexcasting.common.casting.actions.spells + +import at.petrak.hexcasting.api.casting.RenderedSpell +import at.petrak.hexcasting.api.casting.castables.SpellAction +import at.petrak.hexcasting.api.casting.eval.CastingEnvironment +import at.petrak.hexcasting.api.casting.getVecOrVecList +import at.petrak.hexcasting.api.casting.iota.Iota +import at.petrak.hexcasting.api.casting.mishaps.MishapBadLocation +import at.petrak.hexcasting.api.misc.MediaConstants +import at.petrak.hexcasting.common.msgs.MsgParticleLinesS2C +import at.petrak.hexcasting.common.msgs.MsgSingleParticleS2C +import at.petrak.hexcasting.xplat.IXplatAbstractions +import com.mojang.datafixers.util.Either +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.phys.Vec3 +import kotlin.math.roundToLong + +object OpParticles : SpellAction { + override val argc = 1 + + override fun execute(args: List, env: CastingEnvironment): SpellAction.Result { + val loc = args.getVecOrVecList(0, argc) + + // assert all locs in ambit. + loc.map({ env.assertVecInRange(it) }, { assertVecListInRange(env, it, 32.0) }) + + return SpellAction.Result( + Spell(loc), + loc.map({ 0.002 * MediaConstants.DUST_UNIT }, { it.size * 0.002 * MediaConstants.DUST_UNIT }).roundToLong(), + listOf() + ) + } + + fun assertVecListInRange(env: CastingEnvironment, list: List, intraRange: Double) { + for (vec in list) { + env.assertVecInRange(vec) + } + + val sqrRange = intraRange * intraRange + + for (i in list.indices) { + for (j in i until list.size) { + if (list[i].distanceToSqr(list[j]) > sqrRange) throw MishapBadLocation(list[j]) + } + } + } + + data class Spell(val loc: Either>) : RenderedSpell { + override fun cast(env: CastingEnvironment) { + val colouriser = IXplatAbstractions.INSTANCE.getPigment(env.castingEntity as? ServerPlayer) + + loc.map({ + IXplatAbstractions.INSTANCE.sendPacketNear(it, 128.0, env.world, MsgSingleParticleS2C(it, colouriser)) + }, { + if (it.isNotEmpty()) { + val first = it[0] + IXplatAbstractions.INSTANCE.sendPacketNear(first, 128.0, env.world, MsgParticleLinesS2C(it, colouriser)) + } + }) + } + } +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpSmelt.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpSmelt.kt new file mode 100644 index 0000000000..aa080be03e --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpSmelt.kt @@ -0,0 +1,108 @@ +package at.petrak.hexcasting.common.casting.actions.spells + +import at.petrak.hexcasting.api.casting.* +import at.petrak.hexcasting.api.casting.castables.SpellAction +import at.petrak.hexcasting.api.casting.eval.CastingEnvironment +import at.petrak.hexcasting.api.casting.iota.EntityIota +import at.petrak.hexcasting.api.casting.iota.Iota +import at.petrak.hexcasting.api.casting.iota.Vec3Iota +import at.petrak.hexcasting.api.casting.mishaps.MishapBadBlock +import at.petrak.hexcasting.api.casting.mishaps.MishapBadItem +import at.petrak.hexcasting.api.casting.mishaps.MishapInvalidIota +import at.petrak.hexcasting.api.misc.MediaConstants +import at.petrak.hexcasting.xplat.IXplatAbstractions +import net.minecraft.core.BlockPos +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.item.ItemEntity +import net.minecraft.world.item.BlockItem +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.crafting.RecipeHolder +import net.minecraft.world.item.crafting.RecipeType +import net.minecraft.world.item.crafting.SingleRecipeInput +import net.minecraft.world.item.crafting.SmeltingRecipe +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.phys.Vec3 +import java.util.* +import kotlin.math.roundToLong + +object OpSmelt : SpellAction { + override val argc = 1 + + override fun execute(args: List, env: CastingEnvironment): SpellAction.Result { + when (val target = args[0]) { + is EntityIota -> { + val itemEntity = args.getItemEntity(env.world, 0, argc) + env.assertEntityInRange(itemEntity) + + val oldStack = itemEntity.item + val newStack = smeltResult(oldStack.item, env) ?: throw MishapBadItem.of(itemEntity, "smeltable") + newStack.count *= oldStack.count + + return SpellAction.Result( + ItemSpell(itemEntity, newStack), + (oldStack.count * 0.75 * MediaConstants.DUST_UNIT).roundToLong(), + listOf(ParticleSpray.burst(itemEntity.position(), 1.0)) + ) + } + is Vec3Iota -> { + val pos = args.getBlockPos(0, argc) + env.assertPosInRangeForEditing(pos) + + val blockState = env.world.getBlockState(pos) + val resultStack = smeltResult(blockState.block.asItem(), env) ?: throw MishapBadBlock.of(pos, "smeltable") + + return SpellAction.Result( + BlockSpell(pos, blockState, resultStack), + (0.75 * MediaConstants.DUST_UNIT).roundToLong(), + listOf(ParticleSpray.burst(Vec3.atCenterOf(pos), 1.0)) + ) + } + else -> throw MishapInvalidIota.ofType(target, 0, "entity_or_vector") + } + } + + fun smeltResult(item: Item, env: CastingEnvironment): ItemStack? { + val optional: Optional> = env.world.recipeManager.getRecipeFor( + RecipeType.SMELTING, SingleRecipeInput(ItemStack(item, 1)), + env.world + ) + + if (!optional.isPresent) return null + + val result = optional.get().value.getResultItem(env.world.registryAccess()).copy() + + if (result.isEmpty) return null + + return result + } + + private data class ItemSpell(val itemEntity: ItemEntity, val resultStack: ItemStack) : RenderedSpell { + override fun cast(env: CastingEnvironment) { + env.world.addFreshEntity(ItemEntity(env.world, itemEntity.x, itemEntity.y, itemEntity.z, resultStack.copy())) + itemEntity.remove(Entity.RemovalReason.DISCARDED) + } + } + + private data class BlockSpell(val pos: BlockPos, val blockState: BlockState, val resultStack: ItemStack) : RenderedSpell { + override fun cast(env: CastingEnvironment) { + if (!IXplatAbstractions.INSTANCE.isBreakingAllowed(env.world, pos, blockState, env.castingEntity as? ServerPlayer)) return + + if (resultStack.item is BlockItem) { + env.world.setBlockAndUpdate(pos, (resultStack.item as BlockItem).block.defaultBlockState()) + + if (resultStack.count > 1) { + resultStack.count -= 1 + env.world.addFreshEntity(ItemEntity(env.world, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), resultStack.copy())) + } + } else { + env.world.destroyBlock(pos, false, env.castingEntity as? ServerPlayer) + env.world.addFreshEntity(ItemEntity(env.world, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), resultStack.copy())) + // Send a block update, also copied from Ars Nouveau (this is all copied from Ars Nouveau) + if (!env.world.isOutsideBuildHeight(pos)) + env.world.sendBlockUpdated(pos, env.world.getBlockState(pos), env.world.getBlockState(pos), 3) // don't know how this works + } + } + } +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt index 29730acca9..2e0f9ade70 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/great/OpBrainsweep.kt @@ -14,6 +14,7 @@ import at.petrak.hexcasting.api.casting.mishaps.MishapBadLocation import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.api.mod.HexTags import at.petrak.hexcasting.common.recipe.BrainsweepRecipe +import at.petrak.hexcasting.common.recipe.CopyProperties import at.petrak.hexcasting.common.recipe.HexRecipeStuffRegistry import at.petrak.hexcasting.ktxt.tellWitnessesThatIWasMurdered import at.petrak.hexcasting.mixin.accessor.AccessorLivingEntity @@ -75,7 +76,7 @@ object OpBrainsweep : SpellAction { val recipe: BrainsweepRecipe ) : RenderedSpell { override fun cast(env: CastingEnvironment) { - env.world.setBlockAndUpdate(pos, BrainsweepRecipe.copyProperties(state, recipe.result)) + env.world.setBlockAndUpdate(pos, CopyProperties.copyProperties(state, recipe.result)) HexAPI.instance().brainsweep(sacrifice) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/DoubleArithmetic.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/DoubleArithmetic.kt index 075a17a76f..37f8938715 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/DoubleArithmetic.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/DoubleArithmetic.kt @@ -14,6 +14,7 @@ import at.petrak.hexcasting.api.casting.math.HexPattern import at.petrak.hexcasting.api.casting.mishaps.MishapDivideByZero import at.petrak.hexcasting.common.casting.arithmetic.operator.OperatorLog import at.petrak.hexcasting.common.casting.arithmetic.operator.asDoubleBetween +import at.petrak.hexcasting.common.casting.arithmetic.operator.generalFactorial import at.petrak.hexcasting.common.lib.hex.HexIotaTypes import java.util.function.DoubleBinaryOperator import java.util.function.DoubleUnaryOperator @@ -38,7 +39,8 @@ object DoubleArithmetic : Arithmetic { ARCTAN, ARCTAN2, LOG, - MOD + MOD, + FACT ) /** @@ -70,6 +72,7 @@ object DoubleArithmetic : Arithmetic { ARCTAN2 -> make2 { a, b -> atan2(a, b) } LOG -> OperatorLog MOD -> make2 { a, b -> if (b == 0.0) throw MishapDivideByZero.of(a, b) else a % b } + FACT -> make1 { a -> generalFactorial(a) } else -> throw InvalidOperatorException("$pattern is not a valid operator in Arithmetic $this.") } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/Vec3Arithmetic.java b/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/Vec3Arithmetic.java index a1d0af1ce4..e06ddce679 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/Vec3Arithmetic.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/Vec3Arithmetic.java @@ -9,6 +9,7 @@ import at.petrak.hexcasting.api.casting.iota.DoubleIota; import at.petrak.hexcasting.api.casting.iota.Vec3Iota; import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.common.casting.arithmetic.operator.OperatorUtilsKt; import at.petrak.hexcasting.common.casting.arithmetic.operator.vec.OperatorPack; import at.petrak.hexcasting.common.casting.arithmetic.operator.vec.OperatorUnpack; import at.petrak.hexcasting.common.casting.arithmetic.operator.vec.OperatorVec3Delegating; @@ -36,7 +37,8 @@ public enum Vec3Arithmetic implements Arithmetic { POW, FLOOR, CEIL, - MOD + MOD, + FACT ); public static final IotaMultiPredicate ACCEPTS = IotaMultiPredicate.any(IotaPredicate.ofType(VEC3), IotaPredicate.ofType(DOUBLE)); @@ -75,6 +77,10 @@ public Operator getOperator(HexPattern pattern) { return make1(v -> new Vec3(Math.ceil(v.x), Math.ceil(v.y), Math.ceil(v.z))); } else if (pattern.equals(MOD)) { return make2Fallback(pattern); + } else if (pattern.equals(FACT)) { + return make1(v -> new Vec3(OperatorUtilsKt.generalFactorial(v.x), + OperatorUtilsKt.generalFactorial(v.y), + OperatorUtilsKt.generalFactorial(v.z))); } throw new InvalidOperatorException(pattern + " is not a valid operator in Arithmetic " + this + "."); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/operator/OperatorUtils.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/operator/OperatorUtils.kt index 24247286c8..e67924a720 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/operator/OperatorUtils.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/operator/OperatorUtils.kt @@ -5,8 +5,12 @@ import at.petrak.hexcasting.api.casting.iota.DoubleIota import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.iota.ListIota import at.petrak.hexcasting.api.casting.mishaps.MishapInvalidIota +import kotlin.math.PI import kotlin.math.abs +import kotlin.math.exp +import kotlin.math.ln import kotlin.math.roundToInt +import kotlin.math.sqrt fun Iterator>.nextList(argc: Int = 0): SpellList { val (idx, x) = this.next() @@ -64,4 +68,27 @@ fun Iterator>.nextPositiveIntUnderInclusive(max: Int, argc: I * the double's index from the top of the stack (i.e. top iota has [idx]=0, second from the top has [idx]=1, etc.). */ fun Double.asDoubleBetween(min: Double, max: Double, idx: Int) = if (this in min .. max) this - else throw MishapInvalidIota.of(DoubleIota(this), idx, "double.between", min, max) \ No newline at end of file + else throw MishapInvalidIota.of(DoubleIota(this), idx, "double.between", min, max) + +/** + * Takes the standard factorial if `arg` is a positive integer, otherwise uses the gamma function. + */ +fun generalFactorial(arg: Double): Double { + val argInt = arg.roundToInt() + if (arg >= 0 && DoubleIota.tolerates(arg, argInt.toDouble())) { + // normal integer factorial + var result = 1.0 + for (factor in 2..argInt) { + result *= factor + } + return result + } + // gamma function of arg+1 for non-integer factorial + // https://introcs.cs.princeton.edu/java/91float/Gamma.java.html + val x = arg + 1 + val ser = ( 1.0 + 76.18009173 / (x + 0) - 86.50532033 / (x + 1) + + 24.01409822 / (x + 2) - 1.231739516 / (x + 3) + + 0.00120858003 / (x + 4) - 0.00000536382 / (x + 5) ) + val logGamma = (x - 0.5) * ln(x + 4.5) - (x + 4.5) + ln(ser * sqrt(2*PI)) + return exp(logGamma) +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexStateIngredients.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexStateIngredients.java index ae4b7abde8..7217ae9d50 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexStateIngredients.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexStateIngredients.java @@ -13,6 +13,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluid; import java.util.List; import java.util.Random; @@ -30,6 +31,7 @@ public class HexStateIngredients { public static final StateIngredientType BLOCK_TYPE = new StateIngredientBlock.Type(); public static final StateIngredientType BLOCK_STATE = new StateIngredientBlockState.Type(); public static final StateIngredientType BLOCKS = new StateIngredientBlocks.Type(); + public static final StateIngredientType FLUID_TYPE = new StateIngredientFluid.Type(); public static final StateIngredientType TAG = new StateIngredientTag.Type(); public static final StateIngredientType TAG_EXCLUDING = new StateIngredientTagExcluding.Type(); @@ -77,6 +79,7 @@ public static void register(BiConsumer, ResourceLocation> r.accept(BLOCK_TYPE, HexAPI.modLoc("block")); r.accept(BLOCK_STATE, HexAPI.modLoc("state")); r.accept(BLOCKS, HexAPI.modLoc("blocks")); + r.accept(FLUID_TYPE, HexAPI.modLoc("fluid")); r.accept(TAG, HexAPI.modLoc("tag")); r.accept(TAG_EXCLUDING, HexAPI.modLoc("tag_excluding")); } @@ -92,4 +95,6 @@ public static StateIngredient of(BlockState state) { public static StateIngredient of(TagKey tag) { return new StateIngredientTag(tag); } + + public static StateIngredient of(Fluid fluid) { return new StateIngredientFluid(fluid); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java index 7feab39471..0ed9dea7ce 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java @@ -223,6 +223,8 @@ public class HexActions { new OperationAction(HexPattern.fromAngles("eqaqe", HexDir.NORTH_WEST))); public static final ActionRegistryEntry MODULO = make("modulo", new OperationAction(HexPattern.fromAngles("addwaad", HexDir.NORTH_EAST))); + public static final ActionRegistryEntry FACTORIAL = make("factorial", + new OperationAction(HexPattern.fromAngles("wawdedwaw", HexDir.SOUTH_EAST))); // == Sets == @@ -258,10 +260,6 @@ public class HexActions { Fluids.WATER))); public static final ActionRegistryEntry DESTROY_WATER = make("destroy_water", new ActionRegistryEntry(HexPattern.fromAngles("dedwedade", HexDir.SOUTH_WEST), OpDestroyFluid.INSTANCE)); - public static final ActionRegistryEntry IGNITE = make("ignite", - new ActionRegistryEntry(HexPattern.fromAngles("aaqawawa", HexDir.SOUTH_EAST), OpIgnite.INSTANCE)); - public static final ActionRegistryEntry EXTINGUISH = make("extinguish", - new ActionRegistryEntry(HexPattern.fromAngles("ddedwdwd", HexDir.SOUTH_WEST), OpExtinguish.INSTANCE)); public static final ActionRegistryEntry CONJURE_BLOCK = make("conjure_block", new ActionRegistryEntry(HexPattern.fromAngles("qqa", HexDir.NORTH_EAST), new OpConjureBlock(false))); public static final ActionRegistryEntry CONJURE_LIGHT = make("conjure_light", @@ -275,9 +273,22 @@ public class HexActions { new ActionRegistryEntry(HexPattern.fromAngles("qdqawwaww", HexDir.EAST), OpErase.INSTANCE)); public static final ActionRegistryEntry EDIFY = make("edify", new ActionRegistryEntry(HexPattern.fromAngles("wqaqwd", HexDir.NORTH_EAST), OpEdifySapling.INSTANCE)); + public static final ActionRegistryEntry FALLING_BLOCK = make("falling_block", + new ActionRegistryEntry(HexPattern.fromAngles("qaqqwwddwwq", HexDir.EAST), OpFallingBlock.INSTANCE)); + + public static final ActionRegistryEntry IGNITE = make("ignite", + new ActionRegistryEntry(HexPattern.fromAngles("aaqawawa", HexDir.SOUTH_EAST), OpIgnite.INSTANCE)); + public static final ActionRegistryEntry EXTINGUISH = make("extinguish", + new ActionRegistryEntry(HexPattern.fromAngles("ddedwdwd", HexDir.SOUTH_WEST), OpExtinguish.INSTANCE)); + public static final ActionRegistryEntry SMELT = make("smelt", + new ActionRegistryEntry(HexPattern.fromAngles("wqqqwqqadad", HexDir.EAST), OpSmelt.INSTANCE)); + public static final ActionRegistryEntry FREEZE = make("freeze", + new ActionRegistryEntry(HexPattern.fromAngles("weeeweedada", HexDir.EAST), OpFreeze.INSTANCE)); public static final ActionRegistryEntry BEEP = make("beep", new ActionRegistryEntry(HexPattern.fromAngles("adaa", HexDir.WEST), OpBeep.INSTANCE)); + public static final ActionRegistryEntry PARTICLES = make("particles", + new ActionRegistryEntry(HexPattern.fromAngles("eqqqqa", HexDir.NORTH_EAST), OpParticles.INSTANCE)); public static final ActionRegistryEntry CRAFT$CYPHER = make("craft/cypher", new ActionRegistryEntry( HexPattern.fromAngles("waqqqqq", HexDir.EAST), diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgParticleLinesS2C.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgParticleLinesS2C.java new file mode 100644 index 0000000000..b3a89f38ab --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgParticleLinesS2C.java @@ -0,0 +1,56 @@ +package at.petrak.hexcasting.common.msgs; + +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.api.pigment.FrozenPigment; +import at.petrak.hexcasting.common.particles.ConjureParticleOptions; +import at.petrak.paucal.api.PaucalCodecs; +import net.minecraft.client.Minecraft; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.world.phys.Vec3; + +import java.util.List; + +public record MsgParticleLinesS2C(List locs, FrozenPigment colorizer) implements CustomPacketPayload { + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(HexAPI.modLoc("prtcl_l")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + PaucalCodecs.VEC3.apply(ByteBufCodecs.list()), MsgParticleLinesS2C::locs, + FrozenPigment.STREAM_CODEC, MsgParticleLinesS2C::colorizer, + MsgParticleLinesS2C::new + ); + + @Override + public Type type() { + return TYPE; + } + + public void handle() { + MsgParticleLinesS2C.Handler.handle(this); + } + + public static final class Handler { + + public static void handle(MsgParticleLinesS2C msg) { + Minecraft.getInstance().execute(() -> { + var level = Minecraft.getInstance().level; + if (level == null) return; + var colProvider = msg.colorizer().getColorProvider(); + + for (int i = 0; i < msg.locs.size()-1; ++i) { + Vec3 start = msg.locs.get(i); + Vec3 end = msg.locs.get(i+1); + int steps = (int) (end.subtract(start).length() * 10); + for (int j = 0; j <= steps; ++j) { + Vec3 pos = start.add(end.subtract(start).scale((double) j / steps)); + var color = colProvider.getRandomColor(level.random); + level.addParticle(new ConjureParticleOptions(color), + pos.x, pos.y, pos.z, 0.0, 0.0, 0.0); + } + } + }); + } + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgSingleParticleS2C.java b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgSingleParticleS2C.java new file mode 100644 index 0000000000..29e8bd9ff8 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/msgs/MsgSingleParticleS2C.java @@ -0,0 +1,52 @@ +package at.petrak.hexcasting.common.msgs; + +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.api.pigment.FrozenPigment; +import at.petrak.hexcasting.common.particles.ConjureParticleOptions; +import at.petrak.paucal.api.PaucalCodecs; +import net.minecraft.client.Minecraft; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.world.phys.Vec3; + +public record MsgSingleParticleS2C(Vec3 pos, FrozenPigment colorizer) implements CustomPacketPayload { + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(HexAPI.modLoc("prtcl_s")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + PaucalCodecs.VEC3, MsgSingleParticleS2C::pos, + FrozenPigment.STREAM_CODEC, MsgSingleParticleS2C::colorizer, + MsgSingleParticleS2C::new + ); + + @Override + public Type type() { + return TYPE; + } + + public void handle() { + MsgSingleParticleS2C.Handler.handle(this); + } + + public static final class Handler { + + public static void handle(MsgSingleParticleS2C msg) { + Minecraft.getInstance().execute(() -> { + var level = Minecraft.getInstance().level; + if (level == null) return; + var colProvider = msg.colorizer().getColorProvider(); + + var color = colProvider.getRandomColor(level.random); + level.addParticle(new ConjureParticleOptions(color), msg.pos.x, msg.pos.y, msg.pos.z, 0.0, 0.0, 0.0); + for (int i = 0; i <= 10; i++) { + color = colProvider.getRandomColor(level.random); + double offsetX = level.random.nextFloat() * 0.1 - 0.05; + double offsetY = level.random.nextFloat() * 0.1 - 0.05; + double offsetZ = level.random.nextFloat() * 0.1 - 0.05; + level.addParticle(new ConjureParticleOptions(color), + msg.pos.x + offsetX, msg.pos.y + offsetY, msg.pos.z + offsetZ, 0.0, 0.0, 0.0); + } + }); + } + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/BrainsweepRecipe.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/BrainsweepRecipe.java index a9f8ea3384..844fccf2d2 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/recipe/BrainsweepRecipe.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/BrainsweepRecipe.java @@ -67,19 +67,6 @@ public ItemStack getResultItem(HolderLookup.Provider registries) { return ItemStack.EMPTY.copy(); } - // Because kotlin doesn't like doing raw, unchecked types - // Can't blame it, but that's what we need to do - @SuppressWarnings({"rawtypes", "unchecked"}) - public static BlockState copyProperties(BlockState original, BlockState copyTo) { - for (Property prop : original.getProperties()) { - if (copyTo.hasProperty(prop)) { - copyTo = copyTo.setValue(prop, original.getValue(prop)); - } - } - - return copyTo; - } - public static class Serializer extends RecipeSerializerBase { public static MapCodec CODEC = RecordCodecBuilder.mapCodec(inst -> inst.group( diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/CopyProperties.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/CopyProperties.java new file mode 100644 index 0000000000..0cf3fca470 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/CopyProperties.java @@ -0,0 +1,19 @@ +package at.petrak.hexcasting.common.recipe; + +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; + +public class CopyProperties { + // Because kotlin doesn't like doing raw, unchecked types + // Can't blame it, but that's what we need to do + @SuppressWarnings({"rawtypes", "unchecked"}) + public static BlockState copyProperties(BlockState original, BlockState copyTo) { + for (Property prop : original.getProperties()) { + if (copyTo.hasProperty(prop)) { + copyTo = copyTo.setValue(prop, original.getValue(prop)); + } + } + + return copyTo; + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/FreezeRecipe.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/FreezeRecipe.java new file mode 100644 index 0000000000..2979527f37 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/FreezeRecipe.java @@ -0,0 +1,85 @@ +package at.petrak.hexcasting.common.recipe; + +import at.petrak.hexcasting.common.lib.HexStateIngredients; +import at.petrak.hexcasting.common.recipe.ingredient.state.StateIngredient; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.HolderLookup; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeInput; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; + +public record FreezeRecipe( + StateIngredient blockIn, + BlockState result +) implements Recipe { + public boolean matches(BlockState blockIn) { + return this.blockIn.test(blockIn); + } + + @Override + public RecipeType getType() { + return HexRecipeStuffRegistry.FREEZE_TYPE; + } + + @Override + public RecipeSerializer getSerializer() { + return HexRecipeStuffRegistry.FREEZE; + } + + // in order to get this to be a "Recipe" we need to do a lot of bending-over-backwards + // to get the implementation to be satisfied even though we never use it + @Override + public boolean matches(RecipeInput input, Level level) { + return false; + } + + @Override + public ItemStack assemble(RecipeInput input, HolderLookup.Provider registries) { + return ItemStack.EMPTY; + } + + @Override + public boolean canCraftInDimensions(int pWidth, int pHeight) { + return false; + } + + @Override + public ItemStack getResultItem(HolderLookup.Provider registries) { + return ItemStack.EMPTY.copy(); + } + + public static class Serializer extends RecipeSerializerBase { + public static MapCodec CODEC = RecordCodecBuilder.mapCodec(inst -> + inst.group( + HexStateIngredients.TYPED_CODEC.fieldOf("blockIn").forGetter(FreezeRecipe::blockIn), + BlockState.CODEC.fieldOf("result").forGetter(FreezeRecipe::result) + ).apply(inst, FreezeRecipe::new) + ); + public static StreamCodec STREAM_CODEC = StreamCodec.composite( + HexStateIngredients.TYPED_STREAM_CODEC, FreezeRecipe::blockIn, + ByteBufCodecs.VAR_INT, (recipe) -> Block.getId(recipe.result), + (state, stateId) -> + new FreezeRecipe(state, Block.stateById(stateId)) + ); + + @Override + public @NotNull MapCodec codec() { + return CODEC; + } + + @Override + public @NotNull StreamCodec streamCodec() { + return STREAM_CODEC; + } + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/HexRecipeStuffRegistry.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/HexRecipeStuffRegistry.java index cc2ffbba0f..2dfc941d39 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/recipe/HexRecipeStuffRegistry.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/HexRecipeStuffRegistry.java @@ -30,12 +30,15 @@ public static void registerTypes(BiConsumer, ResourceLocation> r) public static final RecipeSerializer BRAINSWEEP = registerSerializer("brainsweep", new BrainsweepRecipe.Serializer()); + public static final RecipeSerializer FREEZE = registerSerializer("freeze", + new FreezeRecipe.Serializer()); public static final RecipeSerializer SEAL_FOCUS = registerSerializer( "seal_focus", SealThingsRecipe.FOCUS_SERIALIZER); public static final RecipeSerializer SEAL_SPELLBOOK = registerSerializer( "seal_spellbook", SealThingsRecipe.SPELLBOOK_SERIALIZER); public static RecipeType BRAINSWEEP_TYPE = registerType("brainsweep"); + public static RecipeType FREEZE_TYPE = registerType("freeze"); private static > RecipeSerializer registerSerializer(String name, RecipeSerializer rs) { var old = SERIALIZERS.put(modLoc(name), rs); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/state/StateIngredientFluid.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/state/StateIngredientFluid.java new file mode 100644 index 0000000000..f40cb12830 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/ingredient/state/StateIngredientFluid.java @@ -0,0 +1,92 @@ +package at.petrak.hexcasting.common.recipe.ingredient.state; + +import at.petrak.hexcasting.common.lib.HexStateIngredients; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; + +import java.util.Collections; +import java.util.List; +import java.util.Random; + +public class StateIngredientFluid implements StateIngredient { + private final Fluid fluid; + + public StateIngredientFluid(Fluid fluid) { this.fluid = fluid; } + + @Override + public StateIngredientType getType() { + return HexStateIngredients.FLUID_TYPE; + } + + @Override + public boolean test(BlockState blockState) { return fluid == blockState.getFluidState().getType(); } + + @Override + public BlockState pick(Random random) { return fluid.defaultFluidState().createLegacyBlock(); } + + @Override + public List getDisplayedStacks() { + if (fluid == Fluids.EMPTY) { + return Collections.emptyList(); + } + return Collections.singletonList(new ItemStack(fluid.getBucket())); + } + + @Override + public List getDisplayed() { + return Collections.singletonList(fluid.defaultFluidState().createLegacyBlock()); + } + + public Fluid getFluid() { return fluid; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return fluid == ((StateIngredientFluid) o).fluid; + } + + @Override + public int hashCode() { + return fluid.hashCode(); + } + + @Override + public String toString() { + return "StateIngredientBlock{" + fluid + "}"; + } + + public static class Type implements StateIngredientType { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + BuiltInRegistries.FLUID.byNameCodec().fieldOf("fluid").forGetter(StateIngredientFluid::getFluid) + ).apply(instance, StateIngredientFluid::new)); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.registry(Registries.FLUID), StateIngredientFluid::getFluid, + StateIngredientFluid::new + ); + + @Override + public MapCodec codec() { + return CODEC; + } + + @Override + public StreamCodec streamCodec() { + return STREAM_CODEC; + } + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java index 35e4ab2020..3058addef2 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java @@ -19,6 +19,7 @@ import at.petrak.hexcasting.datagen.recipe.builders.BrainsweepRecipeBuilder; import at.petrak.hexcasting.datagen.recipe.builders.CreateCrushingRecipeBuilder; import at.petrak.hexcasting.datagen.recipe.builders.FarmersDelightCuttingRecipeBuilder; +import at.petrak.hexcasting.datagen.recipe.builders.FreezeRecipeBuilder; import at.petrak.paucal.api.PaucalAPI; import at.petrak.paucal.api.datagen.PaucalAdvancementSubProvider; import net.minecraft.advancements.CriteriaTriggers; @@ -46,6 +47,7 @@ import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.material.Fluids; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -469,6 +471,29 @@ public void buildRecipes(RecipeOutput recipes) { .requires(HexBlocks.AMETHYST_PILLAR) .unlockedBy("has_item", has(HexBlocks.SLATE)).save(recipes); + new FreezeRecipeBuilder(HexStateIngredients.of(Fluids.WATER), Blocks.ICE.defaultBlockState()) + .unlockedBy("has_item", hasItem(HexTags.Items.STAVES)) + .save(recipes, modLoc("ice")); + new FreezeRecipeBuilder(HexStateIngredients.of(Fluids.FLOWING_WATER), Blocks.SNOW_BLOCK.defaultBlockState()) + .unlockedBy("has_item", hasItem(HexTags.Items.STAVES)) + .save(recipes, modLoc("snow_block")); + new FreezeRecipeBuilder(HexStateIngredients.of(Fluids.LAVA), Blocks.OBSIDIAN.defaultBlockState()) + .unlockedBy("has_item", hasItem(HexTags.Items.STAVES)) + .save(recipes, modLoc("obsidian")); + new FreezeRecipeBuilder(HexStateIngredients.of(Fluids.FLOWING_LAVA), Blocks.COBBLESTONE.defaultBlockState()) + .unlockedBy("has_item", hasItem(HexTags.Items.STAVES)) + .save(recipes, modLoc("cobblestone")); + + new FreezeRecipeBuilder(HexStateIngredients.of(Blocks.ICE), Blocks.PACKED_ICE.defaultBlockState()) + .unlockedBy("has_item", hasItem(HexTags.Items.STAVES)) + .save(recipes, modLoc("packed_ice")); + new FreezeRecipeBuilder(HexStateIngredients.of(Blocks.PACKED_ICE), Blocks.BLUE_ICE.defaultBlockState()) + .unlockedBy("has_item", hasItem(HexTags.Items.STAVES)) + .save(recipes, modLoc("blue_ice")); + new FreezeRecipeBuilder(HexStateIngredients.of(Blocks.WATER_CAULDRON), Blocks.POWDER_SNOW_CAULDRON.defaultBlockState()) + .unlockedBy("has_item", hasItem(HexTags.Items.STAVES)) + .save(recipes, modLoc("powder_snow_cauldron")); + new BrainsweepRecipeBuilder(HexStateIngredients.of(Blocks.AMETHYST_BLOCK), new VillagerIngredient(null, null, 3), Blocks.BUDDING_AMETHYST.defaultBlockState(), MediaConstants.CRYSTAL_UNIT * 10) diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/builders/FreezeRecipeBuilder.java b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/builders/FreezeRecipeBuilder.java new file mode 100644 index 0000000000..4193f007b0 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/builders/FreezeRecipeBuilder.java @@ -0,0 +1,58 @@ +package at.petrak.hexcasting.datagen.recipe.builders; + +import at.petrak.hexcasting.common.recipe.FreezeRecipe; +import at.petrak.hexcasting.common.recipe.ingredient.state.StateIngredient; +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementRequirements; +import net.minecraft.advancements.AdvancementRewards; +import net.minecraft.advancements.Criterion; +import net.minecraft.advancements.critereon.RecipeUnlockedTrigger; +import net.minecraft.data.recipes.RecipeBuilder; +import net.minecraft.data.recipes.RecipeOutput; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class FreezeRecipeBuilder implements RecipeBuilder { + private final StateIngredient blockIn; + private final BlockState result; + + private final Map> criteria = new LinkedHashMap<>(); + + public FreezeRecipeBuilder(StateIngredient blockIn, BlockState result) { + this.blockIn = blockIn; + this.result = result; + } + + @Override + public RecipeBuilder unlockedBy(String pCriterionName, Criterion pCriterionTrigger) { + criteria.put(pCriterionName, pCriterionTrigger); + return this; + } + + @Override + public RecipeBuilder group(@Nullable String pGroupName) { + return this; + } + + @Override + public Item getResult() { + return this.result.getBlock().asItem(); + } + + @Override + public void save(RecipeOutput recipeOutput, ResourceLocation id) { + Advancement.Builder advancement = recipeOutput.advancement() + .addCriterion("has_the_recipe", RecipeUnlockedTrigger.unlocked(id)) + .rewards(AdvancementRewards.Builder.recipe(id)) + .requirements(AdvancementRequirements.Strategy.OR); + this.criteria.forEach(advancement::addCriterion); + + var recipe = new FreezeRecipe(blockIn, result); + recipeOutput.accept(id.withPrefix("freeze/"), recipe, advancement.build(id.withPrefix("recipes/freeze/"))); + } +} diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 index e70a5192d5..5c5230e2de 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 @@ -837,6 +837,7 @@ random: "Entropy Reflection", logarithm: "Logarithmic Distillation", coerce_axial: "Axial Purification", + factorial: "Factorial Purification", read: "Scribe's Reflection", "read/entity": "Chronicler's Purification", @@ -851,6 +852,7 @@ print: "Reveal", beep: "Make Note", + particles: "Particles", explode: "Explosion", "explode/fire": "Fireball", add_motion: "Impulse", @@ -869,10 +871,13 @@ destroy_water: "Destroy Liquid", ignite: "Ignite", extinguish: "Extinguish Area", + smelt: "Smelt", + freeze: "Freeze", conjure_block: "Conjure Block", conjure_light: "Conjure Light", bonemeal: "Overgrow", edify: "Edify Sapling", + falling_block: "Gravitate Block", colorize: "Internalize Pigment", cycle_variant: "Caster's Glamour", @@ -1104,7 +1109,7 @@ living: "a living entity", }, - entity_or_vector: "an entity or a vector", + entity_or_vector: "an entity or vector", unknown: "(unknown, uh-oh, this is a bug)", }, @@ -1112,6 +1117,7 @@ numvec: "a number or vector", numlist: "an integer or list", "list.pattern": "a list of patterns", + vec_or_veclist: "a vector or list of vectors", double: { positive: { @@ -1165,11 +1171,14 @@ colorizer: "a pigment", variant: "an item with variants", placeable: "a placeable item", + smeltable: "a smeltable item", }, bad_block: { "": "Expected %s at %s, but got %s", sapling: "a sapling", + smeltable: "a smeltable block", + freezable: "a freezable block", replaceable: "somewhere to place a block", }, @@ -1317,6 +1326,7 @@ itempicking: "Working with Items", basic_spell: "Basic Spells", blockworks: "Block Manipulation", + heatworks: "Heat Manipulation", nadirs: "Nadirs", hexcasting_spell: "Crafting Casting Items", sentinels: "Sentinels", @@ -1818,6 +1828,7 @@ construct_vec: "Combine three numbers at the top of the stack into a vector's X, Y, and Z components (bottom to top).", deconstruct_vec: "Split a vector into its X, Y, and Z components (bottom to top).", modulo: "Takes the modulus of two numbers. This is the amount $(italics)remaining/$ after division - for example, 5 %% 2 is 1, and 5 %% 3 is 2. When applied on vectors, performs the above operation elementwise.", + factorial: "Takes the factorial of a number. This is the product of all integers from 1 to the number. For non-integers, uses the $(l:https://en.wikipedia.org/wiki/Gamma_function)gamma function/$. For vectors, performs the above operation elementwise.", coerce_axial: "For a vector, coerce it to its nearest axial direction, a unit vector. For a number, return the sign of the number; 1 if positive, -1 if negative. In both cases, zero is unaffected.", random: "Creates a random number between 0 and 1.", }, @@ -2051,6 +2062,8 @@ "beep.1": "Remove a vector and two numbers from the stack. Plays an $(thing)instrument/$ defined by the first number at the given location, with a $(thing)note/$ defined by the second number. Costs a negligible amount of _media.", "beep.2": "There appear to be 16 different $(thing)instruments/$ and 25 different $(thing)notes/$. Both are indexed by zero.$(br2)These seem to be the same instruments I can produce with a $(item)Note Block/$, though the reason for each instrument's number being what it is eludes me.$(br2)Either way, I can find the numbers I need to use by inspecting a $(item)Note Block/$ through a $(l:items/lens)$(item)Scrying Lens/$.", + + particles: "Accepts a location or a list of locations, and either creates a particle at the location, or creates lines of particles between the locations in the list. Costs two thousandths of an $(l:items/amethyst)$(item)Amethyst Dust/$ per location.", }, blockworks: { @@ -2062,8 +2075,14 @@ conjure_light: "Conjure a magical light that softly glows with my pigment at the given position. Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.", bonemeal: "Encourage a plant or sapling at the target position to grow, as if $(item)Bonemeal/$ was applied. Costs a bit more than one $(l:items/amethyst)$(item)Amethyst Dust/$.", edify: "Forcibly infuse _media into the sapling at the target position, causing it to grow into an $(l:items/edified)$(thing)Edified Tree/$. Costs about one $(l:items/amethyst)$(item)Charged Amethyst/$.", + falling_block: "Force the block at the target position to fall as if it were sand or gravel. Certain blocks seem mysteriously immune to this effect. Costs one and a half $(l:items/amethyst)$(item)Amethyst Dust/$.", + }, + + heatworks: { ignite: "Start a fire on top of the given location, as if a $(item)Fire Charge/$ was applied, or set fire to an entity. Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.", extinguish: "Extinguish blocks in a large area. Costs about six $(l:items/amethyst)$(item)Amethyst Dust/$.", + smelt: "Smelts either the block at the given location or all the items in the given item entity. Costs three quarters of an $(l:items/amethyst)$(item)Amethyst Dust/$ per block/item smelted.", + freeze: "Freezes the block at the given location. For example, turns water into ice, and ice into packed ice. Costs one $(l:items/amethyst)$(item)Amethyst Dust/$.", }, nadirs: { diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/math.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/math.json index 668875a547..86a6b1573a 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/math.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/math.json @@ -125,6 +125,14 @@ "output": "num|vec", "text": "hexcasting.page.math.modulo" }, + { + "type": "hexcasting:pattern", + "op_id": "hexcasting:factorial", + "anchor": "hexcasting:factorial", + "input": "num|vec", + "output": "num|vec", + "text": "hexcasting.page.math.factorial" + }, { "type": "hexcasting:pattern", "op_id": "hexcasting:coerce_axial", diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/basic.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/basic.json index 27b2c90e8a..64937ec1fd 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/basic.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/basic.json @@ -57,6 +57,14 @@ { "type": "patchouli:text", "text": "hexcasting.page.basic_spell.beep.2" + }, + { + "type": "hexcasting:pattern", + "op_id": "hexcasting:particles", + "anchor": "hexcasting:particles", + "input": "vector | [vector]", + "output": "", + "text": "hexcasting.page.basic_spell.particles" } ] } diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/blockworks.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/blockworks.json index f39e871d45..eb2c5c27ed 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/blockworks.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/blockworks.json @@ -72,19 +72,11 @@ }, { "type": "hexcasting:pattern", - "op_id": "hexcasting:ignite", - "anchor": "hexcasting:ignite", - "input": "entity | vector", - "output": "", - "text": "hexcasting.page.blockworks.ignite" - }, - { - "type": "hexcasting:pattern", - "op_id": "hexcasting:extinguish", - "anchor": "hexcasting:extinguish", + "op_id": "hexcasting:falling_block", + "anchor": "hexcasting:falling_block", "input": "vector", "output": "", - "text": "hexcasting.page.blockworks.extinguish" + "text": "hexcasting.page.blockworks.falling_block" } ] } \ No newline at end of file diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/heatworks.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/heatworks.json new file mode 100644 index 0000000000..b02adda11f --- /dev/null +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/heatworks.json @@ -0,0 +1,42 @@ +{ + "name": "hexcasting.entry.heatworks", + "category": "hexcasting:patterns/spells", + "icon": "minecraft:magma_block", + "sortnum": 1, + "advancement": "hexcasting:root", + "read_by_default": true, + "pages": [ + { + "type": "hexcasting:pattern", + "op_id": "hexcasting:ignite", + "anchor": "hexcasting:ignite", + "input": "vector | entity", + "output": "", + "text": "hexcasting.page.heatworks.ignite" + }, + { + "type": "hexcasting:pattern", + "op_id": "hexcasting:extinguish", + "anchor": "hexcasting:extinguish", + "input": "vector", + "output": "", + "text": "hexcasting.page.heatworks.extinguish" + }, + { + "type": "hexcasting:pattern", + "op_id": "hexcasting:smelt", + "anchor": "hexcasting:smelt", + "input": "vector | entity", + "output": "", + "text": "hexcasting.page.heatworks.smelt" + }, + { + "type": "hexcasting:pattern", + "op_id": "hexcasting:freeze", + "anchor": "hexcasting:freeze", + "input": "vector", + "output": "", + "text": "hexcasting.page.heatworks.freeze" + } + ] +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/blue_ice.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/blue_ice.json new file mode 100644 index 0000000000..04774bbe17 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/blue_ice.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:blue_ice" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:blue_ice" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/cobblestone.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/cobblestone.json new file mode 100644 index 0000000000..ea73b2f9b7 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/cobblestone.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:cobblestone" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:cobblestone" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/ice.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/ice.json new file mode 100644 index 0000000000..3ab7d63276 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/ice.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:ice" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:ice" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/obsidian.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/obsidian.json new file mode 100644 index 0000000000..0373519388 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/obsidian.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:obsidian" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:obsidian" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/packed_ice.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/packed_ice.json new file mode 100644 index 0000000000..4ebdafe90f --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/packed_ice.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:packed_ice" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:packed_ice" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/powder_snow_cauldron.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/powder_snow_cauldron.json new file mode 100644 index 0000000000..3f16e3b8fe --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/powder_snow_cauldron.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:powder_snow_cauldron" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:powder_snow_cauldron" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/snow_block.json b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/snow_block.json new file mode 100644 index 0000000000..acb66f14da --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/advancement/recipes/freeze/snow_block.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:snow_block" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:snow_block" + ] + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/blue_ice.json b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/blue_ice.json new file mode 100644 index 0000000000..8106c7878e --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/blue_ice.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:block", + "block": "minecraft:packed_ice" + }, + "result": { + "Name": "minecraft:blue_ice" + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/cobblestone.json b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/cobblestone.json new file mode 100644 index 0000000000..62eb26ee5e --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/cobblestone.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:flowing_lava" + }, + "result": { + "Name": "minecraft:cobblestone" + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/ice.json b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/ice.json new file mode 100644 index 0000000000..8cc38bd0e4 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/ice.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:water" + }, + "result": { + "Name": "minecraft:ice" + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/obsidian.json b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/obsidian.json new file mode 100644 index 0000000000..02e435b8a4 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/obsidian.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:lava" + }, + "result": { + "Name": "minecraft:obsidian" + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/packed_ice.json b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/packed_ice.json new file mode 100644 index 0000000000..cc60d06374 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/packed_ice.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:block", + "block": "minecraft:ice" + }, + "result": { + "Name": "minecraft:packed_ice" + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/powder_snow_cauldron.json b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/powder_snow_cauldron.json new file mode 100644 index 0000000000..da6f3a7d38 --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/powder_snow_cauldron.json @@ -0,0 +1,13 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:block", + "block": "minecraft:water_cauldron" + }, + "result": { + "Name": "minecraft:powder_snow_cauldron", + "Properties": { + "level": "1" + } + } +} \ No newline at end of file diff --git a/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/snow_block.json b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/snow_block.json new file mode 100644 index 0000000000..24aa4e0ecc --- /dev/null +++ b/Fabric/src/generated/resources/data/hexcasting/recipe/freeze/snow_block.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:flowing_water" + }, + "result": { + "Name": "minecraft:snow_block" + } +} \ No newline at end of file diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/network/FabricPacketHandler.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/network/FabricPacketHandler.java index c7e2346e9b..d6d866f34c 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/network/FabricPacketHandler.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/network/FabricPacketHandler.java @@ -24,6 +24,8 @@ public static void initPackets() { PayloadTypeRegistry.playS2C().register(MsgNewWallScrollS2C.TYPE, MsgNewWallScrollS2C.STREAM_CODEC); PayloadTypeRegistry.playS2C().register(MsgRecalcWallScrollDisplayS2C.TYPE, MsgRecalcWallScrollDisplayS2C.STREAM_CODEC); PayloadTypeRegistry.playS2C().register(MsgNewSpiralPatternsS2C.TYPE, MsgNewSpiralPatternsS2C.STREAM_CODEC); + PayloadTypeRegistry.playS2C().register(MsgSingleParticleS2C.TYPE, MsgSingleParticleS2C.STREAM_CODEC); + PayloadTypeRegistry.playS2C().register(MsgParticleLinesS2C.TYPE, MsgParticleLinesS2C.STREAM_CODEC); } public static void init() { diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/blue_ice.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/blue_ice.json new file mode 100644 index 0000000000..04774bbe17 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/blue_ice.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:blue_ice" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:blue_ice" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/cobblestone.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/cobblestone.json new file mode 100644 index 0000000000..ea73b2f9b7 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/cobblestone.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:cobblestone" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:cobblestone" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/ice.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/ice.json new file mode 100644 index 0000000000..3ab7d63276 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/ice.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:ice" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:ice" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/obsidian.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/obsidian.json new file mode 100644 index 0000000000..0373519388 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/obsidian.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:obsidian" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:obsidian" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/packed_ice.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/packed_ice.json new file mode 100644 index 0000000000..4ebdafe90f --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/packed_ice.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:packed_ice" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:packed_ice" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/powder_snow_cauldron.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/powder_snow_cauldron.json new file mode 100644 index 0000000000..3f16e3b8fe --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/powder_snow_cauldron.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:powder_snow_cauldron" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:powder_snow_cauldron" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/snow_block.json b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/snow_block.json new file mode 100644 index 0000000000..acb66f14da --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/advancement/recipes/freeze/snow_block.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_item": { + "conditions": { + "items": [ + { + "items": "#hexcasting:staves" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "hexcasting:snow_block" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_item" + ] + ], + "rewards": { + "recipes": [ + "hexcasting:snow_block" + ] + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/blue_ice.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/blue_ice.json new file mode 100644 index 0000000000..8106c7878e --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/blue_ice.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:block", + "block": "minecraft:packed_ice" + }, + "result": { + "Name": "minecraft:blue_ice" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/cobblestone.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/cobblestone.json new file mode 100644 index 0000000000..62eb26ee5e --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/cobblestone.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:flowing_lava" + }, + "result": { + "Name": "minecraft:cobblestone" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/ice.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/ice.json new file mode 100644 index 0000000000..8cc38bd0e4 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/ice.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:water" + }, + "result": { + "Name": "minecraft:ice" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/obsidian.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/obsidian.json new file mode 100644 index 0000000000..02e435b8a4 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/obsidian.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:lava" + }, + "result": { + "Name": "minecraft:obsidian" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/packed_ice.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/packed_ice.json new file mode 100644 index 0000000000..cc60d06374 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/packed_ice.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:block", + "block": "minecraft:ice" + }, + "result": { + "Name": "minecraft:packed_ice" + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/powder_snow_cauldron.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/powder_snow_cauldron.json new file mode 100644 index 0000000000..da6f3a7d38 --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/powder_snow_cauldron.json @@ -0,0 +1,13 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:block", + "block": "minecraft:water_cauldron" + }, + "result": { + "Name": "minecraft:powder_snow_cauldron", + "Properties": { + "level": "1" + } + } +} \ No newline at end of file diff --git a/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/snow_block.json b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/snow_block.json new file mode 100644 index 0000000000..24aa4e0ecc --- /dev/null +++ b/Neoforge/src/generated/resources/data/hexcasting/recipe/freeze/snow_block.json @@ -0,0 +1,10 @@ +{ + "type": "hexcasting:freeze", + "blockIn": { + "type": "hexcasting:fluid", + "fluid": "minecraft:flowing_water" + }, + "result": { + "Name": "minecraft:snow_block" + } +} \ No newline at end of file diff --git a/Neoforge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java b/Neoforge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java index c53a796a4e..66e9b58b6f 100644 --- a/Neoforge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java +++ b/Neoforge/src/main/java/at/petrak/hexcasting/forge/network/ForgePacketHandler.java @@ -49,6 +49,10 @@ public static void init(IEventBus modBus) { makeClientBoundHandler(MsgNewSpiralPatternsS2C::handle)); registar.playToClient(MsgClearSpiralPatternsS2C.TYPE, MsgClearSpiralPatternsS2C.STREAM_CODEC, makeClientBoundHandler(MsgClearSpiralPatternsS2C::handle)); + registar.playToClient(MsgSingleParticleS2C.TYPE, MsgSingleParticleS2C.STREAM_CODEC, + makeClientBoundHandler(MsgSingleParticleS2C::handle)); + registar.playToClient(MsgParticleLinesS2C.TYPE, MsgParticleLinesS2C.STREAM_CODEC, + makeClientBoundHandler(MsgParticleLinesS2C::handle)); }); }