import { world, system, BlockPermutation, EntityDamageCause, EquipmentSlot, GameMode, ItemStack } from "@minecraft/server";
import * as blockArrays from "../arrays/block_arrays.js"
import * as itemArrays from "../arrays/item_arrays.js"
import * as itemUtilities from "./item_utilities.js"
import * as mathUtilities from "./math_utilities.js"

export function alchemyAltar(block,dimension,face,player,params) {
	const rule = params;
	if (!rule) return;
	if (face!="Up") return;
	const blockAbove = block.dimension.getBlock(block.above(1));
	if (!blockAbove.isAir) return;
	const canBeUsed = block.permutation.getState("megaverse:can_be_used");
	if (!canBeUsed) return;
	const itemStack = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	const alchemicBookTypes = {
		"megaverse:alchemic_book": {},
		"megaverse:arcane_alchemic_book": {
			event: "minecraft:place_arcane"
		},
		"megaverse:aurora_alchemic_book": {
			event: "minecraft:place_aurora"
		},
		"megaverse:dark_alchemic_book": {
			event: "minecraft:place_dark"
		},
		"megaverse:electric_alchemic_book": {
			event: "minecraft:place_electric"
		},
		"megaverse:essentia_alchemic_book": {
			event: "minecraft:place_essentia"
		},
		"megaverse:fire_alchemic_book": {
			event: "minecraft:place_fire"
		},
		"megaverse:geo_alchemic_book": {
			event: "minecraft:place_geo"
		},
		"megaverse:ice_alchemic_book": {
			event: "minecraft:place_ice"
		},
		"megaverse:light_alchemic_book": {
			event: "minecraft:place_light"
		},
		"megaverse:necromancy_alchemic_book": {
			event: "minecraft:place_necromancy"
		},
		"megaverse:restoration_alchemic_book": {
			event: "minecraft:place_restoration"
		},
		"megaverse:soul_alchemic_book": {
			event: "minecraft:place_soul"
		},
		"megaverse:stellar_alchemic_book": {
			event: "minecraft:place_stellar"
		},
		"megaverse:water_alchemic_book": {
			event: "minecraft:place_water"
		}
	};
	if (!itemStack.hasItem()) return;
	const alchemicBookItems = alchemicBookTypes[itemStack.typeId];
	if (itemStack.typeId=="minecraft:enchanted_book") {
		itemStack.setItem(new ItemStack("minecraft:book",1));
		dimension.playSound(rule.sounds.arcane,{x:block.center().x,y:block.location.y+1,z:block.center().z});
		dimension.spawnItem(new ItemStack("megaverse:raw_arcane_magic",1),{x:block.center().x,y:block.location.y+1,z:block.center().z});
		dimension.spawnParticle(rule.particles.arcane,{x:block.center().x,y:block.location.y+1,z:block.center().z});
		return;
	}
	else if (alchemicBookItems) {
		const alchemicBookEntities = block.dimension.getEntitiesAtBlockLocation(block.above(1));
		const alchemicBook = alchemicBookEntities.find(entity=>entity.typeId==="megaverse:alchemic_book");
		if (alchemicBook) return;
		if (alchemicBookItems.event) {
			itemUtilities.itemDecrementStack(itemStack,player);
			return block.dimension.spawnEntity("megaverse:alchemic_book",{x:block.center().x,y:block.center().y+0.5,z:block.center().z},{spawnEvent:alchemicBookItems.event});
		}
		else {
			itemUtilities.itemDecrementStack(itemStack,player);
			return block.dimension.spawnEntity("megaverse:alchemic_book",{x:block.center().x,y:block.center().y+0.5,z:block.center().z});
		}
	}
};
export function alchemyAltarTick(block,dimension,params) {
	const rule = params;
	if (!rule) return;
	const blockAbove = dimension.getBlock(block.above(1));
	const canBeUsed = block.permutation.getState("megaverse:can_be_used");
	const hasAltarUsed = block.permutation.getState("megaverse:has_altar_used");
	const alchemicBookEntities = block.dimension.getEntitiesAtBlockLocation(block.above(1));
	const alchemicBook = alchemicBookEntities.find(entity=>entity.typeId==="megaverse:alchemic_book");
	const offsets = [
		[-1,-1],[0,-1],[1,-1],
		[-1,0],[0,0],[1,0],
		[-1,1],[0,1],[1,1],
	];
	for (const [dx,dz] of offsets) {
		const requiredLocation = {
			x: block.below(1).x+dx,
			y: block.below(1).y,
			z: block.below(1).z+dz
		};
		const requiredBlocksLocation = dimension.getBlock(requiredLocation);
		if (!blockAbove.isAir||(!rule.required_conditions.block_types.includes(requiredBlocksLocation.typeId)&&!rule.required_conditions.block_tags.some(tag=>requiredBlocksLocation.hasTag(tag)))) {
			if (canBeUsed||hasAltarUsed) {
				block.setPermutation(block.permutation.withState("megaverse:can_be_used",false));
				return block.setPermutation(block.permutation.withState("megaverse:has_altar_used",false));
			}
			else if (!canBeUsed&&!hasAltarUsed) return;
		}
	}
	if (!canBeUsed) return block.setPermutation(block.permutation.withState("megaverse:can_be_used",true));
	else {
		if (!alchemicBook&&hasAltarUsed) {
			block.setPermutation(block.permutation.withState("megaverse:has_altar_used",false));
			return dimension.playSound(rule.sounds.arcane,block.center());
		}
		if (!alchemicBook) return;
		const alchemyMagic = alchemicBook.getProperty("megaverse:alchemy_magic");
		if (alchemyMagic=="none"&&hasAltarUsed) {
			block.setPermutation(block.permutation.withState("megaverse:has_altar_used",false));
			return dimension.playSound(rule.sounds.arcane,block.center());
		}
		else if (alchemyMagic!="none"&&!hasAltarUsed) {
			block.setPermutation(block.permutation.withState("megaverse:has_altar_used",true));
			return dimension.playSound(rule.sounds.arcane,block.center());
		}
	}
};
export function blockAtelaiozoicScarabEggBreak(block,brokenBlockPermutation,dimension,player,params) {
	const rule = params;
	if (player.getGameMode()==GameMode.Creative) return;
	if (rule.block_particles.destroyed) dimension.spawnParticle(rule.block_particles.destroyed,block.center());
	if (rule.block_sounds.destroyed) dimension.playSound(rule.block_sounds.destroyed,block.center());
};
export function blockAtelaiozoicScarabEggTick(block,dimension,params) {
	const rule = params;
	if (block.isWaterlogged) return;
	const blockBelow = block.dimension.getBlock(block.below(1));
	if (!rule.requirements.block_types.includes(blockBelow.typeId)&&!rule.requirements.block_tags.some(tag=>blockBelow.hasTag(tag))) return;
	function crackVisuals(dimension,rule) {
		if (rule.block_particles.cracked) dimension.spawnParticle(rule.block_particles.cracked,block.center());
		if (rule.block_sounds.cracked) dimension.playSound(rule.block_sounds.cracked,block.center());
	};
	const crackedState = block.permutation.getState(rule.cracked_state.identifier);
	const index = rule.cracked_state.values.indexOf(crackedState);
	if (index<rule.cracked_state.values.length-1) {
		crackVisuals(dimension,rule);
		block.setPermutation(block.permutation.withState(rule.cracked_state.identifier,rule.cracked_state.values[index+1]));
		return;
	}
	if (rule.block_particles.hatched) dimension.spawnParticle(rule.block_particles.hatched,block.center());
	if (rule.block_sounds.hatched) dimension.playSound(rule.block_sounds.hatched,block.center());
	block.setType(rule.block_turns_into);
	dimension.spawnEntity(rule.entity.identifier,block.center(),{spawnEvent:rule.entity.event});
};
export function blockCake(block,dimension,player,params) {
	const rule = params;
	const sliceCounter = block.permutation.getState("megaverse:slice_counter");
	const hunger = player.getComponent("minecraft:player.hunger");
	const currentHunger = hunger.currentValue;
	const defaultHunger = hunger.defaultValue;
	const saturation = player.getComponent("minecraft:player.saturation");
	const currentSaturation = saturation.currentValue;
	const defaultSaturation = saturation.defaultValue;
	if (player.getGameMode()!=GameMode.Creative) {
		if (currentHunger==defaultHunger) return;
		if (currentHunger==defaultHunger-1) hunger.setCurrentValue(defaultHunger);
		else hunger.setCurrentValue(currentHunger+rule.nutrition);
		saturation.setCurrentValue(currentSaturation+(rule.saturation_modifier*rule.nutrition));
	}
	if (sliceCounter!=6) {
		dimension.playSound("random.burp",block.center());
		return block.setPermutation(block.permutation.withState("megaverse:slice_counter",sliceCounter+1));
	}
	else {
		dimension.playSound("random.burp",block.center());
		return block.setType("minecraft:air");
	}
};

export function blockChair(block,dimension,player) {
	const rule = block.getComponent("megaverse:block_chair").customComponentParameters.params;
	if (!rule) return;
	const cardinalDirection = block.permutation.getState("minecraft:cardinal_direction");
	const checkBlockEntity = block.dimension.getEntitiesAtBlockLocation(block.location);
	const blockAbove = block.dimension.getBlock(block.location).above(1);
	for (const blockEntities of checkBlockEntity) {
		if (blockEntities.typeId==rule.block_entity) return player.sendMessage({translate:rule.occupied});
	}
	if (blockAbove.isAir==false) return player.sendMessage({translate:rule.obstructed});
	const blockEntity = block.dimension.spawnEntity(rule.block_entity,{x:block.center().x,y:block.location.y+rule.sit_height,z:block.center().z});
	const blockSittable = blockEntity.getComponent("minecraft:rideable");
	if (cardinalDirection=="north") blockEntity.setRotation({x:0,y:180});
	else if (cardinalDirection=="west") blockEntity.setRotation({x:0,y:90});
	else if (cardinalDirection=="east") blockEntity.setRotation({x:0,y:-90});
	blockSittable.addRider(player);
};

