package ru.dbotthepony.mc.otm.registry.game

import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import net.minecraft.core.Direction
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.util.valueproviders.UniformInt
import net.minecraft.world.item.DyeColor
import net.minecraft.world.level.block.AnvilBlock
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.DropExperienceBlock
import net.minecraft.world.level.block.IronBarsBlock
import net.minecraft.world.level.block.LiquidBlock
import net.minecraft.world.level.block.RedstoneLampBlock
import net.minecraft.world.level.block.RotatedPillarBlock
import net.minecraft.world.level.block.SlabBlock
import net.minecraft.world.level.block.SoundType
import net.minecraft.world.level.block.StairBlock
import net.minecraft.world.level.block.TransparentBlock
import net.minecraft.world.level.block.WallBlock
import net.minecraft.world.level.block.WaterloggedTransparentBlock
import net.minecraft.world.level.block.state.BlockBehaviour
import net.minecraft.world.level.block.state.properties.BlockStateProperties
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument
import net.minecraft.world.level.material.MapColor
import net.minecraft.world.level.material.PushReaction
import net.neoforged.bus.api.IEventBus
import net.neoforged.neoforge.capabilities.BlockCapability
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.capabilities.IBlockCapabilityProvider
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent
import ru.dbotthepony.mc.otm.block.BlackHoleBlock
import ru.dbotthepony.mc.otm.block.EnergyCableBlock
import ru.dbotthepony.mc.otm.block.MatterCableBlock
import ru.dbotthepony.mc.otm.block.MatteryBlock
import ru.dbotthepony.mc.otm.block.MultiblockTestBlock
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.StorageCableBlock
import ru.dbotthepony.mc.otm.block.addSimpleDescription
import ru.dbotthepony.mc.otm.block.decorative.DevChestBlock
import ru.dbotthepony.mc.otm.block.decorative.EngineBlock
import ru.dbotthepony.mc.otm.block.decorative.FluidTankBlock
import ru.dbotthepony.mc.otm.block.decorative.GrillBlock
import ru.dbotthepony.mc.otm.block.decorative.HoloSignBlock
import ru.dbotthepony.mc.otm.block.decorative.InfiniteWaterSourceBlock
import ru.dbotthepony.mc.otm.block.decorative.LaboratoryLamp
import ru.dbotthepony.mc.otm.block.decorative.LaboratoryLampLight
import ru.dbotthepony.mc.otm.block.decorative.PainterBlock
import ru.dbotthepony.mc.otm.block.decorative.TritaniumDoorBlock
import ru.dbotthepony.mc.otm.block.decorative.TritaniumTrapdoorBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.EnergyHatchBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.EnergyInterfaceBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.ItemHatchBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.MatterHatchBlockEntity
import ru.dbotthepony.mc.otm.block.matter.MatterBottlerBlock
import ru.dbotthepony.mc.otm.block.matter.MatterCapacitorBankBlock
import ru.dbotthepony.mc.otm.block.matter.MatterDecomposerBlock
import ru.dbotthepony.mc.otm.block.matter.MatterEntanglerBlock
import ru.dbotthepony.mc.otm.block.matter.MatterPanelBlock
import ru.dbotthepony.mc.otm.block.matter.MatterReconstructorBlock
import ru.dbotthepony.mc.otm.block.matter.MatterRecyclerBlock
import ru.dbotthepony.mc.otm.block.matter.MatterReplicatorBlock
import ru.dbotthepony.mc.otm.block.matter.MatterScannerBlock
import ru.dbotthepony.mc.otm.block.matter.PatternStorageBlock
import ru.dbotthepony.mc.otm.block.tech.HatchBlock
import ru.dbotthepony.mc.otm.block.storage.DriveRackBlock
import ru.dbotthepony.mc.otm.block.storage.DriveViewerBlock
import ru.dbotthepony.mc.otm.block.storage.ItemMonitorBlock
import ru.dbotthepony.mc.otm.block.storage.StorageBusBlock
import ru.dbotthepony.mc.otm.block.storage.StorageExporterBlock
import ru.dbotthepony.mc.otm.block.storage.StorageImporterBlock
import ru.dbotthepony.mc.otm.block.storage.StoragePowerSupplierBlock
import ru.dbotthepony.mc.otm.block.tech.AndroidChargerBlock
import ru.dbotthepony.mc.otm.block.tech.AndroidStationBlock
import ru.dbotthepony.mc.otm.block.tech.BatteryBankBlock
import ru.dbotthepony.mc.otm.block.tech.BlackHoleGeneratorBlock
import ru.dbotthepony.mc.otm.block.tech.BlockGravitationStabilizer
import ru.dbotthepony.mc.otm.block.tech.BlockGravitationStabilizerLens
import ru.dbotthepony.mc.otm.block.tech.ChemicalGeneratorBlock
import ru.dbotthepony.mc.otm.block.tech.CobblerBlock
import ru.dbotthepony.mc.otm.block.tech.EnergyCounterBlock
import ru.dbotthepony.mc.otm.block.tech.EnergyServoBlock
import ru.dbotthepony.mc.otm.block.tech.EssenceStorageBlock
import ru.dbotthepony.mc.otm.block.tech.FlywheelBatteryBlock
import ru.dbotthepony.mc.otm.block.tech.PhantomAttractorBlock
import ru.dbotthepony.mc.otm.block.tech.PlatePressBlock
import ru.dbotthepony.mc.otm.block.tech.PoweredBlastFurnaceBlock
import ru.dbotthepony.mc.otm.block.tech.PoweredFurnaceBlock
import ru.dbotthepony.mc.otm.block.tech.PoweredSmokerBlock
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.config.CablesConfig
import ru.dbotthepony.mc.otm.core.collect.SupplierList
import ru.dbotthepony.mc.otm.core.collect.SupplierMap
import ru.dbotthepony.mc.otm.core.get
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.registry.MRegistry
import java.util.Collections
import java.util.EnumMap
import java.util.HashMap
import java.util.LinkedHashMap
import java.util.function.Supplier

