From 92dcf6648ea6f0849a30b7daf58a651d90a3fd2c Mon Sep 17 00:00:00 2001 From: replaceitem <40722305+replaceitem@users.noreply.github.com> Date: Fri, 27 Nov 2020 04:54:09 +0100 Subject: [PATCH 01/12] Fixed small mistakes in team functions (#580) --- docs/scarpet/api/Scoreboard.md | 2 +- src/main/java/carpet/script/api/Scoreboards.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) 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/src/main/java/carpet/script/api/Scoreboards.java b/src/main/java/carpet/script/api/Scoreboards.java index 821294ce..0ba8d9e5 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; From db99ed26d8c56c9b4dd317cd5692117ad1df98ad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 27 Nov 2020 03:54:26 +0000 Subject: [PATCH 02/12] Merge docs for 'Fixed small mistakes in team functions (#580)' --- docs/scarpet/Full.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index 20369350..3dd89bf4 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -4217,7 +4217,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 From a099ed79e10aea520a4c298651ac8340da772eb5 Mon Sep 17 00:00:00 2001 From: gnembon Date: Fri, 27 Nov 2020 00:34:24 -0400 Subject: [PATCH 03/12] added `player_escapes_sleep` event. Fixes #579 --- docs/scarpet/api/Events.md | 4 ++++ docs/scarpet/resources/editors/idea/4.txt | 3 ++- docs/scarpet/resources/editors/npp/scarpet.xml | 1 + .../ServerPlayNetworkHandler_scarpetEventsMixin.java | 8 +++++++- src/main/java/carpet/script/CarpetEventServer.java | 8 ++++++++ src/main/resources/assets/carpet/scripts/event_test.sc | 6 ++++++ 6 files changed, 28 insertions(+), 2 deletions(-) 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/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..1cf4e378 100644 --- a/docs/scarpet/resources/editors/npp/scarpet.xml +++ b/docs/scarpet/resources/editors/npp/scarpet.xml @@ -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/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java index 1f8a099b..0ce11682 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/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(''); From 989bc1ec2b8dc6ea856b183a895ee94f58042b21 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 27 Nov 2020 04:35:11 +0000 Subject: [PATCH 04/12] Merge docs for 'Merge branch 'master' of https://github.com/gnembon/fabric-carpet' --- docs/scarpet/Full.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index 3dd89bf4..fbea5ea9 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -3950,6 +3950,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)` From 07dce7bc2e30d196ab2856c6a7f88d62b74335b2 Mon Sep 17 00:00:00 2001 From: gnembon Date: Fri, 27 Nov 2020 02:30:10 -0400 Subject: [PATCH 05/12] risky optimizations. --- src/main/java/carpet/script/Expression.java | 8 ++++---- src/main/java/carpet/script/Fluff.java | 2 +- .../java/carpet/script/language/Functions.java | 5 ++--- src/main/java/carpet/script/language/Loops.java | 16 ++++++++-------- .../java/carpet/script/value/FunctionValue.java | 8 ++++---- 5 files changed, 19 insertions(+), 20 deletions(-) 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/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/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)); } } From 620675319840d7cf27bee2d2eac7c0a8db823f31 Mon Sep 17 00:00:00 2001 From: gnembon Date: Fri, 27 Nov 2020 15:50:57 -0400 Subject: [PATCH 06/12] block_state can accept string block name as well. --- docs/scarpet/api/BlocksAndWorldAccess.md | 5 ++++- src/main/java/carpet/script/api/WorldAccess.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/scarpet/api/BlocksAndWorldAccess.md b/docs/scarpet/api/BlocksAndWorldAccess.md index 1cd183ec..36a706c1 100644 --- a/docs/scarpet/api/BlocksAndWorldAccess.md +++ b/docs/scarpet/api/BlocksAndWorldAccess.md @@ -248,15 +248,18 @@ 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
diff --git a/src/main/java/carpet/script/api/WorldAccess.java b/src/main/java/carpet/script/api/WorldAccess.java
index 8c1417c5..ee1ac0b5 100644
--- a/src/main/java/carpet/script/api/WorldAccess.java
+++ b/src/main/java/carpet/script/api/WorldAccess.java
@@ -997,7 +997,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())

From 45e3abf19c6cb639698e3d4614624d70995ab18c Mon Sep 17 00:00:00 2001
From: gnembon 
Date: Sat, 28 Nov 2020 01:24:49 -0400
Subject: [PATCH 07/12] fix to handle invalid structures with invalid boxes.

---
 docs/scarpet/api/BlocksAndWorldAccess.md      |  4 +--
 .../java/carpet/script/api/WorldAccess.java   | 12 ++++++++-
 .../carpet/script/value/ValueConversions.java | 26 +++++++++++--------
 3 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/docs/scarpet/api/BlocksAndWorldAccess.md b/docs/scarpet/api/BlocksAndWorldAccess.md
index 36a706c1..b35b9d0c 100644
--- a/docs/scarpet/api/BlocksAndWorldAccess.md
+++ b/docs/scarpet/api/BlocksAndWorldAccess.md
@@ -685,7 +685,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.
 
