diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index efc638e8..47e2c59c 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -2661,7 +2661,7 @@ Adds a vector to the motion vector. Most realistic way to apply a force to an en ### `modify(e, 'age', number)` -Modifies entity's internal age counter. Fiddling with this will affect directly behaviours of complex +Modifies entity's internal age counter. Fiddling with this will affect directly AI behaviours of complex entities, so use it with caution. ### `modify(e, 'pickup_delay', number)` @@ -2719,6 +2719,35 @@ and `true`. If no duration is specified, or it is null or 0, the effect is remov 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. +### `modify(e, 'gamemode', gamemode?), modify(e, 'gamemode',gamemode_id?)` + +Modifies gamemode of player to whatever string (case-insensitive) or number you put in. + +* 0: survival +* 1: creative +* 2: adventure +* 3: spectator + +### `modify(e, 'jumping', true/false)` + +Will make the entity constantly jump if set to true, and will stop the entity from jumping if set to false. +Note that jumping parameter can be fully controlled by the entity AI, so don't expect that this will have +a permanent effect. Use `'jump'` to make an entity jump once for sure. + +Requires a living entity as an argument. + +### `modify(e, 'jump'))` + +Will make the entity jump once. + +### `modify(e, 'silent', true/false)` + +### `modify(e, 'gravity', true/false)` + +### `modify(e, 'fire', ticks)` + +Will set mob on fire for `ticks` ticks. Set to 0 to extinguish. + ## 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. @@ -3062,7 +3091,7 @@ And colors: * `e` - grEEn * `v` - naVy blue * `k` - blaK - * `#FFAACC` - arbitrary RGB color (1.16+), hex notation + * `#FFAACC` - arbitrary RGB color (1.16+), hex notation. Use uppercase for A-F symbols Decorators (listed as extra argument after the component they would affect): * `'^ '` - hover over tooltip text, appearing when hovering with your mouse over the text below. diff --git a/docs/scarpet/api/Entities.md b/docs/scarpet/api/Entities.md index 9b808752..a0dec45d 100644 --- a/docs/scarpet/api/Entities.md +++ b/docs/scarpet/api/Entities.md @@ -400,7 +400,7 @@ Adds a vector to the motion vector. Most realistic way to apply a force to an en ### `modify(e, 'age', number)` -Modifies entity's internal age counter. Fiddling with this will affect directly behaviours of complex +Modifies entity's internal age counter. Fiddling with this will affect directly AI behaviours of complex entities, so use it with caution. ### `modify(e, 'pickup_delay', number)` @@ -458,6 +458,35 @@ and `true`. If no duration is specified, or it is null or 0, the effect is remov 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. +### `modify(e, 'gamemode', gamemode?), modify(e, 'gamemode',gamemode_id?)` + +Modifies gamemode of player to whatever string (case-insensitive) or number you put in. + +* 0: survival +* 1: creative +* 2: adventure +* 3: spectator + +### `modify(e, 'jumping', true/false)` + +Will make the entity constantly jump if set to true, and will stop the entity from jumping if set to false. +Note that jumping parameter can be fully controlled by the entity AI, so don't expect that this will have +a permanent effect. Use `'jump'` to make an entity jump once for sure. + +Requires a living entity as an argument. + +### `modify(e, 'jump'))` + +Will make the entity jump once. + +### `modify(e, 'silent', true/false)` + +### `modify(e, 'gravity', true/false)` + +### `modify(e, 'fire', ticks)` + +Will set mob on fire for `ticks` ticks. Set to 0 to extinguish. + ## 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. diff --git a/docs/scarpet/resources/editors/idea/2.txt b/docs/scarpet/resources/editors/idea/2.txt index edcf56fb..f12cde37 100644 --- a/docs/scarpet/resources/editors/idea/2.txt +++ b/docs/scarpet/resources/editors/idea/2.txt @@ -25,6 +25,7 @@ entity_list entity_selector escape_nbt flammable +format game_tick generation_status hardness diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml index 8ad6f2ea..33be1144 100644 --- a/docs/scarpet/resources/editors/npp/scarpet.xml +++ b/docs/scarpet/resources/editors/npp/scarpet.xml @@ -65,7 +65,7 @@ scan volume neighbours rect diamond - logger sound particle particle_line particle_rect + format logger sound particle particle_line particle_rect run save tick_time world_time day_time last_tick_times game_tick seed current_dimension in_dimension diff --git a/src/main/java/carpet/fakes/LivingEntityInterface.java b/src/main/java/carpet/fakes/LivingEntityInterface.java new file mode 100644 index 00000000..2dba302e --- /dev/null +++ b/src/main/java/carpet/fakes/LivingEntityInterface.java @@ -0,0 +1,7 @@ +package carpet.fakes; + +public interface LivingEntityInterface +{ + void doJumpCM(); // added CM suffix to remove potential collisions with other mods + boolean isJumpingCM(); +} diff --git a/src/main/java/carpet/mixins/LivingEntity_scarpetEventsMixin.java b/src/main/java/carpet/mixins/LivingEntity_scarpetEventsMixin.java index 8ca20980..456b9b74 100644 --- a/src/main/java/carpet/mixins/LivingEntity_scarpetEventsMixin.java +++ b/src/main/java/carpet/mixins/LivingEntity_scarpetEventsMixin.java @@ -1,6 +1,7 @@ package carpet.mixins; import carpet.fakes.EntityInterface; +import carpet.fakes.LivingEntityInterface; import carpet.script.EntityEventsGroup; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -8,14 +9,19 @@ import net.minecraft.entity.LivingEntity; import net.minecraft.entity.damage.DamageSource; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(LivingEntity.class) -public abstract class LivingEntity_scarpetEventsMixin extends Entity +public abstract class LivingEntity_scarpetEventsMixin extends Entity implements LivingEntityInterface { + @Shadow protected abstract void jump(); + + @Shadow protected boolean jumping; + public LivingEntity_scarpetEventsMixin(EntityType type, World world) { super(type, world); @@ -26,4 +32,16 @@ public abstract class LivingEntity_scarpetEventsMixin extends Entity { ((EntityInterface)this).getEventContainer().onEvent(EntityEventsGroup.EntityEventType.ON_DEATH, this, damageSource_1.name); } + + @Override + public void doJumpCM() + { + jump(); + } + + @Override + public boolean isJumpingCM() + { + return jumping; + } } diff --git a/src/main/java/carpet/script/value/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java index f92ec87f..525fd55f 100644 --- a/src/main/java/carpet/script/value/EntityValue.java +++ b/src/main/java/carpet/script/value/EntityValue.java @@ -2,6 +2,7 @@ package carpet.script.value; import carpet.fakes.EntityInterface; import carpet.fakes.ItemEntityInterface; +import carpet.fakes.LivingEntityInterface; import carpet.fakes.MobEntityInterface; import carpet.helpers.Tracer; import carpet.patches.EntityPlayerMPFake; @@ -45,6 +46,7 @@ import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.Registry; +import net.minecraft.world.GameMode; import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; @@ -60,6 +62,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import static carpet.script.value.NBTSerializableValue.nameFromRegistryId; +import static carpet.utils.MobAI.genericJump; // TODO: decide whether copy(entity) should duplicate entity in the world. public class EntityValue extends Value @@ -279,13 +282,13 @@ public class EntityValue extends Value 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); - /*put("jumping", (e, a) -> { + put("jumping", (e, a) -> { if (e instanceof LivingEntity) { - return ((LivingEntity) e).getJumping()?Value.TRUE:Value.FALSE; + return ((LivingEntityInterface) e).isJumpingCM()?Value.TRUE:Value.FALSE; } return Value.NULL; - });*/ //needs mixing + }); put("gamemode", (e, a) -> { if (e instanceof ServerPlayerEntity) { @@ -374,6 +377,7 @@ public class EntityValue extends Value StatusEffectInstance pe = ((LivingEntity) e).getStatusEffect(potion); return ListValue.of( new NumericValue(pe.getAmplifier()), new NumericValue(pe.getDuration()) ); }); + put("health", (e, a) -> { if (e instanceof LivingEntity) @@ -529,8 +533,6 @@ public class EntityValue extends Value //((ServerWorld)e.getEntityWorld()).method_14178().sendToNearbyPlayers(e, new EntityVelocityUpdateS2CPacket(e)); } - - private static final Map> featureModifiers = new HashMap>() {{ put("remove", (entity, value) -> entity.remove()); put("age", (e, v) -> e.age = Math.abs((int)NumericValue.asNumber(v).getLong()) ); @@ -876,7 +878,7 @@ public class EntityValue extends Value { le.removeStatusEffect(effect); return; - } + } int amplifier = 0; if (lv.size() > 2) amplifier = (int)NumericValue.asNumber(lv.get(2)).getLong(); @@ -893,21 +895,61 @@ public class EntityValue extends Value throw new InternalExpressionException("'effect' needs either no arguments (clear) or effect name, duration, and optional amplifier, show particles and show icon"); }); - // gamemode - // spectate - // "fire" - // "extinguish" - // "silent" - // "gravity" - // "invulnerable" - // "dimension" - // "item" - // "count", - // "age", - // "effect_"name - // "hold" - // "hold_offhand" - // "jump" + put("gamemode", (e,v)->{ + if(!(e instanceof ServerPlayerEntity)) return; + GameMode toSet = v instanceof NumericValue ? + GameMode.byId(((NumericValue) v).getInt(), null) : + GameMode.byName(v.getString().toLowerCase(Locale.ROOT), null); + if (toSet != null) ((ServerPlayerEntity) e).setGameMode(toSet); + }); + + put("jumping",(e,v)->{ + if(!(e instanceof LivingEntity)) return; + ((LivingEntity) e).setJumping(v.getBoolean()); + }); + + put("jump",(e,v)->{ + if (e instanceof LivingEntity) + { + ((LivingEntityInterface)e).doJumpCM(); + } + else + { + genericJump(e); + } + }); + + put("silent",(e,v)->{ + e.setSilent(v.getBoolean()); + }); + + put("gravity",(e,v)->{ + e.setNoGravity(!v.getBoolean()); + }); + + put("invulnerable",(e,v)->{ + e.setInvulnerable(v.getBoolean()); + }); + + put("fire",(e,v)->{ + e.setFireTicks((int)NumericValue.asNumber(v).getLong()); + }); + + // gamemode [check] + // spectate [check] + // "fire" [check] + // "extinguish" [set fire ticks to 0] + // "silent" [check] + // "gravity" [check] + // "invulnerable" [check] + // "dimension" [] + // "item" [] + // "count", [] + // "age", [check] + // "effect_"name [] + // "hold" [inventory_set?] + // "hold_offhand" [inventory_set?] + // "jump" [check] // "nbt" <-big one, for now use run('data merge entity ... }}; diff --git a/src/main/java/carpet/utils/MobAI.java b/src/main/java/carpet/utils/MobAI.java index 0a202b16..dc4b3e03 100644 --- a/src/main/java/carpet/utils/MobAI.java +++ b/src/main/java/carpet/utils/MobAI.java @@ -4,7 +4,13 @@ import carpet.CarpetServer; import com.google.common.collect.Sets; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffects; import net.minecraft.server.world.ServerWorld; +import net.minecraft.tag.FluidTags; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.Registry; import java.util.HashMap; @@ -93,4 +99,25 @@ public class MobAI } } + /** + * Not a replacement for living entity jump() - this barely is to allow other entities that can't jump in vanilla to 'jump' + * @param e + */ + public static void genericJump(Entity e) + { + if (!e.onGround && !e.isInFluid(FluidTags.WATER) && !e.isInLava()) return; + float m = e.world.getBlockState(new BlockPos(e)).getBlock().getJumpVelocityMultiplier(); + float g = e.world.getBlockState(new BlockPos(e.getX(), e.getBoundingBox().y1 - 0.5000001D, e.getZ())).getBlock().getJumpVelocityMultiplier(); + float jumpVelocityMultiplier = (double) m == 1.0D ? g : m; + float jumpStrength = (0.42F * jumpVelocityMultiplier); + Vec3d vec3d = e.getVelocity(); + e.setVelocity(vec3d.x, jumpStrength, vec3d.z); + if (e.isSprinting()) + { + float u = e.yaw * 0.017453292F; + e.setVelocity(e.getVelocity().add((-MathHelper.sin(g) * 0.2F), 0.0D, (MathHelper.cos(u) * 0.2F))); + } + e.velocityDirty = true; + } + }