object MBlocks {
	private val registry = MDeferredRegister(BuiltInRegistries.BLOCK)

	private val knownCaps = ObjectOpenHashSet<BlockCapability<*, *>>()

	fun ensureCapabilityIsKnown(cap: BlockCapability<*, *>) {
		check(cap in knownCaps) { "Tried to expose capability which wasn't known on mod startup. This is unfortunately limitation with new capability system and can not be fixed, unless NeoForge team decides to rethink their decision to remove per block(entity) dynamic capabilities." }
	}

	private fun registerCapabilities(event: RegisterCapabilitiesEvent) {
		// static initializers
		MatteryCapability.BLOCK_ENERGY
		Capabilities.FluidHandler.BLOCK
		Capabilities.EnergyStorage.BLOCK
		Capabilities.ItemHandler.BLOCK

		// ugly
		for (cap in BlockCapability.getAll()) {
			knownCaps.add(cap)

			val provider = IBlockCapabilityProvider<Any?, Direction?> { level, pos, state, be, context: Direction? ->
				if (be is MatteryBlockEntity) {
					return@IBlockCapabilityProvider be.getCapability(cap as BlockCapability<Any, Direction?>, context)
				}

				return@IBlockCapabilityProvider null
			}

			for (block in registry.entries.values) {
				event.registerBlock(cap as BlockCapability<Any, Direction?>, provider, block.value)
			}
		}
	}

	fun register(bus: IEventBus) {
		registry.register(bus)
		bus.addListener(MBlocks::registerCapabilities)
	}