export function blockCoinPile(block,dimension,player,params) {
	const rule = params;
	const amount = block.permutation.getState("megaverse:amount");
	const itemStack = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	if (!itemStack.hasItem()||itemStack.typeId!=block.typeId&&!itemStack.typeId.endsWith("_coin_pile")) {
		const coinsAbove = block.dimension.getBlock(block.above(1));
		if (coinsAbove.typeId.endsWith("_coin_pile")) return;
		dimension.spawnItem(new ItemStack(block.typeId,1),block.center());
		if (amount!=0) {
			if (rule.sounds.take) dimension.playSound(rule.sounds.take,block.center());
			return block.setPermutation(block.permutation.withState("megaverse:amount",amount-1));
		}
		else {
			if (rule.sounds.take) dimension.playSound(rule.sounds.take,block.center());
			return block.setType("minecraft:air");
		}
	}
	if (itemStack.typeId==block.typeId) {
		if (player.getGameMode()!=GameMode.Creative) {
			if (amount==7) return;
			if (itemStack.amount>1) itemStack.amount--;
			else itemStack.setItem(undefined);
		}
		if (amount!=7) {
			if (rule.sounds.add) dimension.playSound(rule.sounds.add,block.center());
			return block.setPermutation(block.permutation.withState("megaverse:amount",amount+1));
		}
	}
	else return;
};

export function blockCoinPileBreak(block,brokenBlockPermutation,dimension,player,params) {
	const rule = params;
	if (player.getGameMode()==GameMode.Creative) return;
	const itemStack = player.getComponent("minecraft:equippable").getEquipment(EquipmentSlot.Mainhand);
	if (!itemStack) return;
	const enchantable = itemStack.getComponent("minecraft:enchantable");
	const silkTouch = enchantable?.getEnchantment("silk_touch");
	if (!silkTouch) return;
	const amount = brokenBlockPermutation.getState("megaverse:amount");
	if (rule.sounds.take) dimension.playSound(rule.sounds.take,block.center());
	let dropCount = amount;
	for (let i = 0; i < dropCount; i++) {
		dimension.spawnItem(new ItemStack(brokenBlockPermutation.type.id,1),block.center());
	}
};

export function blockCropInteract(block,dimension,player) {
	const rule = block.getComponent("megaverse:block_crop").customComponentParameters.params;
	if (!rule) return;
	const mainhand = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	if (!mainhand.hasItem()||mainhand.typeId!=="minecraft:bone_meal") return;
	const growth = block.permutation.getState(rule.growth_state);
	function useBoneMeal(block,dimension) {
		dimension.playSound(rule.grow_sound,block.center());
		dimension.spawnParticle(rule.grow_particle,block.center());
	};
	if (player.getGameMode()==GameMode.Creative) {
		useBoneMeal(block,dimension);
		if (rule.grows_into) {
			if (rule.grows_into.weight&&rule.grows_into.blocks) {
				const index = blockCropRandomiseType(rule.grows_into.weight);
				block.setType(rule.grows_into.blocks[index]);
				return;
			}
			const extraState = block.permutation.getState(rule.grows_into.extra_state);
			if (extraState!=rule.grows_into.extra_state_value&&rule.grows_each_stage) {
				if (rule.grows_into.block&&rule.grows_into.extra_state) {
					const blockAbove = block.dimension.getBlock(block.above(rule.grows_into.block_y_location));
					if (!blockAbove.isAir) return;
					if (rule.grows_into.block_y_location) {
						block.setPermutation(block.permutation.withState(rule.growth_state,rule.max_growth));
						block.dimension.setBlockPermutation({x:block.location.x,y:block.location.y+rule.grows_into.block_y_location,z:block.location.z},BlockPermutation.resolve(rule.grows_into.block,{[rule.grows_into.extra_state]:rule.grows_into.extra_state_value,[rule.growth_state]:rule.grows_into.max_growth}));
					}
				}
			}
		}
		else block.setPermutation(block.permutation.withState(rule.growth_state,rule.max_growth));
	}
	else {
		let growth = block.permutation.getState(rule.growth_state);
		if (rule.grows_into&&rule.grows_into.extra_state) {
			const extraState = block.permutation.getState(rule.grows_into.extra_state);
			if (extraState!=rule.grows_into.extra_state_value&&rule.grows_each_stage) {
				const blockAbove = block.dimension.getBlock(block.above(rule.grows_into.block_y_location));
				if (growth==rule.max_growth&&!blockAbove.isAir) return;
				if (growth==rule.max_growth) {
					const blockAbove = block.dimension.getBlock(block.above(rule.grows_into.block_y_location));
					if (!blockAbove.isAir) return;
					itemUtilities.itemDecrementStack(mainhand,player);
					useBoneMeal(block,dimension);
					if (rule.grows_into.block&&rule.grows_into.extra_state) {
						block.dimension.setBlockPermutation({x:block.location.x,y:block.location.y+rule.grows_into.block_y_location,z:block.location.z},BlockPermutation.resolve(rule.grows_into.block,{[rule.grows_into.extra_state]:rule.grows_into.extra_state_value}));
					}
					return;
				}
				if (growth!=rule.grows_into_stage) {
					block.setPermutation(block.permutation.withState(rule.growth_state,growth+1));
					itemUtilities.itemDecrementStack(mainhand,player);
					useBoneMeal(block,dimension);
					return;
				}
				if (growth==rule.grows_into_stage) {
					const blockAbove = block.dimension.getBlock(block.above(rule.grows_into.block_y_location));
					if (!blockAbove.isAir) return;
					itemUtilities.itemDecrementStack(mainhand,player);
					useBoneMeal(block,dimension);
					if (rule.grows_into.block&&rule.grows_into.extra_state) {
						block.setPermutation(block.permutation.withState(rule.growth_state,growth+1));
						block.dimension.setBlockPermutation({x:block.location.x,y:block.location.y+rule.grows_into.block_y_location,z:block.location.z},BlockPermutation.resolve(rule.grows_into.block,{[rule.grows_into.extra_state]:rule.grows_into.extra_state_value}));
					}
					return;
				}
			}
			if (extraState==rule.grows_into.extra_state_value) {
				if (growth!=rule.grows_into.max_growth) {
					block.setPermutation(block.permutation.withState(rule.growth_state,growth+1));
					itemUtilities.itemDecrementStack(mainhand,player);
					useBoneMeal(block,dimension);
					return;
				}
				if (growth==rule.grows_into.max_growth) return;
			}
		}
		if (growth!=rule.max_growth) {
			growth += mathUtilities.randomInteger(1,rule.max_growth-growth);
			block.setPermutation(block.permutation.withState(rule.growth_state,growth));
			itemUtilities.itemDecrementStack(mainhand,player);
			useBoneMeal(block,dimension);
		}
		if (growth==rule.max_growth) {
			if (rule.grows_into) {
				itemUtilities.itemDecrementStack(mainhand,player);
				useBoneMeal(block,dimension);
				if (rule.grows_into.weight&&rule.grows_into.blocks) {
					const index = blockCropRandomiseType(rule.grows_into.weight);
					block.setType(rule.grows_into.blocks[index]);
				}
			}
		}
	}
};

export function blockCropInteract2(block,dimension,player,params) {
	const rule = params;
	const {x,y,z} = block.center();
	const growth = block.permutation.getState(rule.growth_state);
	const mainhand = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	if (growth<rule.min_growth||(mainhand.hasItem()&&mainhand.typeId==rule.exclude_item)) return;
	if (rule.interact_sound) dimension.playSound(rule.interact_sound,block.center());
	if (block.typeId=="megaverse:soybeans") {
		const amount = mathUtilities.randomInteger(1,3);
		block.dimension.spawnItem(new ItemStack("megaverse:soybean_pod",amount),block.center());
	}
	return block.setPermutation(block.permutation.withState(rule.growth_state,growth-rule.growth_shrink));
};

export function blockCropInteract3(block,dimension,player) {
	const rule = block.getComponent("megaverse:block_crop").customComponentParameters.params;
	if (!rule) return;
	const mainhand = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	if (!mainhand.hasItem()||mainhand.typeId!=="minecraft:bone_meal") return;
	const growth = block.permutation.getState(rule.growth_state);
	function useBoneMeal(block,dimension) {
		dimension.playSound(rule.grow_sound,block.center());
		dimension.spawnParticle(rule.grow_particle,block.center());
	};
	if (player.getGameMode()==GameMode.Creative) {
		useBoneMeal(block,dimension);
		if (rule.grows_into) {
			if (rule.grows_into.weight&&rule.grows_into.blocks) {
				const index = blockCropRandomiseType(rule.grows_into.weight);
				block.setType(rule.grows_into.blocks[index]);
			}
		}
		else block.setPermutation(block.permutation.withState(rule.growth_state,rule.max_growth));
	}
	else {
		let growth = block.permutation.getState(rule.growth_state);
		if (growth!=rule.max_growth) {
			growth += mathUtilities.randomInteger(1,rule.max_growth-growth);
			block.setPermutation(block.permutation.withState(rule.growth_state,growth));
			itemUtilities.itemDecrementStack(mainhand,player);
			useBoneMeal(block,dimension);
		}
		if (growth==rule.max_growth) {
			if (rule.grows_into) {
				itemUtilities.itemDecrementStack(mainhand,player);
				useBoneMeal(block,dimension);
				if (rule.grows_into.weight&&rule.grows_into.blocks) {
					const index = blockCropRandomiseType(rule.grows_into.weight);
					block.setType(rule.grows_into.blocks[index]);
				}
			}
		}
	}
};

export function blockCropRandomiseType(weight) {
	const total = weight.reduce((a,b)=>a+b,0);
	const rand = Math.random()*total;
	let sum = 0;
	for (let i = 0; i < weight.length; i++) {
		sum += weight[i];
		if (rand<sum) return i;
	}
};

