diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index 20369350..d861d1f1 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -2204,21 +2204,34 @@ Deprecated by `block_state(pos, name)` If used with a `block` argument only, it returns a map of block properties and their values. If a block has no properties, returns an empty map. -If `property` is specified, returns value of that property, or `null` if property is not applicable. +If `property` is specified, returns a string value of that property, or `null` if property is not applicable. Returned values or properties are always strings. It is expected from the user to know what to expect and convert values to numbers using `number()` function or booleans using `bool()` function. Returned string values can be directly used back in state definition in various applications where block properties are required. +`block_state` can also accept block names as input, returning block's default state. +
 set(x,y,z,'iron_trapdoor','half','top'); block_state(x,y,z)  => {waterlogged: false, half: top, open: false, ...}
 set(x,y,z,'iron_trapdoor','half','top'); block_state(x,y,z,'half')  => top
+block_state('iron_trapdoor','half')  => top
 set(x,y,z,'air'); block_state(x,y,z,'half')  => null
 block_state(block('iron_trapdoor[half=top]'),'half')  => top
 block_state(block('iron_trapdoor[half=top]'),'powered')  => false
 bool(block_state(block('iron_trapdoor[half=top]'),'powered'))  => 0
 
+### `block_list()`, `block_list(tag)` + +Returns list of all blocks. If tag is provided, returns list of blocks that belong to this block tag. + +### `block_tags()`, `block_tags(block)`, `block_tags(block, tag)` + +Without arguments, returns list of available tags, with block supplied (either by coordinates, or via block name), returns lost +of tags the block belongs to, and if a tag is specified, returns `null` if tag is invalid, `false` if this block doesn't belong +to this tag, and `true` if the block belongs to the tag. + ### `block_data(pos)` Return NBT string associated with specific location, or null if the block does not carry block data. Can be currently @@ -2460,9 +2473,12 @@ This function is tentative - will likely change when chunk ticket API is properl Scarpet provides convenient methods to access and modify information about structures as well as spawn in-game structures and features. List of available options and names that you can use depends mostly if you are using scarpet with minecraft 1.16.1 and below or 1.16.2 and above since in 1.16.2 Mojang has added JSON support for worldgen features -meaning that since 1.16.2 - they have official names that can be used by datapacks and scarpet +meaning that since 1.16.2 - they have official names that can be used by datapacks and scarpet. If you have most recent +scarpet on 1.16.4, you can use `plop()` to get all available worldgen features including custom features and structures +controlled by datapacks. It returns a map of lists in the following categories: +`'scarpet_custom'`, `'configured_features'`, `'structures'`, `'features'`, `'configured_structures'` -### Previous Structure Names, including variants (as of MC 1.16.3) +### Previous Structure Names, including variants (MC1.16.1 and below) * `'monument'`: Ocean Monument. Generates at fixed Y coordinate, surrounds itself with water. * `'fortress'`: Nether Fortress. Altitude varies, but its bounded by the code. * `'mansion'`: Woodland Mansion @@ -2492,7 +2508,7 @@ meaning that since 1.16.2 - they have official names that can be used by datapac * `'bastion_remnant_treasure'`: Treasure room version of a piglin bastion (1.16) * `'bastion_remnant_bridge'` : Bridge version of a piglin bastion (1.16) -### Feature Names (as of mc1.16.1) +### Feature Names (1.16.1 and below) * `'oak'` * `'oak_beehive'`: oak with a hive (1.15+). @@ -2556,13 +2572,17 @@ meaning that since 1.16.2 - they have official names that can be used by datapac * `'twisting_vines'` (1.16) * `'basalt_pillar'` (1.16) -### Standard Structures (as of 1.16.2+) +### Standard Structures (as of MC1.16.2+) + +Use `plop():'structures'`, but it always returns the following: `'bastion_remnant'`, `'buried_treasure'`, `'desert_pyramid'`, `'endcity'`, `'fortress'`, `'igloo'`, `'jungle_pyramid'`, `'mansion'`, `'mineshaft'`, `'monument'`, `'nether_fossil'`, `'ocean_ruin'`, `'pillager_outpost'`, `'ruined_portal'`, `'shipwreck'`, `'stronghold'`, `'swamp_hut'`, `'village'` -### Structure Variants (as of 1.16.2+) +### Structure Variants (as of MC1.16.2+) + +Use `plop():'configured_structures'`, but it always returns the following: `'bastion_remnant'`, `'buried_treasure'`, `'desert_pyramid'`, `'end_city'`, `'fortress'`, `'igloo'`, `'jungle_pyramid'`, `'mansion'`, `'mineshaft'`, `'mineshaft_mesa'`, `'monument'`, `'nether_fossil'`, @@ -2571,48 +2591,16 @@ meaning that since 1.16.2 - they have official names that can be used by datapac `'ruined_portal_swamp'`, `'shipwreck'`, `'shipwreck_beached'`, `'stronghold'`, `'swamp_hut'`, `'village_desert'`, `'village_plains'`, `'village_savanna'`, `'village_snovy'`, `'village_taiga'` -### World Generation Features (as of 1.16.2+) +### World Generation Features (as of MC1.16.2+) -`'acacia'`, `'amethyst_geode'` (1.17+), `'bamboo'`, `'bamboo_light'`, `'bamboo_vegetation'`, `'basalt_blobs'`, `'basalt_pillar'`, -`'birch'`, `'birch_bees_0002'`, `'birch_bees_002'`, `'birch_bees_005'`, `'birch_other'`, `'birch_tall'`, -`'blackstone_blobs'`, `'blue_ice'`, `'bonus_chest'`, `'brown_mushroom_giant'`, `'brown_mushroom_nether'`, -`'brown_mushroom_normal'`, `'brown_mushroom_swamp'`, `'brown_mushroom_taiga'`, `'chorus_plant'`, -`'crimson_forest_vegetation'`, `'crimson_fungi'`, `'crimson_fungi_planted'`, `'dark_forest_vegetation_brown'`, -`'dark_forest_vegetation_red'`, `'dark_oak'`, `'delta'`, `'desert_well'`, `'disk_clay'`, `'disk_gravel'`, -`'disk_sand'`, `'end_gateway'`, `'end_gateway_delayed'`, `'end_island'`, `'end_island_decorated'`, `'end_spike'`, -`'fancy_oak'`, `'fancy_oak_bees_0002'`, `'fancy_oak_bees_002'`, `'fancy_oak_bees_005'`, `'flower_default'`, -`'flower_forest'`, `'flower_plain'`, `'flower_plain_decorated'`, `'flower_swamp'`, `'flower_warm'`, -`'forest_flower_trees'`, `'forest_flower_vegetation'`, `'forest_flower_vegetation_common'`, `'forest_rock'`, -`'fossil'`, `'freeze_top_layer'`, `'glowstone'`, `'glowstone_extra'`, `'huge_brown_mushroom'`, -`'huge_red_mushroom'`, `'ice_patch'`, `'ice_spike'`, `'iceberg_blue'`, `'iceberg_packed'`, `'jungle_bush'`, -`'jungle_tree'`, `'jungle_tree_no_vine'`, `'kelp_cold'`, `'kelp_warm'`, `'lake_lava'`, `'lake_water'`, -`'large_basalt_columns'`, `'mega_jungle_tree'`, `'mega_pine'`, `'mega_spruce'`, `'monster_room'`, -`'mushroom_field_vegetation'`, `'nether_sprouts'`, `'nope'`, `'oak'`, `'oak_badlands'`, `'oak_bees_0002'`, -`'oak_bees_002'`, `'oak_bees_005'`, `'ore_andesite'`, `'ore_blackstone'`, `'ore_coal'`, `'ore_debris_large'`, -`'ore_debris_small'`, `'ore_diamond'`, `'ore_diorite'`, `'ore_dirt'`, `'ore_emerald'`, `'ore_gold'`, -`'ore_gold_deltas'`, `'ore_gold_extra'`, `'ore_gold_nether'`, `'ore_granite'`, `'ore_gravel'`, -`'ore_gravel_nether'`, `'ore_infested'`, `'ore_iron'`, `'ore_lapis'`, `'ore_magma'`, `'ore_quartz_deltas'`, -`'ore_quartz_nether'`, `'ore_redstone'`, `'ore_soul_sand'`, `'patch_berry_bush'`, `'patch_berry_decorated'`, -`'patch_berry_sparse'`, `'patch_brown_mushroom'`, `'patch_cactus'`, `'patch_cactus_decorated'`, -`'patch_cactus_desert'`, `'patch_crimson_roots'`, `'patch_dead_bush'`, `'patch_dead_bush_2'`, -`'patch_dead_bush_badlands'`, `'patch_fire'`, `'patch_grass_badlands'`, `'patch_grass_forest'`, -`'patch_grass_jungle'`, `'patch_grass_normal'`, `'patch_grass_plain'`, `'patch_grass_savanna'`, -`'patch_grass_taiga'`, `'patch_grass_taiga_2'`, `'patch_large_fern'`, `'patch_melon'`, `'patch_pumpkin'`, -`'patch_red_mushroom'`, `'patch_soul_fire'`, `'patch_sugar_cane'`, `'patch_sugar_cane_badlands'`, -`'patch_sugar_cane_desert'`, `'patch_sugar_cane_swamp'`, `'patch_sunflower'`, `'patch_taiga_grass'`, -`'patch_tall_grass'`, `'patch_tall_grass_2'`, `'patch_waterlilly'`, `'pile_hay'`, `'pile_ice'`, -`'pile_melon'`, `'pile_pumpkin'`, `'pile_snow'`, `'pine'`, `'plain_vegetation'`, `'red_mushroom_giant'`, -`'red_mushroom_nether'`, `'red_mushroom_normal'`, `'red_mushroom_swamp'`, `'red_mushroom_taiga'`, -`'sea_pickle'`, `'seagrass_cold'`, `'seagrass_deep'`, `'seagrass_deep_cold'`, `'seagrass_deep_warm'`, -`'seagrass_normal'`, `'seagrass_river'`, `'seagrass_simple'`, `'seagrass_swamp'`, `'seagrass_warm'`, -`'small_basalt_columns'`, `'spring_closed'`, `'spring_closed_double'`, `'spring_delta'`, `'spring_lava'`, -`'spring_lava_double'`, `'spring_open'`, `'spring_water'`, `'spruce'`, `'spruce_snovy'`, `'super_birch_bees_0002'`, -`'swamp_tree'`, `'taiga_vegetation'`, `'trees_giant'`, `'trees_giant_spruce'`, `'trees_jungle'`, -`'trees_jungle_edge'`, `'trees_mountain'`, `'trees_mountain_edge'`, `'trees_savanna'`, `'trees_shattered_savanna'`, -`'trees_water'`, `'twisting_vines'`, `'vines'`, `'void_start_platform'`, `'warm_ocean_vegetation'`, -`'warped_forest_vegetation'`, `'warped_fungi'`, `'warped_fungi_planted'`, `'weeping_vines'` +Use `plop():'features'` and `plop():'configured_features'` for a list of available options. Your output may vary based on +datapacks installed in your world. -### Custom Scarpet Features (1.16.2+) +### Custom Scarpet Features + +Use `plop():'scarpet_custom'` for a full list. + +These contain some popular features and structures that are impossible or difficult to obtain with vanilla structures/features. * `'bastion_remnant_bridge'` - Bridge version of a bastion remnant * `'bastion_remnant_hoglin_stable'` - Hoglin stables version of a bastion remnant @@ -2638,7 +2626,7 @@ making it preferred for scoping ungenerated terrain, but it takes some compute r Unlike `'structure'` this will return a tentative structure location. Random factors in world generation may prevent the actual structure from forming. -If structure is specified, it will return `null` if a chunk is not eligible, `true` if the structure should appear, or +If structure is specified, it will return `null` if a chunk is not eligible or invalid, `true` if the structure should appear, or a map with two values: `'box'` for a pair of coordinates indicating bounding box of the structure, and `'pieces'` for list of elements of the structure (as a tuple), with its name, direction, and box coordinates of the piece. @@ -2655,7 +2643,7 @@ the first case it returns a map of structures at a given position, keyed by stru the bounding box of the structure - a pair of two 3-value coords (see examples). When called with an extra structure name, returns a map with two values, `'box'` for bounding box of the structure, and `'pieces'` for a list of components for that structure, with their name, direction and two sets of coordinates -indicating the bounding box of the structure piece. +indicating the bounding box of the structure piece. If structure is invalid, its data will be `null`. Requires a `Standard Structure` name (see above). @@ -3950,6 +3938,10 @@ Triggered when a server receives a request to deploy elytra, regardless if the f ### `__on_player_wakes_up(player)` Player wakes up from the bed mid sleep, but not when it is kicked out of bed because it finished sleeping. +### `__on_player_escapes_sleep(player)` +Same as `player_wakes_up` but only triggered when pressing the ESC button. Not sure why Mojang decided to send that event +twice when pressing escape, but might be interesting to be able to detect that. + ### `__on_player_starts_sneaking(player)` ### `__on_player_stops_sneaking(player)` ### `__on_player_starts_sprinting(player)` @@ -4217,7 +4209,7 @@ Reads the `property` of the `team` if no `value` is specified. If a `value` is a * `color` * Type: String - * Options: See [team command](https://minecraft.gamepedia.com/Commands/team#Arguments) (same strings as `'teamcolor'` [command argument](https://github.com/gnembon/fabric-carpet/blob/master/docs/scarpet/Full.md#command-argument-types] options)) + * Options: See [team command](https://minecraft.gamepedia.com/Commands/team#Arguments) (same strings as `'teamcolor'` [command argument](https://github.com/gnembon/fabric-carpet/blob/master/docs/scarpet/Full.md#command-argument-types) options) * `displayName` * Type: String or FormattedText, when querying returns FormattedText diff --git a/docs/scarpet/api/BlocksAndWorldAccess.md b/docs/scarpet/api/BlocksAndWorldAccess.md index bf6ae4b2..196d60fb 100644 --- a/docs/scarpet/api/BlocksAndWorldAccess.md +++ b/docs/scarpet/api/BlocksAndWorldAccess.md @@ -248,21 +248,34 @@ Deprecated by `block_state(pos, name)` If used with a `block` argument only, it returns a map of block properties and their values. If a block has no properties, returns an empty map. -If `property` is specified, returns value of that property, or `null` if property is not applicable. +If `property` is specified, returns a string value of that property, or `null` if property is not applicable. Returned values or properties are always strings. It is expected from the user to know what to expect and convert values to numbers using `number()` function or booleans using `bool()` function. Returned string values can be directly used back in state definition in various applications where block properties are required. +`block_state` can also accept block names as input, returning block's default state. +
 set(x,y,z,'iron_trapdoor','half','top'); block_state(x,y,z)  => {waterlogged: false, half: top, open: false, ...}
 set(x,y,z,'iron_trapdoor','half','top'); block_state(x,y,z,'half')  => top