	val ANDROID_STATION = registry.coloredWithBase(MNames.ANDROID_STATION, ::AndroidStationBlock)
	val ANDROID_CHARGER = registry.coloredWithBase(MNames.ANDROID_CHARGER, ::AndroidChargerBlock)
	val BATTERY_BANK = registry.coloredWithBase(MNames.BATTERY_BANK, ::BatteryBankBlock)
	val MATTER_DECOMPOSER = registry.coloredWithBase(MNames.MATTER_DECOMPOSER, ::MatterDecomposerBlock)
	val MATTER_CAPACITOR_BANK = registry.coloredWithBase(MNames.MATTER_CAPACITOR_BANK, ::MatterCapacitorBankBlock)
	val MATTER_CABLE by registry.register(MNames.MATTER_CABLE, ::MatterCableBlock)
	val PATTERN_STORAGE by registry.register(MNames.PATTERN_STORAGE, ::PatternStorageBlock)
	val MATTER_SCANNER = registry.coloredWithBase(MNames.MATTER_SCANNER, ::MatterScannerBlock)
	val MATTER_PANEL = registry.coloredWithBase(MNames.MATTER_PANEL, ::MatterPanelBlock)
	val MATTER_REPLICATOR = registry.coloredWithBase(MNames.MATTER_REPLICATOR, ::MatterReplicatorBlock)
	val MATTER_BOTTLER = registry.coloredWithBase(MNames.MATTER_BOTTLER, ::MatterBottlerBlock)
	val ENERGY_COUNTER = registry.coloredWithBase(MNames.ENERGY_COUNTER, ::EnergyCounterBlock)
	val CHEMICAL_GENERATOR = registry.coloredWithBase(MNames.CHEMICAL_GENERATOR, ::ChemicalGeneratorBlock)
	val PLATE_PRESS = registry.coloredWithBase(MNames.PLATE_PRESS, ::PlatePressBlock)
	val TWIN_PLATE_PRESS = registry.coloredWithBase(MNames.TWIN_PLATE_PRESS) { color -> PlatePressBlock(color, isTwin = true) }
	val POWERED_FURNACE = registry.coloredWithBase(MNames.POWERED_FURNACE, ::PoweredFurnaceBlock)
	val POWERED_BLAST_FURNACE = registry.coloredWithBase(MNames.POWERED_BLAST_FURNACE, ::PoweredBlastFurnaceBlock)
	val POWERED_SMOKER = registry.coloredWithBase(MNames.POWERED_SMOKER, ::PoweredSmokerBlock)
	val MATTER_RECYCLER = registry.coloredWithBase(MNames.MATTER_RECYCLER, ::MatterRecyclerBlock)
	val ENERGY_SERVO = registry.coloredWithBase(MNames.ENERGY_SERVO, ::EnergyServoBlock)
	val COBBLESTONE_GENERATOR = registry.coloredWithBase(MNames.COBBLESTONE_GENERATOR, ::CobblerBlock)
	val INFINITE_WATER_SOURCE by registry.register(MNames.INFINITE_WATER_SOURCE) { InfiniteWaterSourceBlock() }
	val ESSENCE_STORAGE = registry.coloredWithBase(MNames.ESSENCE_STORAGE, ::EssenceStorageBlock)
	val MATTER_RECONSTRUCTOR = registry.coloredWithBase(MNames.MATTER_RECONSTRUCTOR, ::MatterReconstructorBlock)
	val PAINTER by registry.register(MNames.PAINTER, ::PainterBlock)
	val MATTER_ENTANGLER: MatterEntanglerBlock by registry.register(MNames.MATTER_ENTANGLER) { MatterEntanglerBlock() }

	val ENERGY_CABLES: Map<CablesConfig.E, EnergyCableBlock> = SupplierMap(CablesConfig.E.entries.map { conf ->
		conf to registry.register("${conf.name.lowercase()}_energy_cable") { EnergyCableBlock { a, b -> MBlockEntities.ENERGY_CABLES[conf]!!.create(a, b)!! } }
	})

	val FLYWHEEL_BATTERY by registry.register(MNames.FLYWHEEL_BATTERY) { FlywheelBatteryBlock() }