export function blockCropRandomTick(block,dimension) {
	const rule = block.getComponent("megaverse:block_crop").customComponentParameters.params;
	if (!rule) return;
	const growth = block.permutation.getState(rule.growth_state);
	const blockBelow = block.dimension.getBlock(block.below(1));
	const moisturized = blockBelow.permutation.getState("moisturized_amount");
	const maxGrowth = rule.max_growth;
	const percentageChance = (moisturized+rule.growth_chance.numerator)/rule.growth_chance.denominator;
	if (Math.random()>percentageChance) return;
	if (rule.grows_into.extra_state) {
		const extraState = block.permutation.getState(rule.grows_into.extra_state);
		if (extraState!=rule.grows_into.extra_state_value&&rule.grows_each_stage) {
			const blockAbove = block.dimension.getBlock(block.above(rule.grows_into.block_y_location));
			if (growth==rule.max_growth) {
				if (!blockAbove.isAir) return;
				if (rule.grows_into.block&&rule.grows_into.extra_state) {
					block.dimension.setBlockPermutation({x:block.location.x,y:block.location.y+rule.grows_into.block_y_location,z:block.location.z},BlockPermutation.resolve(rule.grows_into.block,{[rule.grows_into.extra_state]:rule.grows_into.extra_state_value}));
					return;
				}
			}
			if (growth!=rule.grows_into_stage) {
				block.setPermutation(block.permutation.withState(rule.growth_state,growth+1));
				return;
			}
			if (growth==rule.grows_into_stage) {
				if (!blockAbove.isAir) return;
				if (rule.grows_into.block&&rule.grows_into.extra_state) {
					block.setPermutation(block.permutation.withState(rule.growth_state,growth+1));
					block.dimension.setBlockPermutation({x:block.location.x,y:block.location.y+rule.grows_into.block_y_location,z:block.location.z},BlockPermutation.resolve(rule.grows_into.block,{[rule.grows_into.extra_state]:rule.grows_into.extra_state_value}));
					return;
				}
			}
		}
		if (extraState==rule.grows_into.extra_state_value) {
			if (growth!=rule.grows_into.max_growth) {
				block.setPermutation(block.permutation.withState(rule.growth_state,growth+1));
				return;
			}
			else return;
		}
	}
	if (growth!=maxGrowth) block.setPermutation(block.permutation.withState(rule.growth_state,growth+1));
	if (growth==maxGrowth) {
		if (!rule.grows_into) return;
		if (rule.grows_into.weight&&rule.grows_into.blocks) {
			const index = blockCropRandomiseType(rule.grows_into.weight);
			block.setType(rule.grows_into.blocks[index]);
		}
		else return;
	}
};

export function blockCropRandomTick2(block,dimension) {
	const rule = block.getComponent("megaverse:block_crop").customComponentParameters.params;
	if (!rule) return;
	const growth = block.permutation.getState(rule.growth_state);
	const blockBelow = block.dimension.getBlock(block.below(1));
	const moisturized = blockBelow.permutation.getState("moisturized_amount");
	const maxGrowth = rule.max_growth;
	const percentageChance = (moisturized+rule.growth_chance.numerator)/rule.growth_chance.denominator;
	if (Math.random()>percentageChance) return;
	if (growth!=maxGrowth) block.setPermutation(block.permutation.withState(rule.growth_state,growth+1));
	if (growth==maxGrowth) {
		if (!rule.grows_into) return;
		if (rule.grows_into.weight&&rule.grows_into.blocks) {
			const index = blockCropRandomiseType(rule.grows_into.weight);
			block.setType(rule.grows_into.blocks[index]);
		}
		else return;
	}
};

export function blockEggBreak(block,brokenBlockPermutation,dimension,player) {
	if (player.getGameMode()==GameMode.Creative) return;
	const rule = blockArrays.blockEggBreakTypes[brokenBlockPermutation.type.id];
	if (!rule) return;
	const {amountCount,crackedState,sound} = rule;
	const amount = brokenBlockPermutation.getState(amountCount.state);
	const cracks = brokenBlockPermutation.getState(crackedState.state);
	const isString = amountCount.type=="string";
	if (sound) dimension.playSound(sound,block.center());
	if (player.isSneaking) {
		if (isString) {
			const index = amountCount.values.indexOf(amount);
			if (index>0) {
				const newAmount = amountCount.values[index-1];
				block.setPermutation(BlockPermutation.resolve(brokenBlockPermutation.type.id,{[amountCount.state]:newAmount,[crackedState.state]:cracks}));
			}
		}
		else if (amount>amountCount.min) {
			block.setPermutation(BlockPermutation.resolve(brokenBlockPermutation.type.id,{[amountCount.state]:amount-1,[crackedState.state]:cracks}));
		}
		return;
	}
	let dropCount = 0;
	if (isString) {
		dropCount = amountCount.values.indexOf(amount);
	}
	else {
		dropCount = amount;
	}
	for (let i = 0; i < dropCount; i++) {
		dimension.spawnItem(new ItemStack(brokenBlockPermutation.type.id,1),block.center());
	}
};

export function blockEggFallOn(block,dimension) {
	const rule = blockArrays.blockEggFallOnTypes[block.typeId];
	if (!rule) return;
	const breakChance = 1/rule.breakDenominator;
	if (Math.random()>breakChance) {
		if (rule.crackParticle) dimension.spawnParticle(rule.crackParticle,block.center());
		if (rule.crackSound) dimension.playSound(rule.crackSound,block.center());
		return;
	}
	const {count} = rule;
	const amount = block.permutation.getState(count.state);
	let changeAmount = false;
	if (count.type=="string") {
		const index = count.values.indexOf(amount);
		if (index>0) {
			block.setPermutation(block.permutation.withState(count.state,count.values[index-1]));
			changeAmount = true;
		}
	}
	else {
		if (amount>count.min) {
			block.setPermutation(block.permutation.withState(count.state,amount-1));
			changeAmount = true;
		}
	}
	if (rule.breakParticle) dimension.spawnParticle(rule.breakParticle,block.center());
	if (rule.breakSound) dimension.playSound(rule.breakSound,block.center());
	if (!changeAmount) {
		block.setType(rule.breakInto);
	}
};

export function blockEggInteract(block,dimension,player) {
	const rule = blockArrays.blockEggInteractTypes[block.typeId];
	if (!rule) return;
	const permutation = block.permutation;
	const itemStack = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	if (itemStack.typeId==block.typeId) {
		if (player.getGameMode()!=GameMode.Creative) {
			if (itemStack.amount>1) itemStack.amount--;
			else itemStack.setItem(undefined);
		}
		const {type} = rule.interaction;
		const blockState = permutation.getState(rule.interaction.state);
		if (rule.particle) dimension.spawnParticle(rule.particle,block.center());
		if (rule.sound) dimension.playSound(rule.sound,block.center());
		if (type=="string") {
			const index = rule.interaction.values.indexOf(blockState);
			if (index<rule.interaction.values.length-1) {
				block.setPermutation(permutation.withState(rule.interaction.state,rule.interaction.values[index+1]));
				return;
			}
		}
		else if (type=="integer") {
			if (blockState<rule.interaction.max) {
				block.setPermutation(permutation.withState(rule.interaction.state,blockState+1));
				return;
			}
		}
	}
	else return;
};

export function blockEggTick(block,dimension) {
	const rule = blockArrays.blockEggHatchTypes[block.typeId];
	const face = block.permutation.getState("minecraft:block_face");
	const array = blockArrays;
	if (!rule||!rule.check(block,face,array)) return;
	const permutation = block.permutation;
	const {type} = rule.hatching;
	if (type=="string") {
		const hatchState = permutation.getState(rule.hatching.state);
		const index = rule.hatching.values.indexOf(hatchState);
		if (index<rule.hatching.values.length-1) {
			if (rule.crackParticle) dimension.spawnParticle(rule.crackParticle,block.center());
			if (rule.crackSound) dimension.playSound(rule.crackSound, block.center());
			block.setPermutation(permutation.withState(rule.hatching.state,rule.hatching.values[index+1]));
			return;
		}
	}
	else if (type=="integer") {
		const hatchState = permutation.getState(rule.hatching.state);
		if (hatchState<rule.hatching.max) {
			if (rule.crackParticle) dimension.spawnParticle(rule.crackParticle,block.center());
			if (rule.crackSound) dimension.playSound(rule.crackSound, block.center());
			block.setPermutation(permutation.withState(rule.hatching.state,hatchState+1));
			return;
		}
	}
	if (rule.hatchParticle) dimension.spawnParticle(rule.hatchParticle,rule.entitySpawnBlockFace?rule.entitySpawnUsingBlockFace(block,permutation,rule.entitySpawnBlockFace):rule.entitySpawnAt(block));
	if (rule.hatchSound) dimension.playSound(rule.hatchSound,rule.entitySpawnBlockFace?rule.entitySpawnUsingBlockFace(block,permutation,rule.entitySpawnBlockFace):rule.entitySpawnAt(block));
	if (rule.blockTurnsInto) {
		if (rule.blockTurnsWithBlockFace) block.setPermutation(BlockPermutation.resolve(rule.blockTurnsInto,{[rule.blockTurnsWithBlockFace]:rule.blockIntoBlockFaceState(permutation,rule.blockTurnsWithBlockFace)}));
		else block.setType(rule.blockTurnsInto);
	}
	let hatchCount = typeof rule.count==="function"?rule.count(mathUtilities):rule.count;
	if (rule.addCount.boolean==true) {
		const amount = permutation.getState(rule.addCount.state);
		if (rule.addCount.type=="string") {
			const indexAmount = rule.addCount.values.indexOf(amount);
			if (indexAmount!=-1) hatchCount += indexAmount;
		}
		else hatchCount += amount;
	}
	for (let i = 0; i < hatchCount; i++) {
		let entitySpawned = dimension.spawnEntity(`${rule.entity}`,rule.entitySpawnBlockFace?rule.entitySpawnUsingBlockFace(block,permutation,rule.entitySpawnBlockFace):rule.entitySpawnAt(block),{spawnEvent:`${rule.event}`});
		if (rule.addEvents.value==true) {
			entitySpawned.triggerEvent(rule.addEvents.event1);
		}
	}
};

