diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java index fb352c64..72a52108 100644 --- a/src/main/java/carpet/script/CarpetEventServer.java +++ b/src/main/java/carpet/script/CarpetEventServer.java @@ -235,7 +235,7 @@ public class CarpetEventServer private ScheduledCall makeEventCall(CarpetContext cc, String function, List extraArgs, int argCount) { UserDefinedFunction udf = cc.host.globalFunctions.get(function); - if (udf == null || (udf.getArguments().size()-extraArgs.size()) != argCount) + if (udf == null || (udf.getArguments().size()-(extraArgs == null ? 0 : extraArgs.size())) != argCount) { // call won't match arguments return null; @@ -389,11 +389,9 @@ public class CarpetEventServer } public ScheduledCall makeDamageCall(CarpetContext cc, String function, List extraArgs) { - return makeEventCall(cc, function, extraArgs, 3); + return makeEventCall(cc, function, extraArgs, 4); } - - public void onEntityDeath(ScheduledCall call, Entity e, String reason) { call.execute( Arrays.asList( (c, t)-> new EntityValue(e), (c, t)-> new StringValue(reason))); diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index c80dee86..d6ff1f4e 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -1586,6 +1586,43 @@ public class CarpetExpression *

Sets AI to stay around the home position, within distance blocks from it. distance * defaults to 16 blocks. null removes it. May not work fully with mobs that have this AI built in, like * Villagers.

+ *

Entity Events

+ *

There is a number of events that happen to entities that you can attach your own code to in the form of event + * handlers. The event handler is any function that runs in your package that accepts certain expected parameters, which + * you can expand with your own arguments. When it comes to the moment when the given command needs to be executed, it + * does so providing that number of arguments it accepts is equal number of event arguments, and extra arguments passed when + * defining the callback with entity_event

+ *

The following events can be handled by entities.

+ * + *

It doesn't mean that all entity types will have a chance to + * execute a given event, but entities will not error when you will attach inapplicable event to it.

+ *

entity_event(e, event, call_name, args...)

+ *

Attaches specific function from the current package to be called upon the event, with extra args + * curried to the original required arguments for the event handler

+ *
+     * protect_villager(entity, amount, source, source_entity, healing_player) ->
+     * (
+     * 	 if(source_entity && source_entity~'type' != 'player',
+     * 	   modify(entity, 'health', amount + entity~'health' );
+     * 	   particle('end_rod', pos(entity)+l(0,3,0));
+     * 	   print(str('%s healed thanks to %s', entity, healing_player))
+     * 	 )
+     * );
+     *
+     * __on_player_interacts_with_entity(player, entity, hand) ->
+     * (
+     *   if (entity~'type' == 'villager',
+     * 	   entity_event(entity, 'on_damage', 'protect_villager', player~'name')
+     *   )
+     * )
+     * 
+ *

In this case this will protect a villager from entity damage (zombies, etc.) except players by granting all the health + * back to the villager after being harmed.

* */ diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index a812c876..155e7c7f 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -309,6 +309,7 @@ import static java.lang.Math.min; public class Expression implements Cloneable { private static final Map precedence = new HashMap() {{ + put("attribute~.", 80); put("unary+-!", 60); put("exponent^", 40); put("multiplication*/%", 30); @@ -560,7 +561,8 @@ public class Expression implements Cloneable return new ExpressionException(e, token, "Your math is wrong, "+exc.getMessage()); if (exc instanceof ExpressionException) return exc; - return new ExpressionException(e, token, "Error while evaluating expression: "+exc.getMessage()); + exc.printStackTrace(); + return new ExpressionException(e, token, "Error while evaluating expression: "+exc); } private void addUnaryOperator(String surface, boolean leftAssoc, Function fun) @@ -912,7 +914,7 @@ public class Expression implements Cloneable public void UserDefinedFunctionsAndControlFlow() // public just to get the javadoc right { // artificial construct to handle user defined functions and function definitions - addLazyFunction(".",-1, (c, t, lv) -> { // adjust based on c + addLazyFunction(" ",-1, (c, t, lv) -> { // adjust based on c String name = lv.get(lv.size()-1).evalValue(c).getString(); //lv.remove(lv.size()-1); // aint gonna cut it // maybe it will because of the eager eval changes if (t != Context.SIGNATURE) // just call the function @@ -1062,11 +1064,12 @@ public class Expression implements Cloneable * note, that commas and brackets are not operators, but behave like them: *

*
    + *
  • Match, Get~ .
  • *
  • Unary + - !
  • *
  • Exponent ^
  • *
  • Multiplication * / %
  • *
  • Addition + -
  • - *
  • Comparison == != > >= <= < ~
  • + *
  • Comparison == != > >= <= <
  • *
  • Logical And&&
  • *
  • Logical Or ||
  • *
  • Assignment = += <>
  • @@ -1140,8 +1143,14 @@ public class Expression implements Cloneable * null != false && run('kill gnembon') => 1 // gnembon dies, cheats allowed * * + *

    Get, Accessor Operator .

    + *

    Operator version of the get(...) function to access elements of lists, nbts, and potentially other + * containers. It is important to distinguish from ~ operator, which is a matching operator, meaning it + * is expected to perform some extra computations to retrieve the result, while . should be + * straightforward and immediate.

    + * *

    Matching Operator ~

    - *

    This operator should be understood as 'matches', or 'in'. For strings it matches the right operand as a regular + *

    This operator should be understood as 'matches', 'contains' or 'is_in'. For strings it matches the right operand as a regular * expression to the left one, returning the first match. This can be used to extract information from unparsed nbt's * in a more efficient way. For lists it checks if an element is in the list, and returns the index of that element, * or null if no such element was found, especially that the use of first function will not @@ -1161,7 +1170,7 @@ public class Expression implements Cloneable *

          * entities = entities_area('all',x,y,z,100,10,100);
          * sid = entities ~ 'Squid';
    -     * if(sid != null, run('execute as '+query(element(entities,sid),'id')+' run say I am here '+query(element(entities,sid),'pos') ) )
    +     * if(sid != null, run('execute as '+query(get(entities,sid),'id')+' run say I am here '+query(get(entities,sid),'pos') ) )
          * 
    *

    Or an example to find if a player has specific enchantment on a held axe (either hand) and get its level * (despite obvious lack of support for json NBT's):

    @@ -1218,6 +1227,7 @@ public class Expression implements Cloneable */ public void Operators() { + addBinaryOperator(".", precedence.get("attribute~."),true, Value::getElementAt); addBinaryOperator("+", precedence.get("addition+-"), true, Value::add); addBinaryOperator("-", precedence.get("addition+-"), true, Value::subtract); addBinaryOperator("*", precedence.get("multiplication*/%"), true, Value::multiply); @@ -1243,7 +1253,7 @@ public class Expression implements Cloneable return v2.getBoolean() ? ((cc, tt) -> v2) : LazyValue.FALSE; }); - addBinaryOperator("~", precedence.get("compare>=><=<"), true, Value::in); + addBinaryOperator("~", precedence.get("attribute~."), true, Value::in); addBinaryOperator(">", precedence.get("compare>=><=<"), false, (v1, v2) -> v1.compareTo(v2) > 0 ? Value.TRUE : Value.FALSE); @@ -2890,7 +2900,7 @@ public class Expression implements Cloneable } else // potentially unknown function or just unknown function { - f = functions.get("."); + f = functions.get(" "); p = new ArrayList<>(); } // pop parameters off the stack until we hit the start of diff --git a/src/main/java/carpet/script/value/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java index e357fa10..52f563e6 100644 --- a/src/main/java/carpet/script/value/EntityValue.java +++ b/src/main/java/carpet/script/value/EntityValue.java @@ -728,6 +728,6 @@ public class EntityValue extends Value put("on_death", (c, e, f, l) -> ((EntityInterface)e).setDeathCallback(c, f, l)); put("on_removed", (c, e, f, l) -> ((EntityInterface)e).setRemovedCallback(c, f, l)); put("on_tick", (c, e, f, l) -> ((EntityInterface)e).setTickCallback(c, f, l)); - put("on_damage", (c, e, f, l) -> ((EntityInterface)e).setDamageCallback(c, f, l)); + put("on_damaged", (c, e, f, l) -> ((EntityInterface)e).setDamageCallback(c, f, l)); }}; }