	val FLYWHEEL_SHAFT   by registry.register(MNames.FLYWHEEL_SHAFT)   {
		MatteryBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).explosionResistance(40f).mapColor(MapColor.COLOR_GRAY).destroyTime(2f).requiresCorrectToolForDrops())
			.addSimpleDescription()
	}

	val FLYWHEEL_HOUSING by registry.register(MNames.FLYWHEEL_HOUSING) {
		MatteryBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).explosionResistance(30f).mapColor(MapColor.COLOR_GRAY).destroyTime(2f).requiresCorrectToolForDrops())

			.addSimpleDescription()
	}

	val FLYWHEEL_BEARING by registry.register(MNames.FLYWHEEL_BEARING) {
		MatteryBlock(BlockBehaviour.Properties.of().sound(SoundType.NETHERITE_BLOCK).explosionResistance(40f).mapColor(MapColor.COLOR_GRAY).destroyTime(2f).requiresCorrectToolForDrops())
			.addSimpleDescription()
	}

	val GENERATOR_BLOCK by registry.register(MNames.GENERATOR_BLOCK) {
		MatteryBlock(BlockBehaviour.Properties.of().sound(SoundType.NETHERITE_BLOCK).explosionResistance(30f).mapColor(MapColor.COLOR_GRAY).destroyTime(2.5f).requiresCorrectToolForDrops())
			.addSimpleDescription()
	}
	val MODULAR_FRAME by registry.register(MNames.MODULAR_FRAME) { TransparentBlock(
		BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GRAY).noOcclusion().sound(SoundType.METAL).requiresCorrectToolForDrops().explosionResistance(30f).destroyTime(2f)
	)}
	val HEAVY_MODULAR_FRAME by registry.register(MNames.HEAVY_MODULAR_FRAME) { TransparentBlock(
		BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GRAY).noOcclusion().sound(SoundType.NETHERITE_BLOCK).requiresCorrectToolForDrops().explosionResistance(60f).destroyTime(2.5f)
	)}

	val STORAGE_BUS: Block by registry.register(MNames.STORAGE_BUS, ::StorageBusBlock)
	val STORAGE_IMPORTER: Block by registry.register(MNames.STORAGE_IMPORTER, ::StorageImporterBlock)
	val STORAGE_EXPORTER: Block by registry.register(MNames.STORAGE_EXPORTER, ::StorageExporterBlock)

	val DRIVE_VIEWER = registry.coloredWithBase(MNames.DRIVE_VIEWER, ::DriveViewerBlock)
	val DRIVE_RACK: Block by registry.register(MNames.DRIVE_RACK, ::DriveRackBlock)
	val ITEM_MONITOR = registry.coloredWithBase(MNames.ITEM_MONITOR, ::ItemMonitorBlock)
	val STORAGE_CABLE: Block by registry.register(MNames.STORAGE_CABLE, ::StorageCableBlock)
	val STORAGE_POWER_SUPPLIER = registry.coloredWithBase(MNames.STORAGE_POWER_SUPPLIER, ::StoragePowerSupplierBlock)

	val GRILL = registry.coloredWithBase(MNames.GRILL, ::GrillBlock)

	val BLACK_HOLE: Block by registry.register(MNames.BLACK_HOLE) { BlackHoleBlock() }
	val GRAVITATION_STABILIZER: Block by registry.register(MNames.GRAVITATION_STABILIZER) { BlockGravitationStabilizer() }
	val GRAVITATION_STABILIZER_LENS: Block by registry.register(MNames.GRAVITATION_STABILIZER_LENS) { BlockGravitationStabilizerLens() }

	val PHANTOM_ATTRACTOR: Block by registry.register(MNames.PHANTOM_ATTRACTOR) { PhantomAttractorBlock() }
	val FLUID_TANK: FluidTankBlock by registry.register(MNames.FLUID_TANK) { FluidTankBlock() }
	val DEV_CHEST: DevChestBlock by registry.register(MNames.DEV_CHEST) { DevChestBlock() }

	val BLACK_HOLE_GENERATOR by registry.register(MNames.BLACK_HOLE_GENERATOR) { BlackHoleGeneratorBlock() }
	val TRITANIUM_HULL by registry.register(MNames.TRITANIUM_HULL) {
		MatteryBlock(BlockBehaviour.Properties.of().sound(SoundType.VAULT).explosionResistance(80f).mapColor(MapColor.COLOR_LIGHT_BLUE).destroyTime(2.5f).requiresCorrectToolForDrops())
			.addSimpleDescription()
	}
	val MATTER_INJECTOR by registry.register(MNames.MATTER_INJECTOR) { RotatableMatteryBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.NETHERITE_BLOCK).requiresCorrectToolForDrops().destroyTime(2.5f).explosionResistance(160.0f)) }
	val ANTIMATTER_INJECTOR by registry.register(MNames.ANTIMATTER_INJECTOR) { RotatableMatteryBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.NETHERITE_BLOCK).requiresCorrectToolForDrops().destroyTime(2.5f).explosionResistance(160.0f)) }
	val HIGH_ENERGY_PARTICLE_COLLECTOR by registry.register(MNames.HIGH_ENERGY_PARTICLE_COLLECTOR) { RotatableMatteryBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.NETHERITE_BLOCK).requiresCorrectToolForDrops().destroyTime(2.5f).explosionResistance(160.0f)) }

	val ITEM_INPUT_HATCH by registry.register(MNames.ITEM_INPUT_HATCH) { HatchBlock(ItemHatchBlockEntity::input) }
	val ITEM_OUTPUT_HATCH by registry.register(MNames.ITEM_OUTPUT_HATCH) { HatchBlock(ItemHatchBlockEntity::output) }
	val ENERGY_INPUT_HATCH by registry.register(MNames.ENERGY_INPUT_HATCH) { HatchBlock(EnergyHatchBlockEntity::input, true) }
	val ENERGY_OUTPUT_HATCH by registry.register(MNames.ENERGY_OUTPUT_HATCH) { HatchBlock(EnergyHatchBlockEntity::output, true) }
	val MATTER_INPUT_HATCH by registry.register(MNames.MATTER_INPUT_HATCH) { HatchBlock(MatterHatchBlockEntity::input, true) }
	val MATTER_OUTPUT_HATCH by registry.register(MNames.MATTER_OUTPUT_HATCH) { HatchBlock(MatterHatchBlockEntity::output, true) }
	val ENERGY_INPUT_INTERFACE by registry.register(MNames.ENERGY_INPUT_INTERFACE) { HatchBlock(EnergyInterfaceBlockEntity::input, true) }
	val ENERGY_OUTPUT_INTERFACE by registry.register(MNames.ENERGY_OUTPUT_INTERFACE) { HatchBlock(EnergyInterfaceBlockEntity::output, true) }

	val LIQUID_XP: LiquidBlock by registry.register("liquid_xp") { LiquidBlock(MFluids.LIQUID_XP_FLOWING, BlockBehaviour.Properties.of().mapColor(MapColor.EMERALD).replaceable().noCollission().strength(100.0f).pushReaction(PushReaction.DESTROY).noLootTable().liquid().sound(SoundType.EMPTY)) }

	val TRITANIUM_ORE: Block by registry.register(MNames.TRITANIUM_ORE) { DropExperienceBlock(
		UniformInt.of(0, 3),
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.STONE)
			.strength(3f, 15.0f)
			.requiresCorrectToolForDrops(),
	) }

	val TRITANIUM_INGOT_BLOCK: Block by registry.register(MNames.TRITANIUM_INGOT_BLOCK) {
		Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).sound(SoundType.METAL).explosionResistance(400f).destroyTime(3f).requiresCorrectToolForDrops())
	}

	val WITHERED_STEEL_BLOCK: Block by registry.register(MNames.WITHERED_STEEL_BLOCK) {
		Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GREEN).sound(SoundType.NETHERITE_BLOCK).explosionResistance(400f).destroyTime(3f).requiresCorrectToolForDrops())
	}

	val ROFLITE_ALLOY_BLOCK: Block by registry.register(MNames.ROFLITE_ALLOY_BLOCK) {
		Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BROWN).sound(SoundType.NETHERITE_BLOCK).explosionResistance(400f).destroyTime(3f).requiresCorrectToolForDrops())
	}

	val METAL_JUNK: MatteryBlock by registry.register(MNames.METAL_JUNK) {
		 MatteryBlock(BlockBehaviour.Properties.of().sound(SoundType.NETHERITE_BLOCK).mapColor(MapColor.COLOR_GRAY).explosionResistance(45f).destroyTime(3f).requiresCorrectToolForDrops())
			 .addSimpleDescription()
	}

	val METAL_MESH: Block by registry.register(MNames.METAL_MESH) {
		WaterloggedTransparentBlock(BlockBehaviour.Properties.of()
				.mapColor(MapColor.COLOR_GRAY)
				.noOcclusion()
				.sound(SoundType.COPPER_GRATE)
				.explosionResistance(30f)
				.destroyTime(2f).requiresCorrectToolForDrops())
	}

	val TRITANIUM_BARS: IronBarsBlock by registry.register(MNames.TRITANIUM_BARS) {
		IronBarsBlock(BlockBehaviour.Properties.of()
					.mapColor(MapColor.COLOR_LIGHT_BLUE)
					.sound(SoundType.METAL)
					.explosionResistance(45f)
					.noOcclusion()
					.destroyTime(2.5f)
					.requiresCorrectToolForDrops())
	}

	val METAL_RAILING: IronBarsBlock by registry.register(MNames.METAL_RAILING) {
		IronBarsBlock(BlockBehaviour.Properties.of()
			.mapColor(MapColor.COLOR_GRAY)
			.sound(SoundType.COPPER_GRATE)
			.explosionResistance(30f)
			.noOcclusion()
			.destroyTime(2f)
			.requiresCorrectToolForDrops())
	}

	val DEEPSLATE_TRITANIUM_ORE: Block by registry.register(MNames.DEEPSLATE_TRITANIUM_ORE) { DropExperienceBlock(
		UniformInt.of(0, 3),
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.DEEPSLATE)
			.sound(SoundType.DEEPSLATE)
			.strength(4.75f, 6.5f)
			.requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE),
	) }

	val TRITANIUM_RAW_BLOCK: Block by registry.register(MNames.TRITANIUM_RAW_BLOCK) { Block(
		BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASEDRUM).strength(8.0f, 10f).requiresCorrectToolForDrops()
	) }

	val DILITHIUM_ORE: Block by registry.register("dilithium_ore") { DropExperienceBlock(
		UniformInt.of(1, 6),
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.STONE)
			.strength(3.5f, 25.0f)
			.requiresCorrectToolForDrops(),
	) }

	val DEEPSLATE_DILITHIUM_ORE: Block by registry.register("deepslate_dilithium_ore") { DropExperienceBlock(
		UniformInt.of(1, 6),
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.DEEPSLATE)
			.strength(4.5f, 25.0f)
			.requiresCorrectToolForDrops(),
	) }

	val DILITHIUM_CRYSTAL_BLOCK: Block by registry.register("dilithium_crystal_block") {
		Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).sound(SoundType.AMETHYST).explosionResistance(400f).destroyTime(3f).requiresCorrectToolForDrops())
	}

	val REDSTONE_LAMP_INVERTED by registry.register(MNames.REDSTONE_LAMP_INVERTED) { RedstoneLampBlock(
		BlockBehaviour.Properties.ofFullCopy(Blocks.REDSTONE_LAMP)
			.lightLevel { if (it[BlockStateProperties.LIT]) 0 else 15 }
	) }

	val REINFORCED_REDSTONE_LAMP by registry.register(MNames.REINFORCED_REDSTONE_LAMP) { RedstoneLampBlock(
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.COLOR_LIGHT_GRAY)
			.sound(SoundType.GLASS)
			.explosionResistance(40f)
			.destroyTime(1.5f)
			.requiresCorrectToolForDrops()
			.lightLevel { if (it[BlockStateProperties.LIT]) 15 else 0 }
			.isValidSpawn { p_61031_, p_61032_, p_61033_, p_61034_ -> true }
	) }

	val REINFORCED_REDSTONE_LAMP_INVERTED by registry.register(MNames.REINFORCED_REDSTONE_LAMP_INVERTED) { RedstoneLampBlock(
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.COLOR_LIGHT_GRAY)
			.sound(SoundType.GLASS)
			.explosionResistance(40f)
			.destroyTime(1.5f)
			.requiresCorrectToolForDrops()
			.lightLevel { if (it[BlockStateProperties.LIT]) 0 else 15 }
			.isValidSpawn { p_61031_, p_61032_, p_61033_, p_61034_ -> true }
	) }

	val LABORATORY_LAMP: Block by registry.register(MNames.LABORATORY_LAMP) { LaboratoryLamp(false) }
	val LABORATORY_LAMP_INVERTED: Block by registry.register(MNames.LABORATORY_LAMP_INVERTED) { LaboratoryLamp(true) }
	val LABORATORY_LAMP_LIGHT: Block by registry.register(MNames.LABORATORY_LAMP_LIGHT) { LaboratoryLampLight() }
	val DANGER_STRIPE_BLOCK: Block by registry.register(MNames.DANGER_STRIPE_BLOCK) { Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GRAY).explosionResistance(6f).destroyTime(1.5f).requiresCorrectToolForDrops()) }
	val METAL_BEAM: Block by registry.register(MNames.METAL_BEAM) { RotatedPillarBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GRAY).sound(SoundType.METAL).explosionResistance(14f).destroyTime(2.5f).requiresCorrectToolForDrops()) }
	val METAL_BEAM_CENTER: Block by registry.register(MNames.METAL_BEAM_CENTER) { RotatedPillarBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GRAY).sound(SoundType.METAL).explosionResistance(14f).destroyTime(2.5f).requiresCorrectToolForDrops()) }
	val ENGINE: Block by registry.register(MNames.ENGINE) { EngineBlock() }
	val HOLO_SIGN: Block by registry.register(MNames.HOLO_SIGN) { HoloSignBlock() }

	const val TRITANIUM_ANVIL_VARIANTS = 7

	val TRITANIUM_ANVIL: Map<DyeColor?, List<Block>>

	init {
		val map = LinkedHashMap<DyeColor?, List<Block>>()

		for (color in DyeColor.entries.toMutableList<DyeColor?>().also { it.add(0, null) }) {
			val anvils = ArrayList<Supplier<Block>>()

			for (i in 0 until TRITANIUM_ANVIL_VARIANTS) {
				val props = BlockBehaviour.Properties.of()
					.mapColor(color?.mapColor ?: MapColor.COLOR_LIGHT_BLUE)
					.sound(SoundType.ANVIL)
					.destroyTime(2.5f - i * 0.15f)
					.explosionResistance(1200f - i * 80f)
					.pushReaction(PushReaction.BLOCK)
					.requiresCorrectToolForDrops()

				var name = MNames.TRITANIUM_ANVIL + i

				if (color != null)
					name += "_${color.name.lowercase()}"

				anvils.add(registry.register(name) { AnvilBlock(props) })
			}

			map[color] = SupplierList(anvils)
		}

		TRITANIUM_ANVIL = Collections.unmodifiableMap(map)
	}

	val TRITANIUM_DOOR = registry.coloredWithBase(MNames.TRITANIUM_DOOR, ::TritaniumDoorBlock)

	val TRITANIUM_TRAPDOOR = registry.coloredWithBase(MNames.TRITANIUM_TRAPDOOR, ::TritaniumTrapdoorBlock)

	val TRITANIUM_STRIPED_BLOCK = registry.colored(MNames.TRITANIUM_STRIPED_BLOCK) { Block(
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.COLOR_LIGHT_BLUE)
			.sound(SoundType.DEEPSLATE)
			.requiresCorrectToolForDrops()
			.explosionResistance(80f)
			.destroyTime(2.5f)
	) }

	val TRITANIUM_STRIPED_STAIRS = registry.colored(MNames.TRITANIUM_STRIPED_STAIRS) { StairBlock(
		TRITANIUM_STRIPED_BLOCK[it]!!.defaultBlockState(),
		BlockBehaviour.Properties.ofLegacyCopy(TRITANIUM_STRIPED_BLOCK[it]!!)
	) }

	val TRITANIUM_STRIPED_SLAB = registry.colored(MNames.TRITANIUM_STRIPED_SLAB) {
		SlabBlock(BlockBehaviour.Properties.ofLegacyCopy(TRITANIUM_STRIPED_BLOCK[it]!!))
	}

	val TRITANIUM_STRIPED_WALL = registry.colored(MNames.TRITANIUM_STRIPED_WALL) {
		WallBlock(BlockBehaviour.Properties.ofLegacyCopy(TRITANIUM_STRIPED_BLOCK[it]!!))
	}

	val CARBON_FIBRE_BLOCK: Block by registry.register(MNames.CARBON_FIBRE_BLOCK) { Block(
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.COLOR_GRAY)
			.sound(SoundType.BASALT)
			.requiresCorrectToolForDrops()
			.explosionResistance(40f)
			.destroyTime(1.5f)
	) }

	val MULTIBLOCK_TEST by registry.register("multiblock_test") { MultiblockTestBlock() }

	init {
		MRegistry.registerBlocks(registry)
	}
}