/*export function blockEggBreak(block,brokenBlockPermutation,dimension,player) {
	if (player.getGameMode()==GameMode.Creative) return;
	const rule = block.getComponent("megaverse:block_egg").customComponentParameters.params;
	if (!rule) return;
	const amount = brokenBlockPermutation.getState(rule.egg_count.state);
	const crackState = brokenBlockPermutation.getState(rule.cracked_state.state);
	if (rule.sounds.break) dimension.playSound(rule.sounds.break,block.center());
	if (player.isSneaking) {
		if (rule.egg_count.type=="enum") {
			const index = rule.egg_count.values.indexOf(amount);
			if (index>0) {
				const newAmount = rule.egg_count.values[index-1];
				block.setPermutation(BlockPermutation.resolve(brokenBlockPermutation.type.id,{[rule.egg_count.state]:newAmount,[rule.cracked_state.state]:crackState}));
			}
		}
		else if (amount>rule.egg_count.min) {
			block.setPermutation(BlockPermutation.resolve(brokenBlockPermutation.type.id,{[rule.egg_count.state]:amount-1,[rule.cracked_state.state]:crackState}));
		}
		return;
	}
	let dropCount = 0;
	if (rule.egg_count.type=="enum") {
		dropCount = rule.egg_count.values.indexOf(amount);
	}
	else {
		dropCount = amount;
	}
	for (let i = 0; i < dropCount; i++) {
		dimension.spawnItem(new ItemStack(brokenBlockPermutation.type.id,1),block.center());
	}
};

export function blockEggFallOn(block,dimension) {
	const rule = block.getComponent("megaverse:block_egg").customComponentParameters.params;
	if (!rule) return;
	const chance = rule.break_chance.numerator/rule.break_chance.denominator;
	if (Math.random()>chance) {
		if (rule.particles.step) dimension.spawnParticle(rule.particles.step,block.center());
		if (rule.sounds.step) dimension.playSound(rule.sounds.step,block.center());
		return;
	}
	const amount = block.permutation.getState(rule.egg_count.state);
	let changeAmount = false;
	if (rule.egg_count.type=="enum") {
		const index = rule.egg_count.values.indexOf(amount);
		if (index>0) {
			block.setPermutation(block.permutation.withState(rule.egg_count.state,rule.egg_count.values[index-1]));
			changeAmount = true;
		}
	}
	else {
		if (amount>rule.egg_count.min) {
			block.setPermutation(block.permutation.withState(rule.egg_count.state,amount-1));
			changeAmount = true;
		}
	}
	if (rule.particles.break) dimension.spawnParticle(rule.particles.break,block.center());
	if (rule.sounds.break) dimension.playSound(rule.sounds.break,block.center());
	if (!changeAmount) {
		block.setType(rule.breaks_into.block);
	}
};
export function blockEggInteract(block,dimension,player) {
	const rule = block.getComponent("megaverse:block_egg").customComponentParameters.params;
	if (!rule) return;
	const itemStack = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	function interacted(block,dimension,itemUtilities,player,rule) {
		itemUtilities.itemDecrementStack(itemStack,player);
		if (rule.particles.interact) dimension.spawnParticle(rule.particles.interact,block.center());
		if (rule.sounds.interact) dimension.playSound(rule.sounds.interact,block.center());
	};
	if (itemStack.typeId==block.typeId) {
		const blockState = block.permutation.getState(rule.egg_count.state);
		if (rule.egg_count.type=="enum") {
			const index = rule.egg_count.values.indexOf(blockState);
			if (index<rule.egg_count.values.length-1) {
				interacted(block,dimension,itemUtilities,player,rule);
				block.setPermutation(block.permutation.withState(rule.egg_count.state,rule.egg_count.values[index+1]));
				return;
			}
		}
		else if (rule.egg_count.type=="int") {
			if (blockState<rule.egg_count.max) {
				interacted(block,dimension,itemUtilities,player,rule);
				block.setPermutation(block.permutation.withState(rule.egg_count.state,blockState+1));
				return;
			}
		}
	}
	else return;
};

export function blockEggTick(block,dimension) {
	const rule = block.getComponent("megaverse:block_egg").customComponentParameters.params;
	if (!rule) return;
	const crackedState = rule.cracked_state;
	const eggCount = rule.egg_count;
	const hatchesInto = rule.hatches_into;
	const hatchAtLocation = rule.hatch_at_location;
	const nestBlocks = rule.nest_blocks;
	const nestLocation = rule.nest_location;
	const particles = rule.particles;
	const sounds = rule.sounds;
	if (nestLocation.location=="below") {
		function nestBlockLocator(block,nestBlocks,nestLocation) {
			const nesting = block.dimension.getBlock(block.below(nestLocation.steps));
			return (nestBlocks.block_types.includes(nesting.typeId)||nestBlocks.block_tags.some(tag=>nesting.hasTag(tag)));
		};
		if (!nestBlockLocator(block,nestBlocks,nestLocation)) return;
	}
	else return;
	function crackVisuals(dimension,particles,sounds) {
		if (particles.crack) dimension.spawnParticle(particles.crack,block.center());
		if (sounds.crack) dimension.playSound(sounds.crack,block.center());
	};
	const hatchState = block.permutation.getState(crackedState.state);
	if (crackedState.type=="enum") {
		const index = crackedState.values.indexOf(hatchState);
		if (index<crackedState.values.length-1) {
			crackVisuals(dimension,particles,sounds);
			block.setPermutation(block.permutation.withState(crackedState.state,crackedState.values[index+1]));
			return;
		}
	}
	else if (crackedState.type=="int") {
		if (hatchState<crackedState.max) {
			crackVisuals(dimension,particles,sounds);
			block.setPermutation(block.permutation.withState(crackedState.state,hatchState+1));
			return;
		}
	}
	if (particles.hatch) dimension.spawnParticle(particles.hatch,block.center());
	if (sounds.hatch) dimension.playSound(sounds.hatch,block.center());
	function entitySpawnBlockFace(block) {
	};
	function blockFaceLocator(block,hatchAtLocation) {
	};
	if (hatchAtLocation) {
		if (hatchAtLocation.location=="block_face") block.setPermutation(BlockPermutation.resolve(hatchesInto.block,{[hatchAtLocation.block_face]:blockFaceLocator(block,hatchAtLocation)}));
		else block.setType(hatchesInto.block);
	}
	let hatchCount = hatchesInto.spawn_count;
	const amount = block.permutation.getState(eggCount.state);
	if (eggCount.type=="enum") {
		const indexAmount = eggCount.values.indexOf(amount);
		if (indexAmount!=-1) hatchCount += indexAmount;
	}
	else hatchCount += amount;
	for (let i = 0; i < hatchCount; i++) {
		let entitySpawned = dimension.spawnEntity(hatchesInto.entity,hatchAtLocation.location=="block_face"?entitySpawnBlockFace(block):block.center(),{spawnEvent:hatchesInto.spawn_event});
	}
};*/

export function blockFireDragonEggBreak(block,brokenBlockPermutation,dimension,player,params) {
	const rule = params;
	if (player.getGameMode()==GameMode.Creative) return;
	if (rule.block_particles.destroyed) dimension.spawnParticle(rule.block_particles.destroyed,block.center());
	if (rule.block_sounds.destroyed) dimension.playSound(rule.block_sounds.destroyed,block.center());
};
export function blockFireDragonEggTick(block,dimension,params) {
	const rule = params;
	if (block.isWaterlogged) return;
	const blockBelow = block.dimension.getBlock(block.below(1));
	if (!rule.requirements.block_types.includes(blockBelow.typeId)&&!rule.requirements.block_tags.some(tag=>blockBelow.hasTag(tag))) return;
	function crackVisuals(dimension,rule) {
		if (rule.block_particles.cracked) dimension.spawnParticle(rule.block_particles.cracked,block.center());
		if (rule.block_sounds.cracked) dimension.playSound(rule.block_sounds.cracked,block.center());
	};
	const crackedState = block.permutation.getState(rule.cracked_state.identifier);
	const index = rule.cracked_state.values.indexOf(crackedState);
	if (index<rule.cracked_state.values.length-1) {
		crackVisuals(dimension,rule);
		block.setPermutation(block.permutation.withState(rule.cracked_state.identifier,rule.cracked_state.values[index+1]));
		return;
	}
	if (rule.block_particles.hatched) dimension.spawnParticle(rule.block_particles.hatched,block.center());
	if (rule.block_sounds.hatched) dimension.playSound(rule.block_sounds.hatched,block.center());
	block.setType(rule.block_turns_into);
	dimension.spawnEntity(rule.entity.identifier,block.center(),{spawnEvent:rule.entity.event});
};

export function blockFlowerInteract(block,dimension,player) {
	const rule = block.getComponent("megaverse:block_flower").customComponentParameters.params;
	if (!rule) return;
	const itemStack = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	if (!itemStack.hasItem()) return;
	if (!rule.growth_items.item_types.includes(itemStack.typeId)&&!rule.growth_items.item_tags.some(tag=>itemStack.hasTag(tag))) return;
	if (player.getGameMode()!=GameMode.Creative) itemUtilities.itemDecrementStack(itemStack,player);
	if (rule.grow_sound) dimension.playSound(rule.grow_sound,block.center());
	if (rule.grows_into.type=="block") {
		if (rule.grow_particle) dimension.spawnParticle(rule.grow_particle,block.center());
		return block.setType(rule.grows_into.block);
	}
	else if (rule.grows_into.type=="feature") {
		if (rule.grow_particle) dimension.spawnParticle(rule.grow_particle,block.center());
		return dimension.placeFeature(rule.grows_into.feature,block.center());
	}
	else return;
};
export function blockPlantInteract(block,dimension,player) {
	const rule = block.getComponent("megaverse:block_plant").customComponentParameters.params;
	if (!rule) return;
	const itemStack = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	if (!itemStack.hasItem()) return;
	if (!rule.growth_items.item_types.includes(itemStack.typeId)&&!rule.growth_items.item_tags.some(tag=>itemStack.hasTag(tag))) return;
	if (player.getGameMode()!=GameMode.Creative) itemUtilities.itemDecrementStack(itemStack,player);
	if (rule.grow_sound) dimension.playSound(rule.grow_sound,block.center());
	if (rule.grows_into.type=="block") {
		if (rule.grow_particle) dimension.spawnParticle(rule.grow_particle,block.center());
		return block.setType(rule.grows_into.block);
	}
	else if (rule.grows_into.type=="feature") {
		if (rule.grow_particle) dimension.spawnParticle(rule.grow_particle,block.center());
		return dimension.placeFeature(rule.grows_into.feature,block.center());
	}
	else return;
};
export function blockLayer(block,dimension,player,params) {
	const rule = params;
	const amount = block.permutation.getState("megaverse:amount");
	const itemStack = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	if (!itemStack) return;
	if (itemStack.typeId==block.typeId) {
		if (player.getGameMode()!=GameMode.Creative) {
			if (amount==7) return;
			if (itemStack.amount>1) itemStack.amount--;
			else itemStack.setItem(undefined);
		}
		if (amount!=7) {
			if (rule.sounds.add) dimension.playSound(rule.sounds.add,block.center());
			return block.setPermutation(block.permutation.withState("megaverse:amount",amount+1));
		}
	}
	else return;
};
export function blockLayerBreak(block,brokenBlockPermutation,dimension,player,params) {
	const rule = params;
	if (player.getGameMode()==GameMode.Creative) return;
	const itemStack = player.getComponent("minecraft:equippable").getEquipment(EquipmentSlot.Mainhand);
	if (!itemStack) return;
	const enchantable = itemStack.getComponent("minecraft:enchantable");
	const silkTouch = enchantable?.getEnchantment("silk_touch");
	if (!silkTouch) return;
	const amount = brokenBlockPermutation.getState("megaverse:amount");
	let dropCount = amount;
	for (let i = 0; i < dropCount; i++) {
		dimension.spawnItem(new ItemStack(brokenBlockPermutation.type.id,1),block.center());
	}
};
export function blockSaplingInteract(block,dimension,player) {
	const rule = block.getComponent("megaverse:block_sapling").customComponentParameters.params;
	if (!rule) return;
	const itemStack = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	if (!itemStack.hasItem()) return;
	if (!rule.growth_items.item_types.includes(itemStack.typeId)&&!rule.growth_items.item_tags.some(tag=>itemStack.hasTag(tag))) return;
	if (rule.grow_particle) dimension.spawnParticle(rule.grow_particle,block.center());
	if (rule.grow_sound) dimension.playSound(rule.grow_sound,block.center());
	if (player.getGameMode()!=GameMode.Creative&&rule.growth_chance) {
		itemUtilities.itemDecrementStack(itemStack,player);
		const fraction = rule.growth_chance.numerator/rule.growth_chance.denominator;
		if (Math.random()>fraction) return;
	}
	system.run(()=>{
		if (rule.grows_into.type=="feature") dimension.placeFeature(rule.grows_into.feature,block.center());
		else dimension.placeFeature(rule.grows_into.block,block.center());
	});
};

