diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index 478888a7..fd87a05d 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -62,7 +62,7 @@ or an OVERLY complex example: or simply
-/script run print('There is'+for(rect(x,9,z,8,8,8), _ == 'diamond_ore')+' diamond ore around you')
+/script run print('There is '+for(rect(x,9,z,8,8,8), _ == 'diamond_ore')+' diamond ore around you')
It definitely pays to check what higher level `scarpet` functions have to offer.
@@ -112,16 +112,17 @@ Or rather:
if
-(
- x<y+6,
+( x<y+6,
(
set(x,8+y,z,'air');
plop(x,top('surface',x,z),z,'birch')
),
+ // else if
sin(query(player(),'yaw'))>0.5,
(
plop(0,0,0,'boulder')
),
+ // else
particle('fire',x,y,z)
)
@@ -134,8 +135,10 @@ have problems with them
## Functions and scoping
Users can define functions in the form `fun(args....) -> expression` and they are compiled and saved for further
-execution in this but also subsequent calls of /script command. Functions can also be assigned to variables,
-passed as arguments, called with `call` function, but in most cases you would want to call them directly by
+execution in this, but also subsequent calls of /script command, added to events, etc. Functions can also be
+ assigned to variables,
+passed as arguments, called with `call('fun', args...)` function, but in most cases you would want to
+call them directly by
name, in the form of `fun(args...)`. This means that once defined functions are saved with the world for
further use. For variables, there are two types of them, global - which are shared anywhere in the code,
and those are all which name starts with 'global_', and local variables which is everything else and those
@@ -690,10 +693,10 @@ number('2')+number('2') => 4
Returns a formatted string representing expression. Accepts formatting style accepted by `String.format`.
Supported types (with `"%?"` syntax):
-* d, o, x: integers
-* a, e, f, g: floats
-* b: booleans
-* s: strings
+* `d`, `o`, `x`: integers, octal, hex
+* `a`, `e`, `f`, `g`: floats
+* `b`: booleans
+* `s`: strings
str(null) => null
@@ -720,7 +723,8 @@ the off-tick time in between ticks that didn't take 50ms. There are however bene
like fine time control not relying on the tick clock, or running things independent on each other. You can still run
your actions on tick-by-tick basis, either taking control of the execution using `game_tick()` API function
(nasty solution), or scheduling tick using `schedule()` function (much nicer solution), but threading often gives
-the neatest solution to solve problems in parallel (see scarpet camera).
+the neatest solution to solve problems in parallel
+(see [scarpet camera](/src/main/resources/assets/carpet/scripts/camera.sc)).
Due to limitations with the game, there are some limits to the threading as well. You cannot for
instance `join_task()` at all from the main script and server thread, because any use of Minecraft specific
@@ -2298,6 +2302,17 @@ Returns mob's attack target or null if none or not applicable.
Returns creature's home position or null if none or not applicable.
+### `query(e, 'pose')`
+
+Returns a pose of an entity, one of the following options
+ * `'standing'`
+ * `'fall_flying'`
+ * `'sleeping'`
+ * `'swimming'`
+ * `'spin_attack'`
+ * `'crouching'`
+ * `'dying'`
+
### `query(e,'sneaking')`
Boolean, true if entity is sneaking.
diff --git a/docs/scarpet/api/Entities.md b/docs/scarpet/api/Entities.md
index 921b9e89..623fd37c 100644
--- a/docs/scarpet/api/Entities.md
+++ b/docs/scarpet/api/Entities.md
@@ -218,6 +218,17 @@ Returns mob's attack target or null if none or not applicable.
Returns creature's home position or null if none or not applicable.
+### `query(e, 'pose')`
+
+Returns a pose of an entity, one of the following options
+ * `'standing'`
+ * `'fall_flying'`
+ * `'sleeping'`
+ * `'swimming'`
+ * `'spin_attack'`
+ * `'crouching'`
+ * `'dying'`
+
### `query(e,'sneaking')`
Boolean, true if entity is sneaking.
diff --git a/src/main/java/carpet/mixins/SpawnHelperMixin.java b/src/main/java/carpet/mixins/SpawnHelperMixin.java
index 52caca33..9f7645e5 100644
--- a/src/main/java/carpet/mixins/SpawnHelperMixin.java
+++ b/src/main/java/carpet/mixins/SpawnHelperMixin.java
@@ -4,6 +4,8 @@ import carpet.CarpetSettings;
import carpet.fakes.WorldInterface;
import carpet.utils.SpawnReporter;
import net.minecraft.block.Block;
+import net.minecraft.block.BlockState;
+import net.minecraft.block.FenceGateBlock;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCategory;
import net.minecraft.entity.EntityData;
@@ -13,6 +15,7 @@ import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.world.ServerWorld;
+import net.minecraft.tag.BlockTags;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
@@ -45,30 +48,78 @@ public class SpawnHelperMixin
// various configurations, but solid and 'passable' blocks, like air, water grass, etc.
// checking if in the BB of the entity are only passable blocks is very cheap and covers most cases
// in case something more complex happens - we default to full block collision check
- if (CarpetSettings.lagFreeSpawning)
+ if (!CarpetSettings.lagFreeSpawning)
{
- BlockPos.Mutable blockpos = new BlockPos.Mutable();
- int minX = MathHelper.floor(bb.x1);
- int maxX = MathHelper.ceil(bb.x2);
- int minY = MathHelper.floor(bb.y1);
- int maxY = MathHelper.ceil(bb.y2);
- int minZ = MathHelper.floor(bb.z1);
- int maxZ = MathHelper.ceil(bb.z2);
- for (int y = minY; y < maxY; y++)
- for (int x = minX; x < maxX; x++)
- for (int z = minZ; z < maxZ; z++)
+ return world.doesNotCollide(bb);
+ }
+ int minX = MathHelper.floor(bb.x1);
+ int minY = MathHelper.floor(bb.y1);
+ int minZ = MathHelper.floor(bb.z1);
+ int maxY = MathHelper.ceil(bb.y2)-1;
+ BlockPos.Mutable blockpos = new BlockPos.Mutable();
+ if (bb.getXLength() <= 1) // small mobs
+ {
+ for (int y=minY; y <= maxY; y++)
+ {
+ blockpos.set(minX,y,minZ);
+ VoxelShape box = world.getBlockState(blockpos).getCollisionShape(world, blockpos);
+ if (box != VoxelShapes.empty())
+ {
+ if (box == VoxelShapes.fullCube())
+ {
+ return false;
+ }
+ else
{
- blockpos.set(x, y, z);
- VoxelShape box = world.getBlockState(blockpos).getCollisionShape(world, blockpos);
- if ( box == VoxelShapes.empty())
- continue;
- if (Block.isShapeFullCube(box))
- return false;
return world.doesNotCollide(bb);
}
+ }
+ }
return true;
}
- return world.doesNotCollide(bb);
+ // this code is only applied for mobs larger than 1 block in footprint
+ int maxX = MathHelper.ceil(bb.x2)-1;
+ int maxZ = MathHelper.ceil(bb.z2)-1;
+ for (int y = minY; y <= maxY; y++)
+ for (int x = minX; x <= maxX; x++)
+ for (int z = minZ; z <= maxZ; z++)
+ {
+ blockpos.set(x, y, z);
+ VoxelShape box = world.getBlockState(blockpos).getCollisionShape(world, blockpos);
+ if (box != VoxelShapes.empty())
+ {
+ if (box == VoxelShapes.fullCube())
+ {
+ return false;
+ }
+ else
+ {
+ return world.doesNotCollide(bb);
+ }
+ }
+ }
+ int min_below = minY - 1;
+ // we need to check blocks below for extended hitbox and in that case call
+ // only applies to 'large mobs', slimes, spiders, magmacubes, ghasts, etc.
+ for (int x = minX; x <= maxX; x++)
+ {
+ for (int z = minZ; z <= maxZ; z++)
+ {
+ blockpos.set(x, min_below, z);
+ BlockState state = world.getBlockState(blockpos);
+ Block block = state.getBlock();
+ if (
+ block.matches(BlockTags.FENCES) ||
+ block.matches(BlockTags.WALLS) ||
+ ((block instanceof FenceGateBlock) && !state.get(FenceGateBlock.OPEN))
+ )
+ {
+ if (x == minX || x == maxX || z == minZ || z == maxZ) return world.doesNotCollide(bb);
+ return false;
+ }
+ }
+ }
+ return true;
}
@Redirect(method = "spawnEntitiesInChunk", at = @At(
diff --git a/src/main/java/carpet/script/value/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java
index c97ad102..4088478a 100644
--- a/src/main/java/carpet/script/value/EntityValue.java
+++ b/src/main/java/carpet/script/value/EntityValue.java
@@ -33,7 +33,6 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
-import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.LiteralText;
@@ -53,8 +52,8 @@ import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
-import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Predicate;
@@ -274,6 +273,7 @@ public class EntityValue extends Value
}
return Value.NULL;
});
+ put("pose", (e, a) -> new StringValue(e.getPose().name().toLowerCase(Locale.ROOT)));
put("sneaking", (e, a) -> e.isSneaking()?Value.TRUE:Value.FALSE);
put("sprinting", (e, a) -> e.isSprinting()?Value.TRUE:Value.FALSE);
put("swimming", (e, a) -> e.isSwimming()?Value.TRUE:Value.FALSE);