From dca72f603b80eae3dca8e006b18a3521304010c5 Mon Sep 17 00:00:00 2001 From: gnembon Date: Sun, 30 Jun 2019 00:51:12 -0300 Subject: [PATCH] touchups and docs --- .gitignore | 1 + .../java/carpet/script/CarpetExpression.java | 312 ++++++++++++------ src/main/java/carpet/script/Expression.java | 25 +- .../java/carpet/script/value/BlockValue.java | 2 +- src/main/java/carpet/settings/Validator.java | 2 +- 5 files changed, 234 insertions(+), 108 deletions(-) diff --git a/.gitignore b/.gitignore index 2105712d..7c9ff93b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ build/ out/ classes/ publish/ +docs/ # idea diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 4f63e39e..c9eeb038 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -281,12 +281,13 @@ public class CarpetExpression *

Specifying blocks

*

block(x, y, z), block(state)

*

Returns either a block from specified location, or block with a specific state - * (as used by /setblock command), so allowing for block properties etc. - * Blocks can be referenced everywhere by its simple name, but its only used in its default state

+ * (as used by /setblock command), so allowing for block properties, block entity data etc. + * Blocks otherwise can be referenced everywhere by its simple string name, but its only used in its default state

*
      * block('air')  => air
      * block('iron_trapdoor[half=top]')  => iron_trapdoor
      * block(0,0,0) == block('bedrock')  => 1
+     * block('hopper[facing=north]{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') => hopper
      * 
*

World Manipulation

*

All the functions below can be used with block value, queried with coord triple, or 3-long list. @@ -315,6 +316,21 @@ public class CarpetExpression * set(x,y,z,'iron_trapdoor[half=top]') // Incorrect. sets bottom iron trapdoor - no parsing of properties * set(x,y,z,'iron_trapdoor','half','top') // correct - top trapdoor * set(x,y,z,block('iron_trapdoor[half=top]')) // also correct, block() provides extra parsing + * set(x,y,z,'hopper[facing=north]{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') // extra block data + * + *

place_item(item, pos, facing?, sneak?)

+ *

Places a given item in the world like it was placed by a player. Item names are default minecraft item name, + * less the minecraft prefix. Default facing is 'up', but there are other options: 'down', 'north', 'east', + * 'south', 'west', but also there are other secondary directions important for placement of blocks like stairs, doors, etc. + * Try experiment with options like 'north-up' which is placed facing north with cursor pointing to the upper part of the block, + * or 'up-north', which means a block placed facing up (player looking down) and placed smidge away of the block center + * towards north. Optional sneak is a boolean indicating if a player would be sneaking while placing the block - + * this option only affects placement of chests and scaffolding at the moment. + * Returns true if placement was successful, false otherwise.