+block_state('iron_trapdoor','half')  => top
 set(x,y,z,'air'); block_state(x,y,z,'half')  => null
 block_state(block('iron_trapdoor[half=top]'),'half')  => top
 block_state(block('iron_trapdoor[half=top]'),'powered')  => false
 bool(block_state(block('iron_trapdoor[half=top]'),'powered'))  => 0
 
+### `block_list()`, `block_list(tag)` + +Returns list of all blocks. If tag is provided, returns list of blocks that belong to this block tag. + +### `block_tags()`, `block_tags(block)`, `block_tags(block, tag)` + +Without arguments, returns list of available tags, with block supplied (either by coordinates, or via block name), returns lost +of tags the block belongs to, and if a tag is specified, returns `null` if tag is invalid, `false` if this block doesn't belong +to this tag, and `true` if the block belongs to the tag. + ### `block_data(pos)` Return NBT string associated with specific location, or null if the block does not carry block data. Can be currently @@ -512,9 +525,12 @@ This function is tentative - will likely change when chunk ticket API is properl Scarpet provides convenient methods to access and modify information about structures as well as spawn in-game structures and features. List of available options and names that you can use depends mostly if you are using scarpet with minecraft 1.16.1 and below or 1.16.2 and above since in 1.16.2 Mojang has added JSON support for worldgen features -meaning that since 1.16.2 - they have official names that can be used by datapacks and scarpet +meaning that since 1.16.2 - they have official names that can be used by datapacks and scarpet. If you have most recent +scarpet on 1.16.4, you can use `plop()` to get all available worldgen features including custom features and structures +controlled by datapacks. It returns a map of lists in the following categories: +`'scarpet_custom'`, `'configured_features'`, `'structures'`, `'features'`, `'configured_structures'` -### Previous Structure Names, including variants (as of MC 1.16.3) +### Previous Structure Names, including variants (MC1.16.1 and below) * `'monument'`: Ocean Monument. Generates at fixed Y coordinate, surrounds itself with water. * `'fortress'`: Nether Fortress. Altitude varies, but its bounded by the code. * `'mansion'`: Woodland Mansion @@ -544,7 +560,7 @@ meaning that since 1.16.2 - they have official names that can be used by datapac * `'bastion_remnant_treasure'`: Treasure room version of a piglin bastion (1.16) * `'bastion_remnant_bridge'` : Bridge version of a piglin bastion (1.16) -### Feature Names (as of mc1.16.1) +### Feature Names (1.16.1 and below) * `'oak'` * `'oak_beehive'`: oak with a hive (1.15+). @@ -608,13 +624,17 @@ meaning that since 1.16.2 - they have official names that can be used by datapac * `'twisting_vines'` (1.16) * `'basalt_pillar'` (1.16) -### Standard Structures (as of 1.16.2+) +### Standard Structures (as of MC1.16.2+) + +Use `plop():'structures'`, but it always returns the following: `'bastion_remnant'`, `'buried_treasure'`, `'desert_pyramid'`, `'endcity'`, `'fortress'`, `'igloo'`, `'jungle_pyramid'`, `'mansion'`, `'mineshaft'`, `'monument'`, `'nether_fossil'`, `'ocean_ruin'`, `'pillager_outpost'`, `'ruined_portal'`, `'shipwreck'`, `'stronghold'`, `'swamp_hut'`, `'village'` -### Structure Variants (as of 1.16.2+) +### Structure Variants (as of MC1.16.2+) + +Use `plop():'configured_structures'`, but it always returns the following: `'bastion_remnant'`, `'buried_treasure'`, `'desert_pyramid'`, `'end_city'`, `'fortress'`, `'igloo'`, `'jungle_pyramid'`, `'mansion'`, `'mineshaft'`, `'mineshaft_mesa'`, `'monument'`, `'nether_fossil'`, @@ -623,48 +643,16 @@ meaning that since 1.16.2 - they have official names that can be used by datapac `'ruined_portal_swamp'`, `'shipwreck'`, `'shipwreck_beached'`, `'stronghold'`, `'swamp_hut'`, `'village_desert'`, `'village_plains'`, `'village_savanna'`, `'village_snovy'`, `'village_taiga'` -### World Generation Features (as of 1.16.2+) +### World Generation Features (as of MC1.16.2+) -`'acacia'`, `'amethyst_geode'` (1.17+), `'bamboo'`, `'bamboo_light'`, `'bamboo_vegetation'`, `'basalt_blobs'`, `'basalt_pillar'`, -`'birch'`, `'birch_bees_0002'`, `'birch_bees_002'`, `'birch_bees_005'`, `'birch_other'`, `'birch_tall'`, -`'blackstone_blobs'`, `'blue_ice'`, `'bonus_chest'`, `'brown_mushroom_giant'`, `'brown_mushroom_nether'`, -`'brown_mushroom_normal'`, `'brown_mushroom_swamp'`, `'brown_mushroom_taiga'`, `'chorus_plant'`, -`'crimson_forest_vegetation'`, `'crimson_fungi'`, `'crimson_fungi_planted'`, `'dark_forest_vegetation_brown'`, -`'dark_forest_vegetation_red'`, `'dark_oak'`, `'delta'`, `'desert_well'`, `'disk_clay'`, `'disk_gravel'`, -`'disk_sand'`, `'end_gateway'`, `'end_gateway_delayed'`, `'end_island'`, `'end_island_decorated'`, `'end_spike'`, -`'fancy_oak'`, `'fancy_oak_bees_0002'`, `'fancy_oak_bees_002'`, `'fancy_oak_bees_005'`, `'flower_default'`, -`'flower_forest'`, `'flower_plain'`, `'flower_plain_decorated'`, `'flower_swamp'`, `'flower_warm'`, -`'forest_flower_trees'`, `'forest_flower_vegetation'`, `'forest_flower_vegetation_common'`, `'forest_rock'`, -`'fossil'`, `'freeze_top_layer'`, `'glowstone'`, `'glowstone_extra'`, `'huge_brown_mushroom'`, -`'huge_red_mushroom'`, `'ice_patch'`, `'ice_spike'`, `'iceberg_blue'`, `'iceberg_packed'`, `'jungle_bush'`, -`'jungle_tree'`, `'jungle_tree_no_vine'`, `'kelp_cold'`, `'kelp_warm'`, `'lake_lava'`, `'lake_water'`, -`'large_basalt_columns'`, `'mega_jungle_tree'`, `'mega_pine'`, `'mega_spruce'`, `'monster_room'`, -`'mushroom_field_vegetation'`, `'nether_sprouts'`, `'nope'`, `'oak'`, `'oak_badlands'`, `'oak_bees_0002'`, -`'oak_bees_002'`, `'oak_bees_005'`, `'ore_andesite'`, `'ore_blackstone'`, `'ore_coal'`, `'ore_debris_large'`, -`'ore_debris_small'`, `'ore_diamond'`, `'ore_diorite'`, `'ore_dirt'`, `'ore_emerald'`, `'ore_gold'`, -`'ore_gold_deltas'`, `'ore_gold_extra'`, `'ore_gold_nether'`, `'ore_granite'`, `'ore_gravel'`, -`'ore_gravel_nether'`, `'ore_infested'`, `'ore_iron'`, `'ore_lapis'`, `'ore_magma'`, `'ore_quartz_deltas'`, -`'ore_quartz_nether'`, `'ore_redstone'`, `'ore_soul_sand'`, `'patch_berry_bush'`, `'patch_berry_decorated'`, -`'patch_berry_sparse'`, `'patch_brown_mushroom'`, `'patch_cactus'`, `'patch_cactus_decorated'`, -`'patch_cactus_desert'`, `'patch_crimson_roots'`, `'patch_dead_bush'`, `'patch_dead_bush_2'`, -`'patch_dead_bush_badlands'`, `'patch_fire'`, `'patch_grass_badlands'`, `'patch_grass_forest'`, -`'patch_grass_jungle'`, `'patch_grass_normal'`, `'patch_grass_plain'`, `'patch_grass_savanna'`, -`'patch_grass_taiga'`, `'patch_grass_taiga_2'`, `'patch_large_fern'`, `'patch_melon'`, `'patch_pumpkin'`, -`'patch_red_mushroom'`, `'patch_soul_fire'`, `'patch_sugar_cane'`, `'patch_sugar_cane_badlands'`, -`'patch_sugar_cane_desert'`, `'patch_sugar_cane_swamp'`, `'patch_sunflower'`, `'patch_taiga_grass'`, -`'patch_tall_grass'`, `'patch_tall_grass_2'`, `'patch_waterlilly'`, `'pile_hay'`, `'pile_ice'`, -`'pile_melon'`, `'pile_pumpkin'`, `'pile_snow'`, `'pine'`, `'plain_vegetation'`, `'red_mushroom_giant'`, -`'red_mushroom_nether'`, `'red_mushroom_normal'`, `'red_mushroom_swamp'`, `'red_mushroom_taiga'`, -`'sea_pickle'`, `'seagrass_cold'`, `'seagrass_deep'`, `'seagrass_deep_cold'`, `'seagrass_deep_warm'`, -`'seagrass_normal'`, `'seagrass_river'`, `'seagrass_simple'`, `'seagrass_swamp'`, `'seagrass_warm'`, -`'small_basalt_columns'`, `'spring_closed'`, `'spring_closed_double'`, `'spring_delta'`, `'spring_lava'`, -`'spring_lava_double'`, `'spring_open'`, `'spring_water'`, `'spruce'`, `'spruce_snovy'`, `'super_birch_bees_0002'`, -`'swamp_tree'`, `'taiga_vegetation'`, `'trees_giant'`, `'trees_giant_spruce'`, `'trees_jungle'`, -`'trees_jungle_edge'`, `'trees_mountain'`, `'trees_mountain_edge'`, `'trees_savanna'`, `'trees_shattered_savanna'`, -`'trees_water'`, `'twisting_vines'`, `'vines'`, `'void_start_platform'`, `'warm_ocean_vegetation'`, -`'warped_forest_vegetation'`, `'warped_fungi'`, `'warped_fungi_planted'`, `'weeping_vines'` +Use `plop():'features'` and `plop():'configured_features'` for a list of available options. Your output may vary based on +datapacks installed in your world. -### Custom Scarpet Features (1.16.2+) +### Custom Scarpet Features + +Use `plop():'scarpet_custom'` for a full list. + +These contain some popular features and structures that are impossible or difficult to obtain with vanilla structures/features. * `'bastion_remnant_bridge'` - Bridge version of a bastion remnant * `'bastion_remnant_hoglin_stable'` - Hoglin stables version of a bastion remnant @@ -690,7 +678,7 @@ making it preferred for scoping ungenerated terrain, but it takes some compute r Unlike `'structure'` this will return a tentative structure location. Random factors in world generation may prevent the actual structure from forming. -If structure is specified, it will return `null` if a chunk is not eligible, `true` if the structure should appear, or +If structure is specified, it will return `null` if a chunk is not eligible or invalid, `true` if the structure should appear, or a map with two values: `'box'` for a pair of coordinates indicating bounding box of the structure, and `'pieces'` for list of elements of the structure (as a tuple), with its name, direction, and box coordinates of the piece. @@ -707,7 +695,7 @@ the first case it returns a map of structures at a given position, keyed by stru the bounding box of the structure - a pair of two 3-value coords (see examples). When called with an extra structure name, returns a map with two values, `'box'` for bounding box of the structure, and `'pieces'` for a list of components for that structure, with their name, direction and two sets of coordinates -indicating the bounding box of the structure piece. +indicating the bounding box of the structure piece. If structure is invalid, its data will be `null`. Requires a `Standard Structure` name (see above). diff --git a/docs/scarpet/api/Events.md b/docs/scarpet/api/Events.md index 6367e3c2..2f343835 100644 --- a/docs/scarpet/api/Events.md +++ b/docs/scarpet/api/Events.md @@ -170,6 +170,10 @@ Triggered when a server receives a request to deploy elytra, regardless if the f ### `__on_player_wakes_up(player)` Player wakes up from the bed mid sleep, but not when it is kicked out of bed because it finished sleeping. +### `__on_player_escapes_sleep(player)` +Same as `player_wakes_up` but only triggered when pressing the ESC button. Not sure why Mojang decided to send that event +twice when pressing escape, but might be interesting to be able to detect that. + ### `__on_player_starts_sneaking(player)` ### `__on_player_stops_sneaking(player)` ### `__on_player_starts_sprinting(player)` diff --git a/docs/scarpet/api/Scoreboard.md b/docs/scarpet/api/Scoreboard.md index 0be72203..98e9c9b7 100644 --- a/docs/scarpet/api/Scoreboard.md +++ b/docs/scarpet/api/Scoreboard.md @@ -69,7 +69,7 @@ Reads the `property` of the `team` if no `value` is specified. If a `value` is a * `color` * Type: String - * Options: See [team command](https://minecraft.gamepedia.com/Commands/team#Arguments) (same strings as `'teamcolor'` [command argument](https://github.com/gnembon/fabric-carpet/blob/master/docs/scarpet/Full.md#command-argument-types] options)) + * Options: See [team command](https://minecraft.gamepedia.com/Commands/team#Arguments) (same strings as `'teamcolor'` [command argument](https://github.com/gnembon/fabric-carpet/blob/master/docs/scarpet/Full.md#command-argument-types) options) * `displayName` * Type: String or FormattedText, when querying returns FormattedText diff --git a/docs/scarpet/resources/editors/idea/2.txt b/docs/scarpet/resources/editors/idea/2.txt index db4d0d7b..ae16592b 100644 --- a/docs/scarpet/resources/editors/idea/2.txt +++ b/docs/scarpet/resources/editors/idea/2.txt @@ -5,9 +5,11 @@ blast_resistance block block_data block_light +block_list block_sound block_state block_tick +block_tags blocks_daylight blocks_movement brightness diff --git a/docs/scarpet/resources/editors/idea/4.txt b/docs/scarpet/resources/editors/idea/4.txt index e9ac7ae1..a7065d6d 100644 --- a/docs/scarpet/resources/editors/idea/4.txt +++ b/docs/scarpet/resources/editors/idea/4.txt @@ -27,7 +27,8 @@ __on_player_stops_sprinting(player) -> __on_player_switches_slot(player, from, to) -> __on_player_swaps_hands(player) -> __on_player_uses_item(player, item_tuple, hand) -> -__on_player_wakes_up(player) -> +__on_player_wakes_up(player) -> +__on_player_escapes_sleep(player) -> __on_statistic(player, category, event, value) -> __on_tick() -> __on_tick_ender() -> diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml index 3ad710dc..92da9036 100644 --- a/docs/scarpet/resources/editors/npp/scarpet.xml +++ b/docs/scarpet/resources/editors/npp/scarpet.xml @@ -53,7 +53,7 @@ transparent opacity blocks_daylight emitted_light light block_light sky_light see_sky brightness hardness blast_resistance top loaded suffocates power ticks_randomly update block_tick random_tick in_slime_chunk set without_updates - blocks_movement block_sound material map_colour block_state block_data poi set_poi + blocks_movement block_sound material map_colour block_state block_list block_tags block_data poi set_poi place_item set_biome biome loaded_status generation_status inhabited_time spawn_potential chunk_tickets structure_eligibility structures structure_references set_structure reset_chunk reload_chunk custom_dimension add_chunk_ticket @@ -115,6 +115,7 @@ __on_player_swaps_hands __on_player_uses_item __on_player_wakes_up + __on_player_escapes_sleep __on_statistic __on_tick __on_tick_ender diff --git a/src/main/java/carpet/helpers/FeatureGenerator.java b/src/main/java/carpet/helpers/FeatureGenerator.java index 6c9b6a7d..aa497e30 100644 --- a/src/main/java/carpet/helpers/FeatureGenerator.java +++ b/src/main/java/carpet/helpers/FeatureGenerator.java @@ -49,7 +49,7 @@ public class FeatureGenerator return custom.plop(world, pos); } Identifier id = new Identifier(featureName); - ConfiguredStructureFeature structureFeature = BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE.get(id); + ConfiguredStructureFeature structureFeature = world.getRegistryManager().get(Registry.CONFIGURED_STRUCTURE_FEATURE_WORLDGEN).get(id); if (structureFeature != null) { return ((StructureFeatureInterface)structureFeature.feature).plopAnywhere( @@ -58,7 +58,7 @@ public class FeatureGenerator } - ConfiguredFeature feature = BuiltinRegistries.CONFIGURED_FEATURE.get(id); + ConfiguredFeature feature = world.getRegistryManager().get(Registry.CONFIGURED_FEATURE_WORLDGEN).get(id); if (feature != null) { CarpetSettings.skipGenerationChecks = true; @@ -77,7 +77,7 @@ public class FeatureGenerator public static ConfiguredStructureFeature resolveConfiguredStructure(String name, ServerWorld world, BlockPos pos) { Identifier id = new Identifier(name); - ConfiguredStructureFeature configuredStructureFeature = BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE.get(id); + ConfiguredStructureFeature configuredStructureFeature = world.getRegistryManager().get(Registry.CONFIGURED_STRUCTURE_FEATURE_WORLDGEN).get(id); if (configuredStructureFeature != null) return configuredStructureFeature; StructureFeature structureFeature = Registry.STRUCTURE_FEATURE.get(id); if (structureFeature == null) return null; @@ -137,7 +137,7 @@ public class FeatureGenerator { ConfiguredStructureFeature configuredFeature = world.getBiome(pos).getGenerationSettings().method_30978(structure.configure(null)); if (configuredFeature.config != null || !tryHard) return configuredFeature; - return BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE.getEntries().stream(). + return world.getRegistryManager().get(Registry.CONFIGURED_STRUCTURE_FEATURE_WORLDGEN).getEntries().stream(). filter(cS -> cS.getValue().feature == structure). findFirst().map(Map.Entry::getValue).orElse(null); } @@ -168,7 +168,7 @@ public class FeatureGenerator return null; } - private static final Map featureMap = new HashMap() {{ + public static final Map featureMap = new HashMap() {{ put("oak_bees", simpleTree(ConfiguredFeatures.OAK.getConfig().setTreeDecorators(ImmutableList.of(new BeehiveTreeDecorator(1.0F))))); put("fancy_oak_bees", simpleTree(ConfiguredFeatures.FANCY_OAK.getConfig().setTreeDecorators(ImmutableList.of(new BeehiveTreeDecorator(1.0F))))); put("birch_bees", simpleTree(ConfiguredFeatures.BIRCH.getConfig().setTreeDecorators(ImmutableList.of(new BeehiveTreeDecorator(1.0F))))); diff --git a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java index 6c806a99..943ff8bf 100644 --- a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java +++ b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java @@ -1,5 +1,6 @@ package carpet.mixins; +import carpet.CarpetSettings; import net.minecraft.item.ItemStack; import net.minecraft.network.packet.c2s.play.ButtonClickC2SPacket; import net.minecraft.network.packet.c2s.play.CraftRequestC2SPacket; @@ -27,6 +28,7 @@ import static carpet.script.CarpetEventServer.Event.PLAYER_CLICKS_BLOCK; import static carpet.script.CarpetEventServer.Event.PLAYER_DEPLOYS_ELYTRA; import static carpet.script.CarpetEventServer.Event.PLAYER_DROPS_ITEM; import static carpet.script.CarpetEventServer.Event.PLAYER_DROPS_STACK; +import static carpet.script.CarpetEventServer.Event.PLAYER_ESCAPES_SLEEP; import static carpet.script.CarpetEventServer.Event.PLAYER_INTERACTS_WITH_ENTITY; import static carpet.script.CarpetEventServer.Event.PLAYER_RELEASED_ITEM; import static carpet.script.CarpetEventServer.Event.PLAYER_RIDES; @@ -205,7 +207,11 @@ public class ServerPlayNetworkHandler_scarpetEventsMixin private void onWakeUp(ClientCommandC2SPacket clientCommandC2SPacket_1, CallbackInfo ci) { //weird one - doesn't seem to work, maybe MP - PLAYER_WAKES_UP.onPlayerEvent(player); + if (player.isSleeping()) + PLAYER_WAKES_UP.onPlayerEvent(player); + else + PLAYER_ESCAPES_SLEEP.onPlayerEvent(player); + } @Inject(method = "onClientCommand", at = @At( diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java index e31dda16..f734c070 100644 --- a/src/main/java/carpet/script/CarpetEventServer.java +++ b/src/main/java/carpet/script/CarpetEventServer.java @@ -337,6 +337,14 @@ public class CarpetEventServer handler.call( () -> Collections.singletonList(new EntityValue(player)), player::getCommandSource); } }; + public static final Event PLAYER_ESCAPES_SLEEP = new Event("player_escapes_sleep", 1, false) + { + @Override + public void onPlayerEvent(ServerPlayerEntity player) + { + handler.call( () -> Collections.singletonList(new EntityValue(player)), player::getCommandSource); + } + }; public static final Event PLAYER_RIDES = new Event("player_rides", 5, false) { @Override diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 2db94244..ad9eb7f5 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -658,18 +658,18 @@ public class Expression case UNARY_OPERATOR: { final LazyValue value = stack.pop(); - LazyValue result = (c, t) -> operators.get(token.surface).lazyEval(c, t, this, token, value, null).evalValue(c); + LazyValue result = (c, t) -> operators.get(token.surface).lazyEval(c, t, this, token, value, null).evalValue(c, t); stack.push(result); break; } case OPERATOR: final LazyValue v1 = stack.pop(); final LazyValue v2 = stack.pop(); - LazyValue result = (c,t) -> operators.get(token.surface).lazyEval(c, t,this, token, v2, v1).evalValue(c); + LazyValue result = (c,t) -> operators.get(token.surface).lazyEval(c, t,this, token, v2, v1).evalValue(c, t); stack.push(result); break; case VARIABLE: - stack.push((c, t) -> getOrSetAnyVariable(c, token.surface).evalValue(c)); + stack.push((c, t) -> getOrSetAnyVariable(c, token.surface).evalValue(c, t)); break; case FUNCTION: String name = token.surface; @@ -700,7 +700,7 @@ public class Expression stack.pop(); } - stack.push((c, t) -> f.lazyEval(c, t, this, token, p).evalValue(c)); + stack.push((c, t) -> f.lazyEval(c, t, this, token, p).evalValue(c, t)); break; case OPEN_PAREN: stack.push(LazyValue.PARAMS_START); diff --git a/src/main/java/carpet/script/Fluff.java b/src/main/java/carpet/script/Fluff.java index ba2a70fd..6aa60cb5 100644 --- a/src/main/java/carpet/script/Fluff.java +++ b/src/main/java/carpet/script/Fluff.java @@ -149,7 +149,7 @@ public abstract class Fluff { try { - return (c, type_ignored) -> AbstractOperator.this.eval(v1.evalValue(c), v2.evalValue(c)); + return (c, type_ignored) -> AbstractOperator.this.eval(v1.evalValue(c, type), v2.evalValue(c, type)); } catch (RuntimeException exc) { diff --git a/src/main/java/carpet/script/api/Auxiliary.java b/src/main/java/carpet/script/api/Auxiliary.java index 6112a2c6..3a7f080b 100644 --- a/src/main/java/carpet/script/api/Auxiliary.java +++ b/src/main/java/carpet/script/api/Auxiliary.java @@ -24,6 +24,7 @@ import carpet.script.value.EntityValue; import carpet.script.value.FormattedTextValue; import carpet.script.value.FunctionValue; import carpet.script.value.ListValue; +import carpet.script.value.MapValue; import carpet.script.value.NBTSerializableValue; import carpet.script.value.NullValue; import carpet.script.value.NumericValue; @@ -60,6 +61,7 @@ import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.EulerAngle; import net.minecraft.util.math.Vec2f; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.registry.DynamicRegistryManager; import net.minecraft.util.registry.Registry; import net.minecraft.world.World; import org.apache.commons.lang3.tuple.Pair; @@ -67,6 +69,7 @@ import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -304,7 +307,7 @@ public class Auxiliary { pointLocator = Vector3Argument.findIn(cc, lv, 1, true); if (lv.size()>pointLocator.offset) { - BlockArgument blockLocator = BlockArgument.findIn(cc, lv, pointLocator.offset, true, true); + BlockArgument blockLocator = BlockArgument.findIn(cc, lv, pointLocator.offset, true, true, false); if (blockLocator.block != null) targetBlock = blockLocator.block.getBlockState(); if (lv.size() > blockLocator.offset) { @@ -619,6 +622,29 @@ public class Auxiliary { }); expression.addLazyFunction("plop", -1, (c, t, lv) ->{ + if (lv.size() == 0) + { + Map plopData = new HashMap<>(); + CarpetContext cc = (CarpetContext)c; + DynamicRegistryManager registryManager = cc.s.getWorld().getRegistryManager(); + plopData.put(StringValue.of("scarpet_custom"), + ListValue.wrap(FeatureGenerator.featureMap.keySet().stream().sorted().map(StringValue::of).collect(Collectors.toList())) + ); + plopData.put(StringValue.of("features"), + ListValue.wrap(Registry.FEATURE.getIds().stream().sorted().map(ValueConversions::of).collect(Collectors.toList())) + ); + plopData.put(StringValue.of("configured_features"), + ListValue.wrap(registryManager.get(Registry.CONFIGURED_FEATURE_WORLDGEN).getIds().stream().sorted().map(ValueConversions::of).collect(Collectors.toList())) + ); + plopData.put(StringValue.of("structures"), + ListValue.wrap(Registry.STRUCTURE_FEATURE.getIds().stream().sorted().map(ValueConversions::of).collect(Collectors.toList())) + ); + plopData.put(StringValue.of("configured_structures"), + ListValue.wrap(registryManager.get(Registry.CONFIGURED_STRUCTURE_FEATURE_WORLDGEN).getIds().stream().sorted().map(ValueConversions::of).collect(Collectors.toList())) + ); + Value ret = MapValue.wrap(plopData); + return (_c, _t) -> ret; + } BlockArgument locator = BlockArgument.findIn((CarpetContext)c, lv, 0); if (lv.size() <= locator.offset) throw new InternalExpressionException("'plop' needs extra argument indicating what to plop"); @@ -656,23 +682,7 @@ public class Auxiliary { expression.addLazyFunction("logger", -1, (c, t, lv) -> { - //CarpetSettings.LOG.error("Standard Structures:"); - //CarpetSettings.LOG.error(Registry.STRUCTURE_FEATURE.getIds().stream().map(i -> "`'"+NBTSerializableValue.nameFromRegistryId(i)+"'`").sorted(). collect(Collectors.joining(", "))); - //CarpetSettings.LOG.error(""); - //CarpetSettings.LOG.error("Configured Structures:"); - //CarpetSettings.LOG.error(BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE.getIds().stream().map(i -> "`'"+NBTSerializableValue.nameFromRegistryId(i)+"'`").sorted().collect(Collectors.joining(", "))); - //CarpetSettings.LOG.error(""); - //CarpetSettings.LOG.error("Features:"); - //CarpetSettings.LOG.error(Registry.FEATURE.getIds().stream().map(i -> "`'"+NBTSerializableValue.nameFromRegistryId(i)+"'`").sorted().collect(Collectors.joining(", "))); - //CarpetSettings.LOG.error(""); - //CarpetSettings.LOG.error("Configured Features:"); - //CarpetSettings.LOG.error(BuiltinRegistries.CONFIGURED_FEATURE.getIds().stream().map(i -> "`'"+NBTSerializableValue.nameFromRegistryId(i)+"'`").sorted().collect(Collectors.joining(", "))); - //CarpetSettings.LOG.error(""); - //CarpetSettings.LOG.error("Custom:"); - //CarpetSettings.LOG.error(FeatureGenerator.featureMap.keySet().stream().map(i -> "`'"+i+"'`").sorted().collect(Collectors.joining(", "))); - //CarpetSettings.LOG.error(Registry.ENTITY_TYPE.getIds().stream().sorted().map(ValueConversions::simplify).collect(Collectors.joining("`, `"))); - Value res; if(lv.size()==1) diff --git a/src/main/java/carpet/script/api/Scoreboards.java b/src/main/java/carpet/script/api/Scoreboards.java index af653369..ee9c5ca4 100644 --- a/src/main/java/carpet/script/api/Scoreboards.java +++ b/src/main/java/carpet/script/api/Scoreboards.java @@ -262,7 +262,7 @@ public class Scoreboards { if(!(propertyVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the second argument"); switch (propertyVal.getString()) { - case "collision_rule": + case "collisionRule": if(!modifying) { Value ret = new StringValue(team.getCollisionRule().name); return (_c, _t) -> ret; @@ -287,7 +287,7 @@ public class Scoreboards { team.setColor(color); break; - case "death_message_visibility": + case "deathMessageVisibility": if(!modifying) { Value ret = new StringValue(team.getDeathMessageVisibilityRule().name); return (_c, _t) -> ret; @@ -300,7 +300,7 @@ public class Scoreboards { team.setDeathMessageVisibilityRule(deathMessageVisibility); break; - case "display_name": + case "displayName": if(!modifying) { Value ret = new FormattedTextValue(team.getDisplayName()); return (_c, _t) -> ret; @@ -319,7 +319,7 @@ public class Scoreboards { team.setDisplayName(displayName); break; - case "friendly_fire": + case "friendlyFire": if(!modifying) { Value ret = new NumericValue(team.isFriendlyFireAllowed()); return (_c, _t) -> ret; @@ -330,7 +330,7 @@ public class Scoreboards { boolean friendlyFire = settingVal.getBoolean(); team.setFriendlyFireAllowed(friendlyFire); break; - case "nametag_visibility": + case "nametagVisibility": if(!modifying) { Value ret = new StringValue(team.getNameTagVisibilityRule().name); return (_c, _t) -> ret; @@ -361,7 +361,7 @@ public class Scoreboards { team.setPrefix(prefix); break; - case "see_friendly_invisibles": + case "seeFriendlyInvisibles": if(!modifying) { Value ret = new NumericValue(team.shouldShowFriendlyInvisibles()); return (_c, _t) -> ret; diff --git a/src/main/java/carpet/script/api/WorldAccess.java b/src/main/java/carpet/script/api/WorldAccess.java index a69324c1..44a60883 100644 --- a/src/main/java/carpet/script/api/WorldAccess.java +++ b/src/main/java/carpet/script/api/WorldAccess.java @@ -18,6 +18,7 @@ import carpet.script.LazyValue; import carpet.script.argument.BlockArgument; import carpet.script.argument.Vector3Argument; import carpet.script.exception.InternalExpressionException; +import carpet.script.utils.BiomeInfo; import carpet.script.utils.WorldTools; import carpet.script.value.BlockValue; import carpet.script.value.EntityValue; @@ -66,6 +67,7 @@ import net.minecraft.sound.SoundCategory; import net.minecraft.state.StateManager; import net.minecraft.state.property.Property; import net.minecraft.structure.StructureStart; +import net.minecraft.tag.TagManager; import net.minecraft.util.ActionResult; import net.minecraft.util.Clearable; import net.minecraft.util.Identifier; @@ -101,6 +103,7 @@ import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.function.BiFunction; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -997,7 +1000,7 @@ public class WorldAccess { // block_state(block, property) expression.addLazyFunction("block_state", -1, (c, t, lv) -> { - BlockArgument locator = BlockArgument.findIn((CarpetContext) c, lv, 0); + BlockArgument locator = BlockArgument.findIn((CarpetContext) c, lv, 0, true); BlockState state = locator.block.getBlockState(); StateManager states = state.getBlock().getStateManager(); if (locator.offset == lv.size()) @@ -1018,16 +1021,71 @@ public class WorldAccess { return (_c, _t) -> retval; }); + expression.addLazyFunction("block_list", -1, (c, t, lv) -> + { + if (lv.size() == 0) + { + Value ret = ListValue.wrap(Registry.BLOCK.getIds().stream().map(ValueConversions::of).collect(Collectors.toList())); + return (_c, _t) -> ret; + } + CarpetContext cc = (CarpetContext)c; + TagManager tagManager = cc.s.getMinecraftServer().getTagManager(); + String tag = lv.get(0).evalValue(c).getString(); + net.minecraft.tag.Tag blockTag = tagManager.getBlocks().getTag(new Identifier(tag)); + if (blockTag == null) return LazyValue.NULL; + Value ret = ListValue.wrap(blockTag.values().stream().map(b -> ValueConversions.of(Registry.BLOCK.getId(b))).collect(Collectors.toList())); + return (_c, _t) -> ret; + }); + + expression.addLazyFunction("block_tags", -1, (c, t, lv) -> + { + CarpetContext cc = (CarpetContext)c; + TagManager tagManager = cc.s.getMinecraftServer().getTagManager(); + if (lv.size() == 0) + { + Value ret = ListValue.wrap(tagManager.getBlocks().getTagIds().stream().map(ValueConversions::of).collect(Collectors.toList())); + return (_c, _t) -> ret; + } + BlockArgument blockLocator = BlockArgument.findIn(cc, lv, 0, true); + if (blockLocator.offset == lv.size()) + { + Value ret = ListValue.wrap(tagManager.getBlocks().getTagsFor(blockLocator.block.getBlockState().getBlock()).stream().map(ValueConversions::of).collect(Collectors.toList())); + return (_c, _t) -> ret; + } + String tag = lv.get(blockLocator.offset).evalValue(c).getString(); + net.minecraft.tag.Tag blockTag = tagManager.getBlocks().getTag(new Identifier(tag)); + if (blockTag == null) return LazyValue.NULL; + return blockLocator.block.getBlockState().isIn(blockTag)?LazyValue.TRUE:LazyValue.FALSE; + }); + + expression.addLazyFunction("biome", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext)c; - BlockArgument locator = BlockArgument.findIn(cc, lv, 0); - ServerWorld world = cc.s.getWorld(); - BlockPos pos = locator.block.getPos(); - Biome biome = world.getBiome(pos); + BlockArgument locator = BlockArgument.findIn(cc, lv, 0, false, false, true); + Biome biome; + if (locator.replacement != null) + { + biome = cc.s.getMinecraftServer().getRegistryManager().get(Registry.BIOME_KEY).get(new Identifier(locator.replacement)); + if (biome == null) throw new InternalExpressionException("Unknown biome: "+locator.replacement); + } + else + { + ServerWorld world = cc.s.getWorld(); + BlockPos pos = locator.block.getPos(); + biome = world.getBiome(pos); + } // in locatebiome - Identifier biomeId = cc.s.getMinecraftServer().getRegistryManager().get(Registry.BIOME_KEY).getId(biome); - Value res = new StringValue(NBTSerializableValue.nameFromRegistryId(biomeId)); - return (_c, _t) -> res; + if (locator.offset == lv.size()) + { + Identifier biomeId = cc.s.getMinecraftServer().getRegistryManager().get(Registry.BIOME_KEY).getId(biome); + Value res = new StringValue(NBTSerializableValue.nameFromRegistryId(biomeId)); + return (_c, _t) -> res; + } + String biomeFeature = lv.get(locator.offset).evalValue(c).getString(); + Function featureProvider = BiomeInfo.biomeFeatures.get(biomeFeature); + if (featureProvider == null) throw new InternalExpressionException("Unknown biome feature: "+biomeFeature); + Value ret = featureProvider.apply(biome); + return (_c, _t) -> ret; }); expression.addLazyFunction("set_biome", -1, (c, t, lv) -> @@ -1128,7 +1186,17 @@ public class WorldAccess { Map ret = new HashMap<>(); for(StructureFeature str : StructureFeature.STRUCTURES.values()) { - StructureStart start = FeatureGenerator.shouldStructureStartAt(world, pos, str, needSize); + StructureStart start; + try + { + start = FeatureGenerator.shouldStructureStartAt(world, pos, str, needSize); + } + catch (NullPointerException npe) + { + CarpetSettings.LOG.error("Failed to detect structure: "+str.getName()); + start = null; + } + if (start == null) continue; Value key = new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.STRUCTURE_FEATURE.getId(str))); diff --git a/src/main/java/carpet/script/argument/BlockArgument.java b/src/main/java/carpet/script/argument/BlockArgument.java index 59c0d96c..5a0f236f 100644 --- a/src/main/java/carpet/script/argument/BlockArgument.java +++ b/src/main/java/carpet/script/argument/BlockArgument.java @@ -16,22 +16,30 @@ import java.util.List; public class BlockArgument extends Argument { public final BlockValue block; + public final String replacement; private BlockArgument(BlockValue b, int o) { super(o); block = b; + replacement = null; + } + private BlockArgument(BlockValue b, int o, String replacement) + { + super(o); + block = b; + this.replacement = replacement; } public static BlockArgument findIn(CarpetContext c, List params, int offset) { - return findIn(c, params,offset, false, false); + return findIn(c, params,offset, false, false, false); } public static BlockArgument findIn(CarpetContext c, List params, int offset, boolean acceptString) { - return findIn(c, params,offset, acceptString, false); + return findIn(c, params,offset, acceptString, false, false); } - public static BlockArgument findIn(CarpetContext c, List params, int offset, boolean acceptString, boolean optional) + public static BlockArgument findIn(CarpetContext c, List params, int offset, boolean acceptString, boolean optional, boolean anyString) { try { @@ -41,6 +49,10 @@ public class BlockArgument extends Argument { return new BlockArgument(null, 1+offset); } + if (anyString && v1 instanceof StringValue) + { + return new BlockArgument(null, 1+offset, v1.getString()); + } if (acceptString && v1 instanceof StringValue) { return new BlockArgument(BlockValue.fromString(v1.getString()), 1+offset); diff --git a/src/main/java/carpet/script/language/Functions.java b/src/main/java/carpet/script/language/Functions.java index e45d6a21..1588a3e0 100644 --- a/src/main/java/carpet/script/language/Functions.java +++ b/src/main/java/carpet/script/language/Functions.java @@ -45,11 +45,10 @@ public class Functions { { FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, false, true); FunctionValue fun = functionArgument.function; - Value retval = fun.callInContext(expr, c, t, fun.getExpression(), fun.getToken(), functionArgument.args).evalValue(c); - return (cc, tt) -> retval; ///!!!! dono might need to store expr and token in statics? (e? t?) + return fun.callInContext(c, t, functionArgument.args); } // gimme signature - String name = lv.get(0).evalValue(c).getString(); + String name = lv.get(0).evalValue(c, Context.NONE).getString(); List args = new ArrayList<>(); List globals = new ArrayList<>(); String varArgs = null; diff --git a/src/main/java/carpet/script/language/Loops.java b/src/main/java/carpet/script/language/Loops.java index aa5f4f66..cfd1cbbd 100644 --- a/src/main/java/carpet/script/language/Loops.java +++ b/src/main/java/carpet/script/language/Loops.java @@ -70,7 +70,7 @@ public class Loops { // expr receives bounded variable '_' indicating iteration expression.addLazyFunction("loop", 2, (c, t, lv) -> { - long limit = NumericValue.asNumber(lv.get(0).evalValue(c)).getLong(); + long limit = NumericValue.asNumber(lv.get(0).evalValue(c, Context.NONE)).getLong(); Value lastOne = Value.NULL; LazyValue expr = lv.get(1); //scoping @@ -99,7 +99,7 @@ public class Loops { // receives bounded variable '_' with the expression expression.addLazyFunction("map", 2, (c, t, lv) -> { - Value rval= lv.get(0).evalValue(c); + Value rval= lv.get(0).evalValue(c, Context.NONE); if (!(rval instanceof AbstractListValue)) throw new InternalExpressionException("First argument of 'map' function should be a list or iterator"); Iterator iterator = ((AbstractListValue) rval).iterator(); @@ -144,7 +144,7 @@ public class Loops { // produces list of values for which the expression is true expression.addLazyFunction("filter", 2, (c, t, lv) -> { - Value rval= lv.get(0).evalValue(c); + Value rval= lv.get(0).evalValue(c, Context.NONE); if (!(rval instanceof AbstractListValue)) throw new InternalExpressionException("First argument of 'filter' function should be a list or iterator"); Iterator iterator = ((AbstractListValue) rval).iterator(); @@ -191,7 +191,7 @@ public class Loops { expression.addLazyFunction("first", 2, (c, t, lv) -> { - Value rval= lv.get(0).evalValue(c); + Value rval= lv.get(0).evalValue(c, Context.NONE); if (!(rval instanceof AbstractListValue)) throw new InternalExpressionException("First argument of 'first' function should be a list or iterator"); Iterator iterator = ((AbstractListValue) rval).iterator(); @@ -242,7 +242,7 @@ public class Loops { // returns true if expr is true for all items expression.addLazyFunction("all", 2, (c, t, lv) -> { - Value rval= lv.get(0).evalValue(c); + Value rval= lv.get(0).evalValue(c, Context.NONE); if (!(rval instanceof AbstractListValue)) throw new InternalExpressionException("First argument of 'all' function should be a list or iterator"); Iterator iterator = ((AbstractListValue) rval).iterator(); @@ -306,7 +306,7 @@ public class Loops { // can be substituted for first and all, but first is more efficient and all doesn't require knowing list size expression.addLazyFunction("for", 2, (c, t, lv) -> { - Value rval= lv.get(0).evalValue(c); + Value rval= lv.get(0).evalValue(c, Context.NONE); if (!(rval instanceof AbstractListValue)) throw new InternalExpressionException("First argument of 'for' function should be a list or iterator"); Iterator iterator = ((AbstractListValue) rval).iterator(); @@ -358,8 +358,8 @@ public class Loops { { LazyValue expr = lv.get(1); - Value acc = lv.get(2).evalValue(c); - Value rval= lv.get(0).evalValue(c); + Value acc = lv.get(2).evalValue(c, Context.NONE); + Value rval= lv.get(0).evalValue(c, Context.NONE); if (!(rval instanceof AbstractListValue)) throw new InternalExpressionException("First argument of 'reduce' should be a list or iterator"); Iterator iterator = ((AbstractListValue) rval).iterator(); diff --git a/src/main/java/carpet/script/utils/BiomeInfo.java b/src/main/java/carpet/script/utils/BiomeInfo.java new file mode 100644 index 00000000..d62dd88e --- /dev/null +++ b/src/main/java/carpet/script/utils/BiomeInfo.java @@ -0,0 +1,32 @@ +package carpet.script.utils; + +import carpet.script.value.BlockValue; +import carpet.script.value.NumericValue; +import carpet.script.value.StringValue; +import carpet.script.value.Value; +import carpet.script.value.ValueConversions; +import net.minecraft.world.biome.Biome; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +public class BiomeInfo +{ + public final static Map> biomeFeatures = new HashMap>(){{ + put("top_material", b -> new BlockValue( b.getGenerationSettings().getSurfaceConfig().getTopMaterial(), null, null)); + put("under_material", b -> new BlockValue( b.getGenerationSettings().getSurfaceConfig().getUnderMaterial(), null, null)); + put("category", b -> StringValue.of(b.getCategory().getName())); + put("temperature", b -> NumericValue.of(b.getTemperature())); + put("fog_color", b -> ValueConversions.ofRGB(b.getFogColor())); + put("foliage_color", b -> ValueConversions.ofRGB(b.getFoliageColor())); + put("sky_color", b -> ValueConversions.ofRGB(b.getSkyColor())); + put("water_color", b -> ValueConversions.ofRGB(b.getWaterColor())); + put("water_fog_color", b -> ValueConversions.ofRGB(b.getWaterFogColor())); + put("humidity", b -> NumericValue.of(b.getDownfall())); + put("precipitation", b -> StringValue.of(b.getPrecipitation().getName())); + put("depth", b -> NumericValue.of(b.getDepth())); + put("scale", b -> NumericValue.of(b.getScale())); + //put("features", b -> b.getGenerationSettings().getFeatures()) + }}; +} diff --git a/src/main/java/carpet/script/value/FunctionValue.java b/src/main/java/carpet/script/value/FunctionValue.java index d81276cc..c9370369 100644 --- a/src/main/java/carpet/script/value/FunctionValue.java +++ b/src/main/java/carpet/script/value/FunctionValue.java @@ -150,11 +150,11 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction return varArgs != null; } - public LazyValue callInContext(Expression callingExpression, Context c, Integer type, Expression e, Tokenizer.Token t, List lazyParams) + public LazyValue callInContext(Context c, Integer type, List lazyParams) { try { - return lazyEval(c, type, e, t, lazyParams); + return lazyEval(c, type, expression, token, lazyParams); } catch (ExpressionException exc) { @@ -164,12 +164,12 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction catch (InternalExpressionException exc) { exc.stack.add(this); - throw new ExpressionException(c, e, t, exc.getMessage(), exc.stack); + throw new ExpressionException(c, expression, token, exc.getMessage(), exc.stack); } catch (ArithmeticException exc) { - throw new ExpressionException(c, e, t, "Your math is wrong, "+exc.getMessage(), Collections.singletonList(this)); + throw new ExpressionException(c, expression, token, "Your math is wrong, "+exc.getMessage(), Collections.singletonList(this)); } } diff --git a/src/main/java/carpet/script/value/NumericValue.java b/src/main/java/carpet/script/value/NumericValue.java index 97ea3a0b..b4e47501 100644 --- a/src/main/java/carpet/script/value/NumericValue.java +++ b/src/main/java/carpet/script/value/NumericValue.java @@ -41,6 +41,7 @@ public class NumericValue extends Value { if (value == null) return Value.NULL; if (value.doubleValue() == value.longValue()) return new NumericValue(value.longValue()); + if (value instanceof Float) return new NumericValue(0.000_001D * Math.round(1_000_000.0D*value.doubleValue())); return new NumericValue(value.doubleValue()); } diff --git a/src/main/java/carpet/script/value/ValueConversions.java b/src/main/java/carpet/script/value/ValueConversions.java index 9fa06397..a47887ba 100644 --- a/src/main/java/carpet/script/value/ValueConversions.java +++ b/src/main/java/carpet/script/value/ValueConversions.java @@ -299,23 +299,27 @@ public class ValueConversions public static Value of(StructureStart structure) { if (structure == null || structure == StructureStart.DEFAULT) return Value.NULL; - List pieces = new ArrayList<>(); - for (StructurePiece piece : structure.getChildren()) - { - BlockBox box = piece.getBoundingBox(); - pieces.add(ListValue.of( - new StringValue( NBTSerializableValue.nameFromRegistryId(Registry.STRUCTURE_PIECE.getId(piece.getType()))), - (piece.getFacing()== null)?Value.NULL: new StringValue(piece.getFacing().getName()), - ListValue.fromTriple(box.minX, box.minY, box.minZ), - ListValue.fromTriple(box.maxX, box.maxY, box.maxZ) - )); - } BlockBox boundingBox = structure.getBoundingBox(); + if (boundingBox.maxX < boundingBox.minX || boundingBox.maxY < boundingBox.minY || boundingBox.maxZ < boundingBox.minZ) return Value.NULL; Map ret = new HashMap<>(); ret.put(new StringValue("box"), ListValue.of( ListValue.fromTriple(boundingBox.minX, boundingBox.minY, boundingBox.minZ), ListValue.fromTriple(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ) )); + List pieces = new ArrayList<>(); + for (StructurePiece piece : structure.getChildren()) + { + BlockBox box = piece.getBoundingBox(); + if (box.maxX >= box.minX && box.maxY >= box.minY && box.maxZ >= box.minZ) + { + pieces.add(ListValue.of( + new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.STRUCTURE_PIECE.getId(piece.getType()))), + (piece.getFacing() == null) ? Value.NULL : new StringValue(piece.getFacing().getName()), + ListValue.fromTriple(box.minX, box.minY, box.minZ), + ListValue.fromTriple(box.maxX, box.maxY, box.maxZ) + )); + } + } ret.put(new StringValue("pieces"), ListValue.wrap(pieces)); return MapValue.wrap(ret); } diff --git a/src/main/resources/assets/carpet/scripts/event_test.sc b/src/main/resources/assets/carpet/scripts/event_test.sc index 2e655054..3c6c989e 100644 --- a/src/main/resources/assets/carpet/scripts/event_test.sc +++ b/src/main/resources/assets/carpet/scripts/event_test.sc @@ -17,6 +17,12 @@ __on_player_wakes_up(player) -> ( print('Player '+player+' wakes up') ); +__on_player_escapes_sleep(player) -> ( + print(''); + print('__on_player_escapes_sleep(player)'); + print('Player '+player+' wakes up using ESC key') +); + __on_player_rides(player, forward, strafe, jumping, sneaking) -> ( print('');