export function blockSaplingRandomTick(block,dimension) {
	const rule = block.getComponent("megaverse:block_sapling").customComponentParameters.params;
	if (!rule) return;
	if (rule.growth_chance) {
		const fraction = rule.growth_chance.numerator/rule.growth_chance.denominator;
		if (Math.random()>fraction) return;
	}
	system.run(()=>{
		if (rule.grows_into.type=="feature") dimension.placeFeature(rule.grows_into.feature,block.center());
		else dimension.placeFeature(rule.grows_into.block,block.center());
	});
};

export function blockSmallShutterInteract(block,dimension,player) {
	const blockType = block.typeId;
	const openBit = block.permutation.getState("megaverse:open_bit");
	if (openBit==false) {
		block.setPermutation(block.permutation.withState("megaverse:open_bit",true));
		if (blockType.includes("bamboo")||blockType.includes("cherry")||blockType.includes("crimson")||blockType.includes("warped")) {
			if (blockType.includes("bamboo")) dimension.playSound("open.bamboo_wood_trapdoor", block.center());
			if (blockType.includes("cherry")) dimension.playSound("open.cherry_wood_trapdoor", block.center());
			if (blockType.includes("crimson")||blockType.includes("warped")) dimension.playSound("open.nether_wood_trapdoor", block.center());
		}
		else dimension.playSound("open.wooden_trapdoor", block.center());
	}
	else {
		block.setPermutation(block.permutation.withState("megaverse:open_bit",false));
		if (blockType.includes("bamboo")||blockType.includes("cherry")||blockType.includes("crimson")||blockType.includes("warped")) {
			if (blockType.includes("bamboo")) dimension.playSound("close.bamboo_wood_trapdoor", block.center());
			if (blockType.includes("cherry")) dimension.playSound("close.cherry_wood_trapdoor", block.center());
			if (blockType.includes("crimson")||blockType.includes("warped")) dimension.playSound("close.nether_wood_trapdoor", block.center());
		}
		else dimension.playSound("close.wooden_trapdoor", block.center());
	}
};

export function blockTrapCoverFallOn(block,dimension) {
	const isTrapCover = (typeId)=>blockArrays.blockTrapCoverTypes.includes(typeId);
	const offsets = [
		{x: 0, z: 0},
		{x: 1, z: 0}, {x: -1, z: 0}, {x: 0, z: 1}, {x: 0, z: -1},
		{x: 1, z: 1}, {x: -1, z: -1}, {x: 1, z: -1}, {x: -1, z: 1}
	];
	if (block.typeId.includes("leaf")) dimension.playSound("block.leaf_litter.break", block.center());
	else if (block.typeId.includes("moss")) dimension.playSound("dig.moss", block.center());
	else dimension.playSound("dig.grass", block.center());
	for (const offset of offsets) {
		const x = block.location.x+offset.x;
		const y = block.location.y;
		const z = block.location.z+offset.z;
		const adjacent = dimension.getBlock({x,y,z});
		if (adjacent&&isTrapCover(adjacent.typeId)) {
			dimension.runCommand(`setblock ${x} ${y} ${z} air destroy`);
		}
	}
};

export function blockTrapCoverStepOn(block, dimension, entity) {
	//const rule = blockArrays.blockTrapCoverTypes[block.typeId];
	const isTrapCover = (typeId)=>blockArrays.blockTrapCoverTypes.includes(typeId);
	const offsets = [
		{x: 0, z: 0},
		{x: 1, z: 0}, {x: -1, z: 0}, {x: 0, z: 1}, {x: 0, z: -1},
		{x: 1, z: 1}, {x: -1, z: -1}, {x: 1, z: -1}, {x: -1, z: 1}
	];
	dimension.spawnParticle(`${block.typeId}_breaking`, {x:block.center().x,y:block.location.y+1,z:block.center().z});
	if (entity.isSneaking) {
		if (block.typeId.includes("leaf")) dimension.playSound("block.leaf_litter.step", block.center());
		else if (block.typeId.includes("moss")) dimension.playSound("step.moss", block.center());
		else dimension.playSound("step.grass", block.center());
		return;
	}
	if (block.typeId.includes("leaf")) dimension.playSound("block.leaf_litter.break", block.center());
	else if (block.typeId.includes("moss")) dimension.playSound("dig.moss", block.center());
	else dimension.playSound("dig.grass", block.center());
	if (entity.typeId=="minecraft:item") return;
	for (const offset of offsets) {
		const x = block.location.x+offset.x;
		const y = block.location.y;
		const z = block.location.z+offset.z;
		const adjacent = dimension.getBlock({x,y,z});
		if (adjacent&&isTrapCover(adjacent.typeId)) {
			dimension.runCommand(`setblock ${x} ${y} ${z} air destroy`);
		}
	}
};

export function burntBlockRandomTick(block,dimension,params) {
	const rule = params;
	const percentageChance = rule.turn_chance.numerator/rule.turn_chance.denominator;
	if (Math.random()>percentageChance) return;
	block.setType(rule.turns_into);
};

export function cryothermaliaRandomTick(block,dimension) {
	const blockBelow = block.dimension.getBlock(block.below(1));
	const active = block.permutation.getState("megaverse:active");
	const convertBlock = blockBelow.typeId.split("minecraft:");
	const toFrost = "megaverse:frosted_";
	if (active==false) {
		if (blockBelow.typeId.includes("frosted_")||blockBelow.typeId.includes("glaciered_")) {
			block.setPermutation(block.permutation.withState("megaverse:active",true));
			dimension.playSound("mob.player.hurt_freeze", block.center());
			dimension.spawnParticle("megaverse:cryothermalia_freeze", block.center());
		}
		else {
			blockBelow.setPermutation(BlockPermutation.resolve(`${toFrost}${convertBlock[1]}`,{"megaverse:age":0}));
		}
	}
	else {
		if (!blockBelow.typeId.includes("frosted_")&&!blockBelow.typeId.includes("glaciered_")) {
			block.setPermutation(block.permutation.withState("megaverse:active",false));
			dimension.playSound("random.glass", block.center());
			dimension.spawnParticle("megaverse:frost", block.center());
		}
	}
};

export function cryothermaliaTick(block,dimension) {
	const mobs = block.dimension.getEntities({families:["mob"],location:block.center(),maxDistance:1});
	const players = block.dimension.getEntities({type:"player",location:block.center(),maxDistance:1});
	mobs.forEach((mob) => {
		const mobType = mob.typeId;
		if (mobType.includes("frost")||mobType.includes("ice_")) return;
		dimension.spawnParticle("megaverse:cryothermalia_freeze",block.center());
		mob.applyDamage(1,{cause:EntityDamageCause.freezing});
	});
	players.forEach((player) => {
		dimension.spawnParticle("megaverse:cryothermalia_freeze",block.center());
		player.applyDamage(1,{cause:EntityDamageCause.freezing});
	});
};

export function deerSkullBreak(block,brokenBlockPermutation,dimension,player) {
	if (player.getGameMode()==GameMode.Creative) return;
	const amount = brokenBlockPermutation.getState("megaverse:amount");
	const antler = amount-1;
	if (amount==1) return dimension.spawnItem(new ItemStack("megaverse:deer_antler",1),block.center());
	else for (let i = 0; i < antler; i++) dimension.spawnItem(new ItemStack("megaverse:deer_antler",1),block.center());
};