+ *
+     *     place_item('stone',x,y,z) // places a stone block on x,y,z block
+     *     place_item('piston,x,y,z,'down') // places a piston facing down
+     *     place_item('carrot',x,y,z) // attempts to plant a carrot plant. Returns true if could place carrots at that position.
      * 
*

update(pos)

*

Causes a block update at position.

@@ -352,7 +368,12 @@ public class CarpetExpression * property(block('iron_trapdoor[half=top]'),'powered') => false * bool(property(block('iron_trapdoor[half=top]'),'powered')) => 0 * - * + *

block_data(pos)

+ *

Return NBT string associated with specific location, or null if the block does not carry block data. + * Can be currently used to match specific information from it, or use it to copy to another block

+ *
+     *     block_data(x,y,z) => '{TransferCooldown:0,x:450,y:68, ... }'
+     * 
*

solid(pos)

*

Boolean function, true if the block is solid

*

air(pos)

@@ -904,6 +925,87 @@ public class CarpetExpression } + /** + *

Inventory and Items API

+ *
+ *

Manipulating inventories of blocks and entities

+ *

Most functions in this category require inventory as the first argument. Inventory could be specified by + * an entity, or a block, or position (three coordinates) of a potential block with inventory. + * If the entity or a block doesn't + * have an inventory, they typically do nothing and return null.

+ *

Most items returned are in the form of + * a triple of item name, count, and nbt or the extra data associated with an item. + * Manipulating of the nbt data can be costly, but retrieving them from the tuple to match other aspects is cheap

+ *

stack_limit(item)

+ *

Returns number indicating what is the stack limit for the item. Its typically 1 (non-stackable), + * 16 (like buckets), or 64 - rest. It is recommended to consult this, as other inventory API functions + * ignore normal stack limits, and it is up to the programmer to keep it at bay. As of 1.13, game checks for negative + * numbers and setting an item to negative is the same as empty.

+ *
+     *     stack_limit('wooden_axe') => 1
+     *     stack_limit('ender_pearl') => 16
+     *     stack_limit('stone') => 64
+     * 
+ *

inventory_size(inventory)

+ *

Returns the size of the inventory for the entity or block in question. Returns null if the block or entity + * don't have an inventory

+ *
+     *     inventory_size(player()) => 41
+     *     inventory_size(x,y,z) => 27 // chest
+     *     inventory_size(block(pos)) => 5 // hopper
+     * 
+ *

inventory_get(inventory, slot)

+ *

Returns the item in the corresponding inventory slot, or null if slot empty or inventory is invalid. + * You can use negative numbers to indicate slots counted from 'the back'.

+ *
+     *     inventory_get(player(), 0) => null // nothing in first hotbar slot
+     *     inventory_get(x,y,z, 5) => ['stone', 1, {}]
+     *     inventory_get(player(), -1) => ['diamond_pickaxe', 1, {Damage:4}] // slightly damaged diamond pick in the offhand
+     * 
+ * + *

inventory_set(inventory, slot, count, item?, nbt?)

+ *

Modifies or sets a stack in inventory. specify count 0 to empty the slot. + * If item is not specified, keeps existing item, just modifies the count. If item is provided - replaces current item. + * If nbt is provided - adds a tag to the stack at slot. Returns previous stack in that slot.

+ *
+     *     inventory_set(player(), 0, 0) => ['stone', 64, {}] // player had a stack of stone in first hotbar slot
+     *     inventory_set(player(), 0, 6) => ['diamond', 64, {}] // changed stack of diamonds in player slot to 6
+     *     inventory_set(player(), 0, 1, 'diamond_axe','{Damage:5}') => null //added slightly damaged pick to first player slot
+     * 
+ * + *

inventory_find(inventory, item, start_slot?, ), inventory_find(inventory, null, start_slot?)

+ *

Finds the first slot with a corresponding item in the inventory, or if queried with null: the first empty slot. + * Returns slot number if found, or null otherwise. Optional start_slot argument allows to skip all preceeding slots + * allowing for efficient (so not slot-by-slot) inventory search for items.

+ *
+     *     inventory_find(player(), 'stone') => 0 // player has stone in first hotbar slot
+     *     inventory_find(player(), null) => null // player's inventory has no empty spot
+     *     while( (slot = inventory_find(p, 'diamond', slot)) != null, 41, drop_item(p, slot) )
+     *         // spits all diamonds from player inventory wherever they are
+     *     inventory_drop(x,y,z, 0) => 64 // removed and spawned in the world a full stack of items
+     * 
+ * + *

inventory_remove(inventory, item, amount?)

+ *

Removes amount (defaults to 1) of item from inventory. If the inventory doesn't have the defined amount, nothing + * happens, otherwise the given amount of items is removed wherever they are in the inventory. Returns boolean whether + * the removal operation was successful. Easiest way to remove a specific item from player inventory without specifying + * the slot.

+ *
+     *     inventory_remove(player(), 'diamond') => 1 // removed diamond from player inventory
+     *     inventory_remove(player(), 'diamond', 100) => 0 // player doesn't have 100 diamonds, nothing happened
+     * 
+ * + *

drop_item(inventory, slot, amount?, )

+ *

Drops the items from indicated inventory slot, like player that Q's an item or villager, that exchanges food. + * You can Q items from block inventories as well. default amount is 0 - which is all from the slot. NOTE: hoppers are quick + * enough to pick all the queued items from their inventory anyways. + * Returns size of the actual dropped items.

+ *
+     *     inventory_drop(player(), 0, 1) => 1 // Q's one item on the ground
+     *     inventory_drop(x,y,z, 0) => 64 // removed and spawned in the world a full stack of items
+     * 
+ *
+ */ public void API_InventoryManipulation() { this.expr.addLazyFunction("stack_limit", 1, (c, t, lv) -> @@ -948,58 +1050,59 @@ public class CarpetExpression return (_c, _t) -> res; }); - //inventory_drop(, , ) -> entity_item (and sets slot) or null if cannot - this.expr.addLazyFunction("inventory_drop", -1, (c, t, lv) -> + //inventory_set(, , , , ) + this.expr.addLazyFunction("inventory_set", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); if (inventoryLocator == null) return (_c, _t) -> Value.NULL; - if (lv.size() == inventoryLocator.offset) - throw new InternalExpressionException("slot number is required for inventory_drop"); - int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); + if (lv.size() < inventoryLocator.offset+2) + throw new InternalExpressionException("inventory_set requires at least slot number and new stack size, and optional new item"); + int slot = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+0).evalValue(c)).getLong(); slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); if (slot == inventoryLocator.inventory.getInvSize()) return (_c, _t) -> Value.NULL; - int amount = 0; - if (lv.size() > inventoryLocator.offset+1) - amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); - if (amount < 0) - throw new InternalExpressionException("Cannot throw negative number of items"); - ItemStack stack = inventoryLocator.inventory.getInvStack(slot); - if (stack == null || stack.isEmpty()) - return (_c, _t) -> Value.ZERO; - if (amount == 0) - amount = stack.getCount(); - ItemStack droppedStack = inventoryLocator.inventory.takeInvStack(slot, amount); - if (droppedStack.isEmpty()) + int count = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); + if (count == 0) { - return (_c, _t) -> Value.ZERO; + // clear slot + ItemStack removedStack = inventoryLocator.inventory.removeInvStack(slot); + //Value res = ListValue.fromItemStack(removedStack); // that tuple will be read only but cheaper if noone cares + return (_c, _t) -> ListValue.fromItemStack(removedStack); } - Object owner = inventoryLocator.owner; - ItemEntity item; - if (owner instanceof PlayerEntity) - item = ((PlayerEntity) owner).dropItem(droppedStack, false, true); - else if (owner instanceof LivingEntity) + if (lv.size() < inventoryLocator.offset+3) { - LivingEntity villager = (LivingEntity)owner; - // stolen from LookTargetUtil.give((VillagerEntity)owner, droppedStack, (LivingEntity) owner); - double double_1 = villager.y - 0.30000001192092896D + (double)villager.getStandingEyeHeight(); - item = new ItemEntity(villager.world, villager.x, double_1, villager.z, droppedStack); - Vec3d vec3d_1 = villager.getRotationVec(1.0F).normalize().multiply(0.3);// new Vec3d(0, 0.3, 0); - item.setVelocity(vec3d_1); - item.setToDefaultPickupDelay(); + ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); + ItemStack newStack = previousStack.copy(); + newStack.setCount(count); + inventoryLocator.inventory.setInvStack(slot, newStack); + return (_c, _t) -> ListValue.fromItemStack(previousStack); } - else + CompoundTag nbt = null; // skipping one argument + if (lv.size() > inventoryLocator.offset+3) { - Vec3d point = new Vec3d(inventoryLocator.position); - item = new ItemEntity(cc.s.getWorld(), point.x+0.5, point.y+0.5, point.z+0.5, droppedStack); - item.setToDefaultPickupDelay(); + Value nbtValue = lv.get(inventoryLocator.offset+3).evalValue(c); + if (nbtValue instanceof NBTSerializableValue) + nbt = ((NBTSerializableValue)nbtValue).getTag(); + else + nbt = new NBTSerializableValue(nbtValue.getString()).getTag(); } - inventoryLocator.inventory.markDirty(); - cc.s.getWorld().spawnEntity(item); - Value res = new NumericValue(item.getStack().getCount()); - return (_c, _t) -> res; + ItemStackArgument newitem = NBTSerializableValue.parseItem( + lv.get(inventoryLocator.offset+2).evalValue(c).getString(), + nbt + ); + + ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); + try + { + inventoryLocator.inventory.setInvStack(slot, newitem.createStack(count, false)); + } + catch (CommandSyntaxException e) + { + throw new InternalExpressionException(e.getMessage()); + } + return (_c, _t) -> ListValue.fromItemStack(previousStack); }); //inventory_find(, or null (first empty slot), ) -> or null @@ -1034,60 +1137,7 @@ public class CarpetExpression return (_c, _t) -> Value.NULL; }); - //inventory_set(, , , , ) - this.expr.addLazyFunction("inventory_set", -1, (c, t, lv) -> - { - CarpetContext cc = (CarpetContext) c; - NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); - if (inventoryLocator == null) - return (_c, _t) -> Value.NULL; - if (lv.size() < inventoryLocator.offset+2) - throw new InternalExpressionException("inventory_set requires at least slot number and new stack size, and optional new item"); - int slot = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+0).evalValue(c)).getLong(); - slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); - if (slot == inventoryLocator.inventory.getInvSize()) - return (_c, _t) -> Value.NULL; - int count = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); - if (count == 0) - { - // clear slot - ItemStack removedStack = inventoryLocator.inventory.removeInvStack(slot); - //Value res = ListValue.fromItemStack(removedStack); // that tuple will be read only but cheaper if noone cares - return (_c, _t) -> ListValue.fromItemStack(removedStack); - } - if (lv.size() < inventoryLocator.offset+3) - { - ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); - ItemStack newStack = previousStack.copy(); - newStack.setCount(count); - inventoryLocator.inventory.setInvStack(slot, newStack); - return (_c, _t) -> ListValue.fromItemStack(previousStack); - } - CompoundTag nbt = null; - if (lv.size() >= inventoryLocator.offset+3) - { - Value nbtValue = lv.get(inventoryLocator.offset+3).evalValue(c); - if (nbtValue instanceof NBTSerializableValue) - nbt = ((NBTSerializableValue)nbtValue).getTag(); - else - nbt = new NBTSerializableValue(nbtValue.getString()).getTag(); - } - ItemStackArgument newitem = NBTSerializableValue.parseItem( - lv.get(inventoryLocator.offset+2).evalValue(c).getString(), - nbt - ); - ItemStack previousStack = inventoryLocator.inventory.getInvStack(slot); - try - { - inventoryLocator.inventory.setInvStack(slot, newitem.createStack(count, false)); - } - catch (CommandSyntaxException e) - { - throw new InternalExpressionException(e.getMessage()); - } - return (_c, _t) -> ListValue.fromItemStack(previousStack); - }); //inventory_remove(, , ) -> bool @@ -1134,6 +1184,63 @@ public class CarpetExpression throw new InternalExpressionException("Something bad happened - cannot pull all items from inventory"); return (_c, _t) -> Value.TRUE; }); + + //inventory_drop(, , ) -> entity_item (and sets slot) or null if cannot + this.expr.addLazyFunction("drop_item", -1, (c, t, lv) -> + { + CarpetContext cc = (CarpetContext) c; + NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); + if (inventoryLocator == null) + return (_c, _t) -> Value.NULL; + if (lv.size() == inventoryLocator.offset) + throw new InternalExpressionException("slot number is required for inventory_drop"); + int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); + slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); + if (slot == inventoryLocator.inventory.getInvSize()) + return (_c, _t) -> Value.NULL; + int amount = 0; + if (lv.size() > inventoryLocator.offset+1) + amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); + if (amount < 0) + throw new InternalExpressionException("Cannot throw negative number of items"); + ItemStack stack = inventoryLocator.inventory.getInvStack(slot); + if (stack == null || stack.isEmpty()) + return (_c, _t) -> Value.ZERO; + if (amount == 0) + amount = stack.getCount(); + ItemStack droppedStack = inventoryLocator.inventory.takeInvStack(slot, amount); + if (droppedStack.isEmpty()) + { + return (_c, _t) -> Value.ZERO; + } + Object owner = inventoryLocator.owner; + ItemEntity item; + if (owner instanceof PlayerEntity) + { + item = ((PlayerEntity) owner).dropItem(droppedStack, false, true); + } + else if (owner instanceof LivingEntity) + { + LivingEntity villager = (LivingEntity)owner; + // stolen from LookTargetUtil.give((VillagerEntity)owner, droppedStack, (LivingEntity) owner); + double double_1 = villager.y - 0.30000001192092896D + (double)villager.getStandingEyeHeight(); + item = new ItemEntity(villager.world, villager.x, double_1, villager.z, droppedStack); + Vec3d vec3d_1 = villager.getRotationVec(1.0F).normalize().multiply(0.3);// new Vec3d(0, 0.3, 0); + item.setVelocity(vec3d_1); + item.setToDefaultPickupDelay(); + cc.s.getWorld().spawnEntity(item); + } + else + { + Vec3d point = new Vec3d(inventoryLocator.position); + item = new ItemEntity(cc.s.getWorld(), point.x+0.5, point.y+0.5, point.z+0.5, droppedStack); + item.setToDefaultPickupDelay(); + cc.s.getWorld().spawnEntity(item); + } + inventoryLocator.inventory.markDirty(); + Value res = new NumericValue(item.getStack().getCount()); + return (_c, _t) -> res; + }); } @@ -1185,6 +1292,12 @@ public class CarpetExpression *

