{ lib, config, ... }: with lib; { options = { blocks = mkOption { type = types.attrsOf ( types.submodule { options = { displayName = mkOption { type = types.str; description = "The display name of the block."; }; properties = { ## Mining properties # .strength(float destroyTime, ?) hardness = mkOption { type = types.float; default = 1.0; description = "The block's destroy time (hardness)."; }; # .strength(?, float explosionResistance) resistance = mkOption { type = types.nullOr types.float; default = null; description = "The block's explosion resistance."; }; # requiresCorrectToolForDrops() requiresTool = mkOption { type = types.bool; default = false; description = "Whether the block requires the correct tool to drop."; }; ## Physical properties # noCollision() noCollision = mkOption { type = types.bool; default = false; description = "Whether the block has no collision."; }; # noOcclusion() noOcclusion = mkOption { type = types.bool; default = false; description = "Whether the block has no occlusion."; }; # dynamicShape() dynamicShape = mkOption { type = types.bool; default = false; description = "Whether the block has a dynamic shape."; }; # forceSolidOn() forceSolidOn = mkOption { type = types.bool; default = false; description = "Whether the block is forced to be solid on all sides."; }; # pushReaction(PushReaction) pushReaction = mkOption { type = types.enum [ "NORMAL" "DESTROY" "BLOCK" "IGNORE" "PUSH_ONLY" ]; default = "NORMAL"; description = "The block's reaction to being pushed by pistons."; }; # offsetType(BlockBehaviour.OffsetType) offsetType = mkOption { type = types.enum [ "NONE" "XYZ" "XZ" ]; default = "NONE"; description = "The block's offset type."; }; # replaceable() replaceable = mkOption { type = types.bool; default = false; description = "Whether the block is replaceable; e.g. like tall grass or snow layers."; }; ## Movement # friction(float) friction = mkOption { type = types.float; default = 0.6; description = "The block's friction."; }; # speedFactor(float) speedFactor = mkOption { type = types.float; default = 1.0; description = "The block's speed factor."; }; #jumpFactor(float) jumpFactor = mkOption { type = types.float; default = 1.0; description = "The block's jump factor."; }; ## Visual #mapColor(MapColor) & mapColor(DyeColor) & mapColor(closure) mapColor = mkOption { type = types.nullOr types.str; default = null; description = '' The block's map color. For dyecolor, use dye:, map:. To specify a closure, use closure:. For example, to reference the GetMapColor() method of a class, use closure:com.example.MyBlock::getMapColor. ''; }; #lightLevel(ToIntFunction) lightLevel = mkOption { type = types.nullOr (types.oneOf [ types.int types.str ]); default = null; description = '' The block's light level. Can be a constant integer (0-15), or a path method with (BlockState) -> Integer, e.g. closure:com.example.MyBlock::getLightLevel. ''; }; #noTerrainParticles() noTerrainParticles = mkOption { type = types.bool; default = false; description = "Whether the block has no terrain particles."; }; #isViewBlocking(BlockBehaviour.StatePredicate) isViewBlocking = mkOption { type = types.nullOr types.str; default = null; description = "Whether the block is view blocking. Provide a path to a BlockBehavior.StatePredicate method, e.g. closure:com.example.MyBlock::isViewBlocking."; }; #isSuffocating(BlockBehaviour.StatePredicate) isSuffocating = mkOption { type = types.nullOr types.str; default = null; description = "Whether the block is suffocating. Provide a path to a BlockBehavior.StatePredicate method, e.g. closure:com.example.MyBlock::isSuffocating."; }; ## Sound sounds = mkOption { type = types.str; default = "STONE"; description = "The name of the vanilla SoundType constant to use."; }; instruments = mkOption { type = types.nullOr types.str; default = null; description = "The name of the vanilla Instrument constant to use."; }; ## Loot noLootTable = mkOption { type = types.bool; default = false; description = "Whether the block has no loot table."; }; lootFrom = mkOption { type = types.nullOr types.str; default = null; description = "A Supplier that provides the loot table for this block. Provide a path to a method that returns a Block, e.g. closure:com.example.MyBlock::getLootTable."; }; ## Miscellaneous randomTicks = mkOption { type = types.bool; default = false; description = "Whether the block receives random ticks."; }; ignitesByLava = mkOption { type = types.bool; default = false; description = "Whether the block can be ignited by lava."; }; liquid = mkOption { type = types.bool; default = false; description = "Whether the block is a liquid."; }; isValidSpawn = mkOption { type = types.nullOr types.str; default = null; description = "BlockBehaviour.StateArgumentPredicate> that determines whether this block is a valid spawn point for the given entity type. Provide a path to a method that returns a boolean, e.g. closure:com.example.MyBlock::isValidSpawn."; }; air = mkOption { type = types.bool; default = false; description = "Whether the block is air-like"; }; requiredFeatures = mkOption { type = types.listOf types.str; default = [ ]; description = "A list of required features for this block to be available. Written as :."; }; }; customClass = mkOption { type = types.nullOr types.str; default = null; description = '' Path (relative to this mod.nix) to a hand-written Java file whose public class extends the generated "Base''${className}" block class. When unset, snowy generates one flat, concrete block class instead. ''; }; /* states = { "Integer:power" = { min = 0; max = 15; default = 0; }; "Boolean:lit" = { default = true; } "Enum:facing" = { enum = "net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING" } } */ states = mkOption { type = types.attrsOf { }; }; customModel = mkOption { type = types.bool; default = false; description = '' When true, snowy still generates this block's blockstates.json (pointing at ":block/" as usual), but expects a hand-written models/block/.json to already exist there instead of generating one from textures. Mutually exclusive with textures. ''; }; item = { enabled = mkOption { type = types.bool; default = true; description = "Whether to register a BlockItem for this block."; }; texture = mkOption { type = types.nullOr types.str; default = null; description = '' Flat 2D item icon (relative to textures/item/, no extension). When unset, the item renders the block's 3D model instead. Mutually exclusive with item.customModel. ''; }; customModel = mkOption { type = types.bool; default = false; description = '' Like the block-level customModel: expect a hand-written models/item/.json instead of generating one. Mutually exclusive with item.texture. ''; }; }; blockEntity = mkOption { type = types.nullOr ( types.submodule { options = { class = mkOption { type = types.str; description = '' Path (relative to this mod.nix) to a hand-written Java file whose public class extends the generated "Base''${className}Entity" block entity class. ''; }; ticker = { client = mkOption { type = types.bool; default = false; description = "Whether this block entity ticks on the client."; }; server = mkOption { type = types.bool; default = false; description = "Whether this block entity ticks on the server."; }; }; }; } ); default = null; description = "The block entity attached to this block, if any."; }; }; } ); default = { }; description = '' The blocks this mod registers, keyed by full registry name (":"). ''; }; }; }