export function deerSkullInteract(block,dimension,face,player) {
	const mainhand = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	const amount = block.permutation.getState("megaverse:amount");
	const rotation = block.permutation.getState("megaverse:rotation");
	const direction = block.permutation.getState("minecraft:cardinal_direction");
	const blockFace = block.permutation.getState("minecraft:block_face");
	function interactSound(block,dimension) {
		dimension.playSound("dig.bone_block", block.center());
	};
	function decrementStack(mainhand,player) {
		if (player.getGameMode()!=GameMode.Creative) {
			if (mainhand.amount>1) mainhand.amount--;
			else mainhand.setItem(undefined);
		}
	};
	function leftAntler(block,dimension,mainhand,player) {
		interactSound(block,dimension);
		decrementStack(mainhand,player);
		block.setPermutation(block.permutation.withState("megaverse:amount",1));
	};
	function rightAntler(block,dimension,mainhand,player) {
		interactSound(block,dimension);
		decrementStack(mainhand,player);
		block.setPermutation(block.permutation.withState("megaverse:amount",2));
	};
	function allAntlers(block,dimension,mainhand,player) {
		interactSound(block,dimension);
		decrementStack(mainhand,player);
		block.setPermutation(block.permutation.withState("megaverse:amount",3));
	};
	if (!mainhand.hasItem()||mainhand.typeId!="megaverse:deer_antler") {
		interactSound(block,dimension);
		if (rotation!=4) return block.setPermutation(block.permutation.withState("megaverse:rotation",rotation+1));
		else return block.setPermutation(block.permutation.withState("megaverse:rotation",0));
	}
	else if (mainhand.typeId=="megaverse:deer_antler") {
		if (amount==0) {
			if (blockFace=="up"||blockFace=="down") {
				if (direction=="north") {
					if (rotation<=2) {
						if (face=="West") return leftAntler(block,dimension,mainhand,player);
						if (face=="East") return rightAntler(block,dimension,mainhand,player);
					}
					if (rotation==3) {
						if (face=="West") return leftAntler(block,dimension,mainhand,player);
						if (face=="North") return rightAntler(block,dimension,mainhand,player);
					}
					if (rotation==4) {
						if (face=="North") return leftAntler(block,dimension,mainhand,player);
						if (face=="East") return rightAntler(block,dimension,mainhand,player);
					}
				}
				if (direction=="south") {
					if (rotation<=2) {
						if (face=="East") return leftAntler(block,dimension,mainhand,player);
						if (face=="West") return rightAntler(block,dimension,mainhand,player);
					}
					if (rotation==3) {
						if (face=="East") return leftAntler(block,dimension,mainhand,player);
						if (face=="South") return rightAntler(block,dimension,mainhand,player);
					}
					if (rotation==4) {
						if (face=="South") return leftAntler(block,dimension,mainhand,player);
						if (face=="West") return rightAntler(block,dimension,mainhand,player);
					}
				}
				if (direction=="west") {
					if (rotation<=2) {
						if (face=="South") return leftAntler(block,dimension,mainhand,player);
						if (face=="North") return rightAntler(block,dimension,mainhand,player);
					}
					if (rotation==3) {
						if (face=="South") return leftAntler(block,dimension,mainhand,player);
						if (face=="West") return rightAntler(block,dimension,mainhand,player);
					}
					if (rotation==4) {
						if (face=="West") return leftAntler(block,dimension,mainhand,player);
						if (face=="North") return rightAntler(block,dimension,mainhand,player);
					}
				}
				if (direction=="east") {
					if (rotation<=2) {
						if (face=="North") return leftAntler(block,dimension,mainhand,player);
						if (face=="South") return rightAntler(block,dimension,mainhand,player);
					}
					if (rotation==3) {
						if (face=="North") return leftAntler(block,dimension,mainhand,player);
						if (face=="East") return rightAntler(block,dimension,mainhand,player);
					}
					if (rotation==4) {
						if (face=="East") return leftAntler(block,dimension,mainhand,player);
						if (face=="South") return rightAntler(block,dimension,mainhand,player);
					}
				}
			}
			if (blockFace=="north") {
				if (face=="West") return leftAntler(block,dimension,mainhand,player);
				if (face=="East") return rightAntler(block,dimension,mainhand,player);
			}
			if (blockFace=="south") {
				if (face=="East") return leftAntler(block,dimension,mainhand,player);
				if (face=="West") return rightAntler(block,dimension,mainhand,player);
			}
			if (blockFace=="west") {
				if (face=="South") return leftAntler(block,dimension,mainhand,player);
				if (face=="North") return rightAntler(block,dimension,mainhand,player);
			}
			if (blockFace=="east") {
				if (face=="North") return leftAntler(block,dimension,mainhand,player);
				if (face=="South") return rightAntler(block,dimension,mainhand,player);
			}
		}
		if (amount==1) {
			if (blockFace=="up"||blockFace=="down") {
				if (direction=="north") {
					if (rotation!=3&&face=="East") return allAntlers(block,dimension,mainhand,player);
					if (rotation==3&&face=="North") return allAntlers(block,dimension,mainhand,player);
				}
				if (direction=="south") {
					if (rotation!=3&&face=="West") return allAntlers(block,dimension,mainhand,player);
					if (rotation==3&&face=="South") return allAntlers(block,dimension,mainhand,player);
				}
				if (direction=="west") {
					if (rotation!=3&&face=="North") return allAntlers(block,dimension,mainhand,player);
					if (rotation==3&&face=="West") return allAntlers(block,dimension,mainhand,player);
				}
				if (direction=="east") {
					if (rotation!=3&&face=="South") return allAntlers(block,dimension,mainhand,player);
					if (rotation==3&&face=="East") return allAntlers(block,dimension,mainhand,player);
				}
			}
			if (blockFace=="north"&&face=="East") return allAntlers(block,dimension,mainhand,player);
			if (blockFace=="south"&&face=="West") return allAntlers(block,dimension,mainhand,player);
			if (blockFace=="west"&&face=="North") return allAntlers(block,dimension,mainhand,player);
			if (blockFace=="east"&&face=="South") return allAntlers(block,dimension,mainhand,player);
		}
		if (amount==2) {
			if (blockFace=="up"||blockFace=="down") {
				if (direction=="north") {
					if (rotation!=4&&face=="West") return allAntlers(block,dimension,mainhand,player);
					if (rotation==4&&face=="North") return allAntlers(block,dimension,mainhand,player);
				}
				if (direction=="south") {
					if (rotation!=4&&face=="East") return allAntlers(block,dimension,mainhand,player);
					if (rotation==4&&face=="South") return allAntlers(block,dimension,mainhand,player);
				}
				if (direction=="west") {
					if (rotation!=4&&face=="South") return allAntlers(block,dimension,mainhand,player);
					if (rotation==4&&face=="West") return allAntlers(block,dimension,mainhand,player);
				}
				if (direction=="east") {
					if (rotation!=4&&face=="North") return allAntlers(block,dimension,mainhand,player);
					if (rotation==4&&face=="East") return allAntlers(block,dimension,mainhand,player);
				}
			}
			if (blockFace=="north"&&face=="West") return allAntlers(block,dimension,mainhand,player);
			if (blockFace=="south"&&face=="East") return allAntlers(block,dimension,mainhand,player);
			if (blockFace=="west"&&face=="South") return allAntlers(block,dimension,mainhand,player);
			if (blockFace=="east"&&face=="North") return allAntlers(block,dimension,mainhand,player);
		}
	}
};
export function fallingBlockTick(block,dimension,rule) {
	const blockBelow = block.dimension.getBlock(block.below(1));
	if (blockBelow.isAir||blockBelow.isLiquid) {
		block.setType("minecraft:air");
		dimension.spawnEntity(rule.block_entity,{x:block.center().x,y:block.location.y,z:block.center().z});
	}
	else return;
};
export function firewoodBreak(block,brokenBlockPermutation,dimension,player) {
	if (player.getGameMode()==GameMode.Creative) return;
	const amount = brokenBlockPermutation.getState("megaverse:amount");
	for (let i = 0; i < amount; i++) {
		dimension.spawnItem(new ItemStack(brokenBlockPermutation.type.id,1),block.center());
	}
};

export function firewoodInteract(block,dimension,player) {
	const item = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	const amount = block.permutation.getState("megaverse:amount");
	const direction = block.permutation.getState("minecraft:cardinal_direction");
	const fuelItemTags = itemArrays.firewoodKindlingFuelItemTags.some(tag=>item.hasTag(tag));
	const fuelItemTypes = itemArrays.firewoodKindlingFuelItemTypes.includes(item.typeId);
	if (item.typeId==block.typeId&&amount!=15) {
		itemUtilities.itemDecrementStack(item,player);
		dimension.playSound("dig.wood", block.center());
		block.setPermutation(block.permutation.withState("megaverse:amount",amount+1));
	}
	if (amount==3&&(fuelItemTags||fuelItemTypes)) {
		itemUtilities.itemDecrementStack(item,player);
		dimension.playSound("use.wood", block.center());
		block.setPermutation(BlockPermutation.resolve("megaverse:kindling_pile",{"minecraft:cardinal_direction":direction,"megaverse:active":false}));
	}
};

export function frostRandomTick(block,dimension) {
	const age = block.permutation.getState("megaverse:age");
	const percentageChance = 1/3;
	if (Math.random()>percentageChance) return;
	if (age!=3) block.setPermutation(block.permutation.withState("megaverse:age",age+1));
	else {
		block.setType("minecraft:air");
		dimension.playSound("break.suspicious_sand", block.center());
		dimension.spawnParticle(block.typeId, block.center());
	}
};

export function frostTick(block,dimension) {
	const age = block.permutation.getState("megaverse:age");
	const blockBelow = block.dimension.getBlock(block.below(1));
	const convertBlock = block.typeId.split(":");
	if (blockBelow.isAir||blockBelow.isLiquid) {
		block.setType("minecraft:air");
		let fallingBlock = dimension.spawnEntity(`${convertBlock[0]}:falling_${convertBlock[1]}`,{x:block.center().x,y:block.location.y,z:block.center().z});
		fallingBlock.setProperty("megaverse:falling_block_age",age);
	}
	else return;
};

export function frostedBlockRandomTick(block,dimension) {
	const age = block.permutation.getState("megaverse:age");
	const convertBlock = block.typeId.split("frosted_");
	if (age!=3) block.setPermutation(block.permutation.withState("megaverse:age",age+1));
	else block.setType(`minecraft:${convertBlock[1]}`);
};
export function frostedBlockTick(block,dimension) {
	const age = block.permutation.getState("megaverse:age");
	const blockBelow = block.dimension.getBlock(block.below(1));
	const convertBlock = block.typeId.split(":");
	if (blockBelow.isAir||blockBelow.isLiquid) {
		block.setType("minecraft:air");
		let fallingBlock = dimension.spawnEntity(`${convertBlock[0]}:falling_${convertBlock[1]}`,{x:block.center().x,y:block.location.y,z:block.center().z});
		fallingBlock.setProperty("megaverse:falling_block_age",age);
	}
	else return;
};
export function fuelCanBreak(block,brokenBlockPermutation,dimension,player) {
	if (player.getGameMode()==GameMode.Creative) return;
	const itemStack = player.getComponent("minecraft:equippable").getEquipment(EquipmentSlot.Mainhand);
	if (!itemStack) return;
	const enchantable = itemStack.getComponent("minecraft:enchantable");
	const silkTouch = enchantable?.getEnchantment("silk_touch");
	if (!silkTouch) return;
	const amount = brokenBlockPermutation.getState("megaverse:amount");
	let dropCount = amount;
	for (let i = 0; i < dropCount; i++) {
		dimension.spawnItem(new ItemStack(brokenBlockPermutation.type.id,1),block.center());
	}
};
export function fuelCanInteract(block,dimension,player) {
	const itemStack = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	if (!itemStack.hasItem()) return;
	if (itemStack.typeId==block.typeId) {
		if (player.getGameMode()!=GameMode.Creative) {
			if (itemStack.amount>1) itemStack.amount--;
			else itemStack.setItem(undefined);
		}
		const amount = block.permutation.getState("megaverse:amount");
		dimension.playSound("place.iron",block.center());
		if (amount<7) {
			block.setPermutation(block.permutation.withState("megaverse:amount",amount+1));
			return;
		}
	}
	else return;
};
export function greatVelanidiaSaplingInteract(block,dimension,player,rule) {
	const itemStack = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	if (!itemStack.hasItem()) return;
	if (!rule.growth_items.item_types.includes(itemStack.typeId)&&!rule.growth_items.item_tags.some(tag=>itemStack.hasTag(tag))) return;
	if (rule.grow_particle) dimension.spawnParticle(rule.grow_particle,block.center());
	if (rule.grow_sound) dimension.playSound(rule.grow_sound,block.center());
	if (player.getGameMode()!=GameMode.Creative&&rule.growth_chance) {
		itemUtilities.itemDecrementStack(itemStack,player);
		const fraction = rule.growth_chance.numerator/rule.growth_chance.denominator;
		if (Math.random()>fraction) return;
	}
	const offsets = [[-1,0,0],[1,0,0],[0,0,-1],[0,0,1],[-1,0,-1],[-1,0,1],[1,0,1],[1,0,-1]];
	for (const [dx,dy,dz] of offsets) {
		const requiredLocation = {
			x: block.center().x+dx,
			y: block.center().y+dy,
			z: block.center().z+dz
		};
		const requiredBlocksLocation = dimension.getBlock(requiredLocation);
		if (requiredBlocksLocation.typeId!=block.typeId) return;
	}
	system.run(()=>{
		if (rule.grows_into.type=="feature") dimension.placeFeature(rule.grows_into.feature,{x:block.center().x-1,y:block.center().y,z:block.center().z-1});
		else dimension.placeFeature(rule.grows_into.block,block.center());
	});
};