Unlike with blocks, that use plethora of vastly different querying functions, entities are queried with * query function and altered via modify function. Type of information needed or * values to be modified are different for each call

+ *

Using ~ (in) operator is an alias for query. Especially useful if a statement has + * no arguments, which in this case can be radically simplified

+ *
+     *     query(p, 'name') <=> p ~ 'name'     // much shorter and cleaner
+     *     query(p, 'holds', 'offhand') <=> p ~ l('holds', 'offhand')    // not really but can be done
+     * 
*

query(e,'removed')

*

Boolean. True if the entity is removed

*

query(e,'id')

@@ -1295,6 +1408,12 @@ public class CarpetExpression *
  • feet
  • * *

    If slot is not specified, it defaults to the main hand.

    + *

    query(e,'selected_slot')

    + *

    Number indicating the selected slot of entity inventory. Currently only applicable to players.

    + *

    query(e,'facing', order?)

    + *

    Returns where the entity is facing. optional order (number from 0 to 5, and negative), indicating + * primary directions where entity is looking at. From most prominent (order 0) to opposite (order 5, or -1)

    + * *

    query(e,'nbt',path?)

    *

    Returns full NBT of the entity. If path is specified, it fetches only that portion of the NBT, * that corresponds to the path. For specification of path attribute, consult @@ -2419,6 +2538,7 @@ public class CarpetExpression *

    The last method is the one that world edit is using (part of carpet mod). It turns out that the outline method with 32.5 radius, * fill method with round function and draw command are equivalent

    * + * @param host . * @param x . * @param y . * @param z . @@ -2461,12 +2581,14 @@ public class CarpetExpression /** *

    /script run command

    *
    - *

    primary way to input commands. The command executes in the context, position, and dimension of the executing + *

    Primary way to input commands. The command executes in the context, position, and dimension of the executing * player, commandblock, etc... The command receives 4 variables, x, y, z * and p indicating position and the executing entity of the command. + * You will receive tab completion suggestions as you type your code suggesting functions and global variables. * It is advisable to use /execute in ... at ... as ... run script run ... or similar, to simulate running * commands in a different scope

    *
    + * @param host . * @param pos . * @return . */ diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 2468efef..fe02649a 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -859,9 +859,10 @@ public class Expression implements Cloneable *

    Ability to combine more statements into one expression, with functions, passing parameters, and global and outer * scoping allow to organize even larger scripts

    *

    Control flow

    - *

    return(expr)

    + *

    return(expr?)

    *

    Sometimes its convenient to break the organized control flow, or it is not practical to pass * the final result value of a function to the last statement, in this case a return statement can be used

    + *

    If no argument is provided - returns null value.

    *
          * def() -> (
          *  expr1;
    @@ -873,12 +874,14 @@ public class Expression implements Cloneable
          * 
    *

    In general its cheaper to leave the last expression as a return value, rather than calling returns everywhere, * but it would often lead to a messy code.

    - *

    exit(expr)

    - *

    It terminates entire program passing expr as the result of the program execution.

    - *

    try(expr, catch_expr(_)) ... throw(value)

    + *

    exit(expr?)

    + *

    It terminates entire program passing expr as the result of the program execution, or null if omitted.

    + *

    try(expr, catch_expr(_)?) ... throw(value?)

    *

    try function evaluates expression, and continues further unless throw function is called * anywhere inside expr. In that case the catch_expr is evaluates with _ set - * to the argument throw was called with. This mechanism allows to terminate large portion of a convoluted + * to the argument throw was called with. + * This mechanic accepts skipping thrown value - it throws null instead, and catch expression - then try returns null as well + * This mechanism allows to terminate large portion of a convoluted * call stack and continue program execution. There is only one level of exceptions currently in carpet, so if the inner * function also defines the try catchment area, it will received the exception first, but it can technically * rethrow the value its getting for the outer scope. Unhandled throw acts like an exit statement.

    @@ -1620,15 +1623,15 @@ public class Expression implements Cloneable * range(20, 10, -2) => [20, 18, 16, 14, 12] * * - *

    element(list, index)

    + *

    get(list, index), element(list, index)(deprecated)

    *

    Returns the value at index element from the list. - * use negative numbers to reach elements from the end of the list. element + * use negative numbers to reach elements from the end of the list. get * call will always be able to find the index. In case there is few items, it will loop over

    *
    -     *     element(l(range(10)), 5)  => 5
    -     *     element(l(range(10)), -1)  => 9
    -     *     element(l(range(10)), 10)  => 0
    -     *     element(l(range(10)), 93)  => 3
    +     *     get(l(range(10)), 5)  => 5
    +     *     get(l(range(10)), -1)  => 9
    +     *     get(l(range(10)), 10)  => 0
    +     *     get(l(range(10)), 93)  => 3
          * 
    * *

    put(list, index, values ...), put(list, null, values ...)

    diff --git a/src/main/java/carpet/script/value/BlockValue.java b/src/main/java/carpet/script/value/BlockValue.java index 2fa1dee6..d08097ef 100644 --- a/src/main/java/carpet/script/value/BlockValue.java +++ b/src/main/java/carpet/script/value/BlockValue.java @@ -298,7 +298,7 @@ public class BlockValue extends Value DOWNNORTH ("down-north", 0.5, 1.0, 0.4, Direction.DOWN), DOWNSOUTH ("down-south", 0.5, 1.0, 0.6, Direction.DOWN), - DOWNEAST("dow-neast", 0.6, 1.0, 0.5, Direction.DOWN), + DOWNEAST("down-east", 0.6, 1.0, 0.5, Direction.DOWN), DOWNWEST("down-west", 0.4, 1.0, 0.5, Direction.DOWN), diff --git a/src/main/java/carpet/settings/Validator.java b/src/main/java/carpet/settings/Validator.java index 8d0ea4e2..66ca79cf 100644 --- a/src/main/java/carpet/settings/Validator.java +++ b/src/main/java/carpet/settings/Validator.java @@ -47,7 +47,7 @@ public abstract class Validator if (source != null) try { - Messenger.m(source, "r "+currentRule.name+" not yet fully implemented - we are still working on it."); + Messenger.m(source, "r "+currentRule.name+" is not yet fully implemented - we are still working on it."); } catch (NullPointerException ignored) { } return newValue;