@@ -702,7 +702,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/src/main/java/carpet/script/api/WorldAccess.java b/src/main/java/carpet/script/api/WorldAccess.java
index ee1ac0b5..c534b7b9 100644
--- a/src/main/java/carpet/script/api/WorldAccess.java
+++ b/src/main/java/carpet/script/api/WorldAccess.java
@@ -1128,7 +1128,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/value/ValueConversions.java b/src/main/java/carpet/script/value/ValueConversions.java
index 8ffd3c02..1108b1e2 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);
     }

From 083d2a7f2ed041ee9eab23e0928616704c10d366 Mon Sep 17 00:00:00 2001
From: gnembon 
Date: Sat, 28 Nov 2020 01:44:16 -0400
Subject: [PATCH 08/12] plop with no args returns all available structures and
 features.

---
 docs/scarpet/api/BlocksAndWorldAccess.md      | 65 ++++++-------------
 .../java/carpet/helpers/FeatureGenerator.java | 10 +--
 .../java/carpet/script/api/Auxiliary.java     | 42 +++++++-----
 3 files changed, 51 insertions(+), 66 deletions(-)

diff --git a/docs/scarpet/api/BlocksAndWorldAccess.md b/docs/scarpet/api/BlocksAndWorldAccess.md
index b35b9d0c..3cb288bd 100644
--- a/docs/scarpet/api/BlocksAndWorldAccess.md
+++ b/docs/scarpet/api/BlocksAndWorldAccess.md
@@ -507,9 +507,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
@@ -539,7 +542,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+).
@@ -603,13 +606,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'`,
@@ -618,48 +625,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
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/script/api/Auxiliary.java b/src/main/java/carpet/script/api/Auxiliary.java
index 6e115aa3..a7e1f134 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;
@@ -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)

From 6ee8d55f889839d5dc2493da4d245dad42576ccf Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" 
Date: Sat, 28 Nov 2020 05:44:49 +0000
Subject: [PATCH 09/12] Merge docs for 'plop with no args returns all available
 structures and features.'

---
 docs/scarpet/Full.md | 74 ++++++++++++++++----------------------------
 1 file changed, 26 insertions(+), 48 deletions(-)

diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md
index fbea5ea9..db7e3248 100644
--- a/docs/scarpet/Full.md
+++ b/docs/scarpet/Full.md
@@ -2204,15 +2204,18 @@ 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
@@ -2460,9 +2463,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 +2498,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 +2562,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 +2581,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 +2616,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 +2633,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).
 

From b13c59eedf5800b202cfb560c791890ef2205917 Mon Sep 17 00:00:00 2001
From: gnembon 
Date: Sat, 28 Nov 2020 02:29:26 -0400
Subject: [PATCH 10/12] added `block_list` and `block_tags` to handle block
 tags.

---
 docs/scarpet/api/BlocksAndWorldAccess.md      | 10 +++++
 docs/scarpet/resources/editors/idea/2.txt     |  2 +
 .../scarpet/resources/editors/npp/scarpet.xml |  2 +-
 .../java/carpet/script/api/WorldAccess.java   | 39 +++++++++++++++++++
 4 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/docs/scarpet/api/BlocksAndWorldAccess.md b/docs/scarpet/api/BlocksAndWorldAccess.md
index 3cb288bd..8b64135c 100644
--- a/docs/scarpet/api/BlocksAndWorldAccess.md
+++ b/docs/scarpet/api/BlocksAndWorldAccess.md
@@ -266,6 +266,16 @@ 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 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/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml index 1cf4e378..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 diff --git a/src/main/java/carpet/script/api/WorldAccess.java b/src/main/java/carpet/script/api/WorldAccess.java index c534b7b9..c1389303 100644 --- a/src/main/java/carpet/script/api/WorldAccess.java +++ b/src/main/java/carpet/script/api/WorldAccess.java @@ -66,6 +66,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; @@ -1018,6 +1019,44 @@ 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); From f01518a5439a5b65ed7097c3e44e0111ebd79582 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Nov 2020 06:29:51 +0000 Subject: [PATCH 11/12] Merge docs for 'added and to handle block tags.' --- docs/scarpet/Full.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index db7e3248..d861d1f1 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -2222,6 +2222,16 @@ 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 From 54d306d9bcad86abc05b0488713c5b03e1d069f2 Mon Sep 17 00:00:00 2001 From: gnembon Date: Sat, 28 Nov 2020 12:11:31 -0400 Subject: [PATCH 12/12] added biome query to `biome` --- .../java/carpet/script/api/Auxiliary.java | 2 +- .../java/carpet/script/api/WorldAccess.java | 33 +++++++++++++++---- .../carpet/script/argument/BlockArgument.java | 18 ++++++++-- .../java/carpet/script/utils/BiomeInfo.java | 32 ++++++++++++++++++ .../carpet/script/value/NumericValue.java | 1 + 5 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 src/main/java/carpet/script/utils/BiomeInfo.java diff --git a/src/main/java/carpet/script/api/Auxiliary.java b/src/main/java/carpet/script/api/Auxiliary.java index a7e1f134..edf922c3 100644 --- a/src/main/java/carpet/script/api/Auxiliary.java +++ b/src/main/java/carpet/script/api/Auxiliary.java @@ -307,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) { diff --git a/src/main/java/carpet/script/api/WorldAccess.java b/src/main/java/carpet/script/api/WorldAccess.java index c1389303..154b09f5 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; @@ -102,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; @@ -1059,14 +1061,31 @@ public class WorldAccess { 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) -> 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/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/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()); }