export function greatVelanidiaSaplingRandomTick(block,dimension,rule) {
	const offsets = [[-1,0,0],[1,0,0],[0,0,-1],[0,0,1],[-1,0,-1],[-1,0,1],[1,0,1],[1,0,-1]];
	for (const [dx,dy,dz] of offsets) {
		const requiredLocation = {
			x: block.center().x+dx,
			y: block.center().y+dy,
			z: block.center().z+dz
		};
		const requiredBlocksLocation = dimension.getBlock(requiredLocation);
		if (requiredBlocksLocation.typeId!=block.typeId) return;
	}
	if (rule.growth_chance) {
		const fraction = rule.growth_chance.numerator/rule.growth_chance.denominator;
		if (Math.random()>fraction) return;
	}
	system.run(()=>{
		if (rule.grows_into.type=="feature") dimension.placeFeature(rule.grows_into.feature,{x:block.center().x-1,y:block.center().y,z:block.center().z-1});
		else dimension.placeFeature(rule.grows_into.block,block.center());
	});
};
export function iceSpikesFallOn(block,dimension) {
	const age = block.permutation.getState("megaverse:age");
	if (age!=3) {
		dimension.spawnParticle("megaverse:frost", block.center());
		dimension.playSound("random.glass", block.center());
		block.setPermutation(block.permutation.withState("megaverse:age",age+1));
	}
	else {
		dimension.spawnParticle("megaverse:frost", block.center());
		dimension.playSound("random.glass", block.center());
		block.setType("minecraft:air");
	}
};

export function iceSpikesRandomTick(block,dimension) {
	const age = block.permutation.getState("megaverse:age");
	if (age!=3) {
		dimension.playSound("drip.water.pointed_dripstone", block.center());
		block.setPermutation(block.permutation.withState("megaverse:age",age+1));
	}
	else {
		dimension.spawnParticle("megaverse:frost", block.center());
		dimension.playSound("drip.water.pointed_dripstone", block.center());
		block.setType("minecraft:air");
	}
};

export function iceSpikesStepOn(block,dimension,entity) {
	const age = block.permutation.getState("megaverse:age");
	const damageAmount = 4-age;
	entity.applyDamage(damageAmount,{cause:EntityDamageCause.contact});
	if (age!=3) {
		dimension.spawnParticle("megaverse:frost", block.center());
		dimension.playSound("random.glass", block.center());
		block.setPermutation(block.permutation.withState("megaverse:age",age+1));
	}
	else {
		dimension.spawnParticle("megaverse:frost", block.center());
		dimension.playSound("random.glass", block.center());
		block.setType("minecraft:air");
	}
};

export function kindlingPileBreak(block,brokenBlockPermutation,dimension,player) {
	if (player.getGameMode()==GameMode.Creative) return;
	const active = brokenBlockPermutation.getState("megaverse:active");
	if (active==true) {
		dimension.spawnItem(new ItemStack("minecraft:stick",1),block.center());
	}
};

export function kindlingPileInteract(block,dimension,player) {
	const item = player.getComponent("minecraft:equippable").getEquipment(EquipmentSlot.Mainhand);
	const enchantable = item.getComponent("minecraft:enchantable");
	const fireAspect = enchantable?.getEnchantment("fire_aspect");
	const active = block.permutation.getState("megaverse:active");
	const amount = block.permutation.getState("megaverse:amount");
	const direction = block.permutation.getState("minecraft:cardinal_direction");
	if (item.typeId=="minecraft:stick") {
		if (active==false) {
			itemUtilities.itemDecrementStack(item,player);
			dimension.playSound("dig.wood", block.center());
			block.setPermutation(block.permutation.withState("megaverse:active",true));
		}
		else {
			const percentageChance = 1/3;
			if (Math.random()>percentageChance) {
				dimension.spawnParticle("megaverse:fire_starting_smoke",block.center());
				dimension.playSound("fire.ignite",block.center());
			}
			else {
				const percentageChance = 1/2;
				if (Math.random()>percentageChance) {
					itemUtilities.itemDecrementStack(item,player);
					dimension.spawnParticle("megaverse:fire_starting_smoke",block.center());
					dimension.playSound("random.break",block.center());
					block.setPermutation(block.permutation.withState("megaverse:active",false));
				}
				else {
					dimension.spawnParticle("megaverse:fire_starting_spark",block.center());
					dimension.playSound("mob.ghast.fireball",block.center());
					block.setPermutation(BlockPermutation.resolve("minecraft:campfire",{"minecraft:cardinal_direction":direction,"extinguished":false}));
				}
			}
		}
	}
	if (item.typeId=="minecraft:flint") {
		const percentageChance = 1/3;
		if (Math.random()>percentageChance) {
			dimension.spawnParticle("megaverse:fire_starting_smoke",block.center());
			dimension.playSound("fire.ignite",block.center());
		}
		else {
			dimension.spawnParticle("megaverse:fire_starting_spark",block.center());
			dimension.playSound("mob.ghast.fireball",block.center());
			block.setPermutation(BlockPermutation.resolve("minecraft:campfire",{"minecraft:cardinal_direction":direction,"extinguished":false}));
		}
	}
	if (fireAspect||item.typeId=="minecraft:fire_charge"||item.typeId=="minecraft:flint_and_steel") {
		block.setPermutation(BlockPermutation.resolve("minecraft:campfire",{"minecraft:cardinal_direction":direction,"extinguished":false}));
		dimension.spawnParticle("megaverse:fire_starting_spark", block.center());
		dimension.playSound("fire.ignite", block.center());
	}
};

export function pyronellaRandomTick(block,dimension,rule) {
	const skyLightLevel = block.getSkyLightLevel();
	if (rule.change_type) {
		if (skyLightLevel>=rule.change_type.min_sky_light_level&&skyLightLevel<=rule.change_type.max_sky_light_level) {
			if (rule.change_type.sound) dimension.playSound(rule.change_type.sound,block.center());
			if (rule.change_type.particle) dimension.spawnParticle(rule.change_type.particle,block.center());
			block.setType(rule.change_type.block_type);
		}
	}
	if (rule.burn_entities) {
		const mobs = block.dimension.getEntities({families:["mob"],location:block.center(),maxDistance:rule.burn_entities.burn_radius});
		const players = block.dimension.getEntities({type:"player",location:block.center(),maxDistance:rule.burn_entities.burn_radius});
		mobs.forEach((mob)=>{
			dimension.spawnParticle(rule.burn_entities.burn_particle,block.center());
			mob.setOnFire(rule.burn_entities.burn_time);
		});
		players.forEach((player)=>{
			dimension.spawnParticle(rule.burn_entities.burn_particle,block.center());
			player.setOnFire(rule.burn_entities.burn_time);
		});
	}
};

export function sconceInteract(block,dimension,player) {
	const mainhand = player.getComponent("minecraft:equippable").getEquipmentSlot(EquipmentSlot.Mainhand);
	const extinguished = block.permutation.getState("megaverse:extinguished");
	const blockFace = block.permutation.getState("minecraft:block_face");
	const offset = blockArrays.sconceParticleOffsets[blockFace];
	const center = block.center();
	const vector = {x:center.x+offset.x,y:center.y+offset.y,z:center.z+offset.z};
	const itemStack = mainhand.getItem();
	function matchesFireItem(itemStack) {
		return (itemArrays.blockFireItemsTypeIncludes.some(substr => itemStack.typeId.includes(substr))||itemArrays.blockFireItemsTypeId.includes(itemStack.typeId)||itemArrays.blockFireItemsTags.some(tag => itemStack.hasTag(tag)));
	};
	if (extinguished==true) {
		if (matchesFireItem(itemStack)) {
			player.playSound("mob.ghast.fireball",{location:center,pitch:1.25});
			dimension.spawnParticle("megaverse:sconce_emitting_smoke",vector);
			return block.setPermutation(block.permutation.withState("megaverse:extinguished",false));
		}
	}
	else {
		if (mainhand.hasItem()) return;
		player.playSound("random.fizz",{location:center});
		dimension.spawnParticle("megaverse:sconce_extinguished_smoke",vector);
		return block.setPermutation(block.permutation.withState("megaverse:extinguished",true));
	}
};
export function sconceRandomTick(block,dimension) {
	const extinguished = block.permutation.getState("megaverse:extinguished");
	const blockFace = block.permutation.getState("minecraft:block_face");
	const offset = blockArrays.sconceParticleOffsets[blockFace];
	const center = block.center();
	const vector = {x:center.x+offset.x,y:center.y+offset.y,z:center.z+offset.z};
	if (extinguished==true) return;
	else return dimension.spawnParticle("megaverse:sconce_emitting_smoke",vector);
};

export function silkwormCocoonTick(block,dimension) {
	const array = blockArrays;
	const rule = array.silkwormCocoonTypes[block.typeId];
	const face = block.permutation.getState("minecraft:block_face");
	if (!rule||!rule.check(block)) return;
	const permutation = block.permutation;
	if (rule.condition.type=="bool") {
		const conditionState = permutation.getState(rule.condition.state);
		if (conditionState==false) {
			if (rule.addition.type="string") {
				const additionState = permutation.getState(rule.addition.state);
				const index = rule.addition.values.indexOf(additionState);
				if (index>0) {
					if (rule.turnParticle) dimension.spawnParticle(rule.turnParticle,block.center());
					if (rule.turnSound) dimension.playSound(rule.turnSound,block.center());
					return block.setPermutation(permutation.withState(rule.addition.state,rule.addition.values[index-1]));
				}
				else if (index==0&&rule.criteria(block)) {
					if (rule.turnParticle) dimension.spawnParticle(rule.turnParticle,block.center());
					if (rule.turnSound) dimension.playSound(rule.turnSound,block.center());
					return block.setPermutation(permutation.withState(rule.condition.state,true));
				}
				else return;
			}
		}
		else if (conditionState==true) {
			if (rule.turnParticle) dimension.spawnParticle(rule.turnParticle,block.center());
			if (rule.turnSound) dimension.playSound(rule.turnSound,block.center());
			if (rule.criteria(block)) {
				if (rule.blockTurnsWithBlockFace) return block.setPermutation(BlockPermutation.resolve(rule.blockTurnsInto,{[rule.blockTurnsWithBlockFace]:rule.blockIntoBlockFaceState(permutation,rule.blockTurnsWithBlockFace)}));
				else block.setType(rule.blockTurnsInto);
			}
			else return block.setPermutation(permutation.withState(rule.condition.state,false));
		}
	}
};

export function smolderingBlockRandomTick(block,dimension,rule) {
	dimension.spawnParticle(rule.smoldering_particle, block.center());
	const blockFace = block.permutation.getState("minecraft:block_face");
	let percentageChance = rule.turn_chance.numerator/rule.turn_chance.denominator;
	if (rule.smoldering) {
		const age = block.permutation.getState(rule.smoldering.age_state);
		percentageChance = (rule.turn_chance.numerator-age)/rule.turn_chance.denominator;
	}
	if (Math.random()>percentageChance) return;
	if (blockFace) return block.setPermutation(BlockPermutation.resolve(rule.turns_into,{"minecraft:block_face":blockFace}));
	else return block.setType(rule.turns_into);
};

export function smolderingBlockTick(block,dimension,rule) {
	const age = block.permutation.getState(rule.smoldering.age_state);
	const spread = block.permutation.getState(rule.smoldering.spread_state);
	if (spread&&age<rule.smoldering.max) {
		const offsets = [
			{x:1,y:0,z:0}, {x:-1,y:0,z:0},
			{x:0,y:1,z:0}, {x:0,y:-1,z:0},
			{x:0,y:0,z:1}, {x:0,y:0,z:-1},
			{x:1,y:-1,z:0}, {x:-1,y:-1,z:0},
			{x:0,y:-1,z:1}, {x:0,y:-1,z:-1},
			{x:1,y:1,z:0}, {x:-1,y:1,z:0},
			{x:0,y:1,z:1}, {x:0,y:1,z:-1},
			{x:1,y:0,z:1}, {x:-1,y:0,z:1},
			{x:-1,y:0,z:-1}, {x:1,y:0,z:-1}
		];
		const candidates = [];
		for (const o of offsets) {
			const target = dimension.getBlock({
				x: block.location.x+o.x,
				y: block.location.y+o.y,
				z: block.location.z+o.z
			});
			if (!target) continue;
			if (target.typeId==rule.smoldering.smolder_blocks) {
				candidates.push(target);
			}
		}
		if (candidates.length>0) {
			const target = candidates[Math.floor(Math.random()*candidates.length)];
			const newAge = Math.min(age+1,rule.smoldering.max);
			target.dimension.setBlockPermutation(target.center(),BlockPermutation.resolve(rule.smoldering.smolder,{[rule.smoldering.age_state]:newAge,[rule.smoldering.spread_state]:true}));
		}
		return block.setPermutation(block.permutation.withState(rule.smoldering.spread_state,false));
	}
	else if (spread&&age==rule.smoldering.max) return block.setPermutation(block.permutation.withState(rule.smoldering.spread_state,false));
};

/*export function smolderingBlockTick(block,dimension,params) {
	const rule = params;
	const age = block.permutation.getState(rule.smoldering.age_state);
	if (age<rule.smoldering.max) {
		const offsets = [
			{x:1,y:0,z:0}, {x:-1,y:0,z:0},
			{x:0,y:1,z:0}, {x:0,y:-1,z:0},
			{x:0,y:0,z:1}, {x:0,y:0,z:-1},
			{x:1,y:-1,z:0}, {x:-1,y:-1,z:0},
			{x:0,y:-1,z:1}, {x:0,y:-1,z:-1},
			{x:1,y:1,z:0}, {x:-1,y:1,z:0},
			{x:0,y:1,z:1}, {x:0,y:1,z:-1},
			{x:1,y:0,z:1}, {x:-1,y:0,z:1},
			{x:-1,y:0,z:-1}, {x:1,y:0,z:-1}
		];
		for (const o of offsets) {
			const target = dimension.getBlock({
				x:block.location.x+o.x,
				y:block.location.y+o.y,
				z:block.location.z+o.z
			});
			if (!target) continue;
			if (target.typeId==rule.smoldering.smolder_blocks) {
				const newAge = Math.min(age+1,rule.smoldering.max);
				target.dimension.setBlockPermutation(target.center(),BlockPermutation.resolve(rule.smoldering.smolder,{[rule.smoldering.age_state]:newAge}));
			}
		}
		return block.setPermutation(block.permutation.withState(rule.smoldering.age_state,15));
	}
	if (age!=rule.smoldering.max) return;
	block.setType(rule.turns_into);
};*/

export function truffledDirt(block,dimension) {
	const offsets = [[-1,0,0],[1,0,0],[0,0,-1],[0,0,1],[0,-1,0]];
	const convertToTruffled = [
		"minecraft:dirt",
		"minecraft:dirt_with_roots",
		"minecraft:coarse_dirt",
		"minecraft:farmland",
		"minecraft:grass_block",
		"minecraft:grass_path",
		"minecraft:mycelium",
		"minecraft:podzol"
	];
	for (const [dx,dy,dz] of offsets) {
		const requiredLocation = {x:block.center().x+dx,y:block.center().y+dy,z:block.center().z+dz};
		const requiredBlocksLocation = dimension.getBlock(requiredLocation);
		if (!requiredBlocksLocation.hasTag("dirt")) return;
		if (block.typeId=="megaverse:truffled_dirt") return block.setType("megaverse:truffled_dirt_bud");
		else if (block.typeId=="megaverse:truffled_dirt_bud") {
			const extraOffsets = [[-1,0],[1,0],[0,-1],[0,1]];
			const randomIndex = mathUtilities.randomInteger(0,extraOffsets.length-1);
			const [edx,edz] = extraOffsets[randomIndex];
			const extraLocation = {x:block.center().x+edx,y:block.center().y,z:block.center().z+edz};
			const extraDirtBlock = block.dimension.getBlock(extraLocation);
			if (convertToTruffled.includes(extraDirtBlock.typeId)) extraDirtBlock.setType("megaverse:truffled_dirt_cluster");
			return block.setType("megaverse:truffled_dirt_cluster");
		}
		else return;
	}
};

export function truffledRoots(block,dimension) {
	const growth = block.permutation.getState("megaverse:growth");
	const treeAbove = block.dimension.getBlock(block.above(2));
	const allowedLogs = [
		"minecraft:acacia_log",
		"minecraft:birch_log",
		"minecraft:dark_oak_log",
		"minecraft:oak_log",
		"minecraft:spruce_log"
	];
	const convertToTruffled = [
		"minecraft:dirt",
		"minecraft:dirt_with_roots",
		"minecraft:coarse_dirt",
		"minecraft:farmland",
		"minecraft:grass_block",
		"minecraft:grass_path",
		"minecraft:mycelium",
		"minecraft:podzol"
	];
	if (block.isWaterlogged) return block.setType("minecraft:hanging_roots");
	const offsets = [[-1,0,0],[1,0,0],[0,0,-1],[0,0,1],[0,-1,0],[0,1,0]];
	for (const [dx,dy,dz] of offsets) {
		const requiredLocation = {
			x: block.center().x+dx,
			y: block.center().y+dy,
			z: block.center().z+dz
		};
		const requiredBlocksLocation = dimension.getBlock(requiredLocation);
		if (!requiredBlocksLocation.hasTag("dirt")||growth!=1||!allowedLogs.includes(treeAbove.typeId)) return;
		const dirtAbove = block.dimension.getBlock(block.above(1));
		if (convertToTruffled.includes(dirtAbove.typeId)) dirtAbove.setType("megaverse:truffled_dirt");
		return block.setType("megaverse:truffled_dirt");
	}
};

export function truffledRootsTick(block,dimension) {
	const growth = block.permutation.getState("megaverse:growth");
	const treeAbove = block.dimension.getBlock(block.above(2));
	const ageBit = treeAbove.permutation.getState("age_bit");
	const allowedSaplings = [
		"minecraft:acacia_sapling",
		"minecraft:birch_sapling",
		"minecraft:dark_oak_sapling",
		"minecraft:oak_sapling",
		"minecraft:spruce_sapling"
	];
	const convertToRooted = [
		"minecraft:dirt",
		"minecraft:dirt_with_roots",
		"minecraft:coarse_dirt",
		"minecraft:farmland",
		"minecraft:grass_block",
		"minecraft:grass_path",
		"minecraft:mycelium",
		"minecraft:podzol"
	];
	const offsets = [[-1,0,0],[1,0,0],[0,0,-1],[0,0,1],[0,-1,0],[0,1,0]];
	for (const [dx,dy,dz] of offsets) {
		const requiredLocation = {
			x: block.center().x+dx,
			y: block.center().y+dy,
			z: block.center().z+dz
		};
		const requiredBlocksLocation = dimension.getBlock(requiredLocation);
		if (!requiredBlocksLocation.hasTag("dirt")||!allowedSaplings.includes(treeAbove.typeId)) return;
		if (growth!=1&&ageBit==true) {
			const dirtAbove = block.dimension.getBlock(block.above(1));
			if (convertToRooted.includes(dirtAbove.typeId)) dirtAbove.setType("minecraft:dirt_with_roots");
			return block.setPermutation(block.permutation.withState("megaverse:growth",1));
		}
	}
};