added create_explosion and more event handlers.

This commit is contained in:
gnembon committed 2021-04-09 01:38:00 -03:00
1 parent 7b00952653
commit e063748e83
12 files changed
+226 -31

No files matched your search

+7
View File
@@ -229,6 +229,13 @@ Causes a block to be harvested by a specified player entity. Honors player item
tool if applicable. If the entity is not a valid player, no block gets destroyed. If a player is not allowed to break tool if applicable. If the entity is not a valid player, no block gets destroyed. If a player is not allowed to break
that block, a block doesn't get destroyed either. that block, a block doesn't get destroyed either.
### `create_explosion(pos, power?, mode?, fire?, source?, attacker?)`
Creates an explosion at a given position. Default values of optional parameters are: `'power'` - `4` (TNT power),
`'mode'` (block breaking effect `none`, `destroy` or `break`: `break`, `fire` (whether extra fire blocks should be created) - `false`,
`source` (exploding entity) - `null` and `attacker` (entity responsible for trigerring) - `null`. Explosions created with this
endpoint cannot be captured with `__on_explosion` event, however they will be captured by `__on_explosion_outcome`.
### `weather()`,`weather(type)`,`weather(type, ticks)` ### `weather()`,`weather(type)`,`weather(type, ticks)`
If called with no args, returns `'clear'`, `'rain` or `'thunder'` based on the current weather. If thundering, will If called with no args, returns `'clear'`, `'rain` or `'thunder'` based on the current weather. If thundering, will
+11 -3
View File
@@ -79,10 +79,18 @@ at the same time.
Triggered right after a lightning strikes. Lightning entity as well as potential horseman trap would Triggered right after a lightning strikes. Lightning entity as well as potential horseman trap would
already be spawned at that point. `mode` is `true` if the lightning did cause a trap to spawn. already be spawned at that point. `mode` is `true` if the lightning did cause a trap to spawn.
### `__on_explosion(pos, power, source, create_fire, blocks, entities)` ### `__on_explosion(pos, power, source, causer, mode, fire)`
Triggered right before an explosion blows up and any changes to the blocks are done, but the decision to blow up is already made and entities are already affected.
Event triggered right before explosion takes place and before has any effect on the world. `source` can be an entity causing
the explosion, and `causer` the entity triggering it,
`mode` indicates block effects: `'none'`, `'break'` (drop all blocks), or `'destroy'` - drop few blocks. Event
is not captured when `create_explosion()` is called.
### `__on_explosion_outcome(pos, power, source, causer, mode, fire, blocks, entities)`
Triggered during the explosion, before any changes to the blocks are done,
but the decision to blow up is already made and entities are already affected.
The parameter `blocks` contains the list of blocks that will blow up (empty if `explosionNoBlockDamage` is set to `true`). The parameter `blocks` contains the list of blocks that will blow up (empty if `explosionNoBlockDamage` is set to `true`).
The parameter `entities` contains the list of entities that have been affected by the explosion. The parameter `entities` contains the list of entities that have been affected by the explosion. Triggered even with `create_explosion()`.
### `__on_carpet_rule_changes(rule, new_value)` ### `__on_carpet_rule_changes(rule, new_value)`
Triggered when a carpet mod rule is changed. It includes extension rules, not using default `/carpet` command, Triggered when a carpet mod rule is changed. It includes extension rules, not using default `/carpet` command,
@@ -18,6 +18,7 @@ chunk_tickets
convert_date convert_date
crafting_remaining_item crafting_remaining_item
create_datapack create_datapack
create_explosion
create_marker create_marker
current_dimension current_dimension
day_time day_time
+2 -1
View File
@@ -43,4 +43,5 @@ __on_player_dies(player) ->
__on_player_respawns(player) -> __on_player_respawns(player) ->
__on_player_disconnects(player, reason) -> __on_player_disconnects(player, reason) ->
__on_player_connects(player) -> __on_player_connects(player) ->
__on_explosion(pos, power, source, create_fire, blocks, entities) -> __on_explosion(pos, power, source, causer, mode, fire) ->
__on_explosion_outcome(pos, power, source, causer, mode, fire, blocks, entities) ->
@@ -55,7 +55,9 @@
set without_updates set without_updates
blocks_movement block_sound material map_colour block_state block_list block_tags 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 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 create_datapack enable_hidden_dimensions plop harvest destroy create_explosion
structure_eligibility structures structure_references set_structure
reset_chunk reload_chunk create_datapack enable_hidden_dimensions
add_chunk_ticket add_chunk_ticket
convert_date unix_time convert_date unix_time
@@ -82,7 +84,7 @@
run save tick_time world_time day_time last_tick_times game_tick current_dimension in_dimension view_distance run save tick_time world_time day_time last_tick_times game_tick current_dimension in_dimension view_distance
plop harvest destroy schedule nbt draw_shape create_marker remove_all_markers schedule nbt draw_shape create_marker remove_all_markers
load_app_data store_app_data read_file write_file delete_file list_files load_app_data store_app_data read_file write_file delete_file list_files
escape_nbt parse_nbt encode_nbt tag_matches statistic escape_nbt parse_nbt encode_nbt tag_matches statistic
@@ -140,6 +142,7 @@
__on_player_disconnects __on_player_disconnects
__on_player_connects __on_player_connects
__on_explosion __on_explosion
__on_explosion_outcome
</Keywords> </Keywords>
<Keywords name="Keywords8">$</Keywords> <Keywords name="Keywords8">$</Keywords>
<Keywords name="Delimiters">00&apos; 01\ 02&apos; 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23</Keywords> <Keywords name="Delimiters">00&apos; 01\ 02&apos; 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23</Keywords>
@@ -10,13 +10,10 @@ import java.util.List;
import carpet.logging.logHelpers.ExplosionLogHelper; import carpet.logging.logHelpers.ExplosionLogHelper;
import carpet.mixins.ExplosionAccessor; import carpet.mixins.ExplosionAccessor;
import carpet.CarpetSettings; import carpet.CarpetSettings;
import carpet.mixins.ExplosionMixin;
import carpet.utils.Messenger; import carpet.utils.Messenger;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
@@ -48,7 +45,7 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import static carpet.script.CarpetEventServer.Event.EXPLOSION; import static carpet.script.CarpetEventServer.Event.EXPLOSION_OUTCOME;
public class OptimizedExplosion public class OptimizedExplosion
{ {
@@ -77,7 +74,7 @@ public class OptimizedExplosion
ExplosionAccessor eAccess = (ExplosionAccessor) e; ExplosionAccessor eAccess = (ExplosionAccessor) e;
entityList.clear(); entityList.clear();
boolean eventNeeded = EXPLOSION.isNeeded(); boolean eventNeeded = EXPLOSION_OUTCOME.isNeeded() && !eAccess.getWorld().isClient();
blastCalc(e); blastCalc(e);
if (!CarpetSettings.explosionNoBlockDamage) { if (!CarpetSettings.explosionNoBlockDamage) {
@@ -208,8 +205,8 @@ boolean eventNeeded = EXPLOSION.isNeeded();
double posZ = eAccess.getZ(); double posZ = eAccess.getZ();
// If it is needed, calls scarpet event // If it is needed, calls scarpet event
if (EXPLOSION.isNeeded()) { if (EXPLOSION_OUTCOME.isNeeded() && !world.isClient()) {
EXPLOSION.onExplosion((ServerWorld) world, eAccess.getX(), eAccess.getY(), eAccess.getZ(), eAccess.getPower(), e.getDamageSource(), eAccess.isCreateFire(), e.getAffectedBlocks(), entityList); EXPLOSION_OUTCOME.onExplosion((ServerWorld) world, eAccess.getEntity(), e::getCausingEntity, eAccess.getX(), eAccess.getY(), eAccess.getZ(), eAccess.getPower(), eAccess.isCreateFire(), e.getAffectedBlocks(), entityList, eAccess.getDestructionType());
} }
boolean damagesTerrain = eAccess.getDestructionType() != Explosion.DestructionType.NONE; boolean damagesTerrain = eAccess.getDestructionType() != Explosion.DestructionType.NONE;
@@ -1,9 +1,7 @@
package carpet.mixins; package carpet.mixins;
import carpet.logging.LoggerRegistry;
import carpet.logging.logHelpers.ExplosionLogHelper;
import carpet.script.value.EntityValue;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageSource;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -11,6 +9,7 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.explosion.Explosion; import net.minecraft.world.explosion.Explosion;
import net.minecraft.world.explosion.ExplosionBehavior; import net.minecraft.world.explosion.ExplosionBehavior;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@@ -20,11 +19,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static carpet.script.CarpetEventServer.Event.EXPLOSION; import static carpet.script.CarpetEventServer.Event.EXPLOSION_OUTCOME;
@Mixin(value = Explosion.class, priority = 990) @Mixin(value = Explosion.class, priority = 990)
public abstract class Explosion_scarpetEventMixin public abstract class Explosion_scarpetEventMixin
@@ -34,16 +32,20 @@ public abstract class Explosion_scarpetEventMixin
@Shadow @Final private double y; @Shadow @Final private double y;
@Shadow @Final private double z; @Shadow @Final private double z;
@Shadow @Final private float power; @Shadow @Final private float power;
@Shadow @Final private DamageSource damageSource;
@Shadow @Final private boolean createFire; @Shadow @Final private boolean createFire;
@Shadow @Final private List<BlockPos> affectedBlocks; @Shadow @Final private List<BlockPos> affectedBlocks;
@Shadow @Final private Explosion.DestructionType destructionType;
@Shadow @Final private @Nullable Entity entity;
@Shadow /*@Nullable*/ public abstract /*@Nullable*/ LivingEntity getCausingEntity();
private List<Entity> affectedEntities; private List<Entity> affectedEntities;
@Inject(method = "<init>(Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;Lnet/minecraft/entity/damage/DamageSource;Lnet/minecraft/world/explosion/ExplosionBehavior;DDDFZLnet/minecraft/world/explosion/Explosion$DestructionType;)V", @Inject(method = "<init>(Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;Lnet/minecraft/entity/damage/DamageSource;Lnet/minecraft/world/explosion/ExplosionBehavior;DDDFZLnet/minecraft/world/explosion/Explosion$DestructionType;)V",
at = @At(value = "RETURN")) at = @At(value = "RETURN"))
private void onExplosionCreated(World world, Entity entity, DamageSource damageSource, ExplosionBehavior explosionBehavior, double x, double y, double z, float power, boolean createFire, Explosion.DestructionType destructionType, CallbackInfo ci) private void onExplosionCreated(World world, Entity entity, DamageSource damageSource, ExplosionBehavior explosionBehavior, double x, double y, double z, float power, boolean createFire, Explosion.DestructionType destructionType, CallbackInfo ci)
{ {
if (EXPLOSION.isNeeded()) if (EXPLOSION_OUTCOME.isNeeded() && !world.isClient())
{ {
affectedEntities = new ArrayList<>(); affectedEntities = new ArrayList<>();
} }
@@ -61,9 +63,9 @@ public abstract class Explosion_scarpetEventMixin
@Inject(method = "affectWorld", at = @At("HEAD")) @Inject(method = "affectWorld", at = @At("HEAD"))
private void onExplosion(boolean spawnParticles, CallbackInfo ci) private void onExplosion(boolean spawnParticles, CallbackInfo ci)
{ {
if (EXPLOSION.isNeeded()) if (EXPLOSION_OUTCOME.isNeeded() && !world.isClient())
{ {
EXPLOSION.onExplosion((ServerWorld) world, x, y, z, power, damageSource, createFire, affectedBlocks, affectedEntities); EXPLOSION_OUTCOME.onExplosion((ServerWorld) world, entity, this::getCausingEntity, x, y, z, power, createFire, affectedBlocks, affectedEntities, destructionType);
} }
} }
} }
@@ -5,20 +5,27 @@ import carpet.fakes.ServerWorldInterface;
import carpet.script.CarpetEventServer; import carpet.script.CarpetEventServer;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LightningEntity; import net.minecraft.entity.LightningEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.profiler.Profiler; import net.minecraft.util.profiler.Profiler;
import net.minecraft.world.chunk.WorldChunk; import net.minecraft.world.chunk.WorldChunk;
import net.minecraft.world.explosion.Explosion;
import net.minecraft.world.explosion.ExplosionBehavior;
import net.minecraft.world.level.ServerWorldProperties; import net.minecraft.world.level.ServerWorldProperties;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import static carpet.script.CarpetEventServer.Event.ENTITY_LOAD; import static carpet.script.CarpetEventServer.Event.ENTITY_LOAD;
import static carpet.script.CarpetEventServer.Event.EXPLOSION;
import static carpet.script.CarpetEventServer.Event.LIGHTNING; import static carpet.script.CarpetEventServer.Event.LIGHTNING;
@Mixin(ServerWorld.class) @Mixin(ServerWorld.class)
@@ -57,6 +64,14 @@ public class ServerWorld_scarpetMixin implements ServerWorldInterface
} }
} }
@Inject(method = "createExplosion", at = @At("HEAD"))
private void handleExplosion(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionBehavior explosionBehavior, double d, double e, double f, float g, boolean bl, Explosion.DestructionType destructionType, CallbackInfoReturnable<Explosion> cir)
{
if (EXPLOSION.isNeeded())
EXPLOSION.onExplosion((ServerWorld) (Object)this, entity, null, d, e, f, g, bl, null, null, destructionType);
}
@Final
@Shadow @Shadow
private ServerWorldProperties worldProperties; private ServerWorldProperties worldProperties;
public ServerWorldProperties getWorldPropertiesCM(){ public ServerWorldProperties getWorldPropertiesCM(){
@@ -5,6 +5,7 @@ import carpet.CarpetSettings;
import carpet.helpers.TickSpeed; import carpet.helpers.TickSpeed;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.value.BlockValue; import carpet.script.value.BlockValue;
import carpet.script.value.BooleanValue;
import carpet.script.value.EntityValue; import carpet.script.value.EntityValue;
import carpet.script.value.FunctionValue; import carpet.script.value.FunctionValue;
import carpet.script.value.ListValue; import carpet.script.value.ListValue;
@@ -19,8 +20,11 @@ import carpet.utils.Messenger;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.TntEntity;
import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.passive.MerchantEntity; import net.minecraft.entity.passive.MerchantEntity;
import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
@@ -42,6 +46,7 @@ import net.minecraft.village.Merchant;
import net.minecraft.village.TradeOffer; import net.minecraft.village.TradeOffer;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.explosion.Explosion;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList; import java.util.ArrayList;
@@ -52,6 +57,7 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@@ -865,21 +871,55 @@ public class CarpetEventServer
); );
} }
}; };
public static final Event EXPLOSION = new Event("explosion", 6, true) //copy of Explosion.getCausingEntity() #TRACK#
private static LivingEntity getExplosionCausingEntity(Entity entity)
{
if (entity == null) return null;
else if (entity instanceof TntEntity) return ((TntEntity)entity).getCausingEntity();
else if (entity instanceof LivingEntity) return (LivingEntity)entity;
else if (entity instanceof ProjectileEntity) {
Entity owner = ((ProjectileEntity)entity).getOwner();
if (owner instanceof LivingEntity) return (LivingEntity)owner;
}
return null;
}
public static final Event EXPLOSION_OUTCOME = new Event("explosion_outcome", 8, true)
{ {
@Override @Override
public void onExplosion(ServerWorld world, double x, double y, double z, float power, DamageSource source, boolean createFire, List<BlockPos> affectedBlocks, List<Entity> affectedEntities) public void onExplosion(ServerWorld world, Entity e, Supplier<LivingEntity> attacker, double x, double y, double z, float power, boolean createFire, List<BlockPos> affectedBlocks, List<Entity> affectedEntities, Explosion.DestructionType type)
{ {
handler.call( handler.call(
() -> Arrays.asList( () -> Arrays.asList(
ListValue.fromTriple(x, y, z), ListValue.fromTriple(x, y, z),
new NumericValue(power), NumericValue.of(power),
source.getAttacker()==null?Value.NULL:new EntityValue(source.getAttacker()), EntityValue.of(e),
createFire?Value.TRUE:Value.FALSE, EntityValue.of(attacker!= null?attacker.get():Event.getExplosionCausingEntity(e)),
new ListValue(affectedBlocks.stream().map( StringValue.of(type.name().toLowerCase(Locale.ROOT)),
BooleanValue.of(createFire),
new ListValue(affectedBlocks.stream().filter(b -> !world.isAir(b)). map( // da heck they send air blocks
b -> new BlockValue(world.getBlockState(b),world,b) b -> new BlockValue(world.getBlockState(b),world,b)
).collect(Collectors.toList())), ).collect(Collectors.toList())),
new ListValue(affectedEntities.stream().map(EntityValue::new).collect(Collectors.toList())) new ListValue(affectedEntities.stream().map(EntityValue::of).collect(Collectors.toList()))
), () -> CarpetServer.minecraft_server.getCommandSource().withWorld(world)
);
}
};
public static final Event EXPLOSION = new Event("explosion", 6, true)
{
@Override
public void onExplosion(ServerWorld world, Entity e, Supplier<LivingEntity> attacker, double x, double y, double z, float power, boolean createFire, List<BlockPos> affectedBlocks, List<Entity> affectedEntities, Explosion.DestructionType type)
{
handler.call(
() -> Arrays.asList(
ListValue.fromTriple(x, y, z),
NumericValue.of(power),
EntityValue.of(e),
EntityValue.of(attacker!= null?attacker.get():Event.getExplosionCausingEntity(e)),
StringValue.of(type.name().toLowerCase(Locale.ROOT)),
BooleanValue.of(createFire)
), () -> CarpetServer.minecraft_server.getCommandSource().withWorld(world) ), () -> CarpetServer.minecraft_server.getCommandSource().withWorld(world)
); );
} }
@@ -1004,8 +1044,7 @@ public class CarpetEventServer
public void onSlotSwitch(ServerPlayerEntity player, int from, int to) {} public void onSlotSwitch(ServerPlayerEntity player, int from, int to) {}
public void onTrade(ServerPlayerEntity player, Merchant merchant, TradeOffer tradeOffer) {} public void onTrade(ServerPlayerEntity player, Merchant merchant, TradeOffer tradeOffer) {}
public void onExplosion(ServerWorld world, double x, double y, double z, float power, DamageSource source, boolean createFire, List<BlockPos> affectedBlocks, List<Entity> affectedEntities) { } public void onExplosion(ServerWorld world, Entity e, Supplier<LivingEntity> attacker, double x, double y, double z, float power, boolean createFire, List<BlockPos> affectedBlocks, List<Entity> affectedEntities, Explosion.DestructionType type) { }
public void onWorldEvent(ServerWorld world, BlockPos pos) { } public void onWorldEvent(ServerWorld world, BlockPos pos) { }
public void onWorldEventFlag(ServerWorld world, BlockPos pos, int flag) { } public void onWorldEventFlag(ServerWorld world, BlockPos pos, int flag) { }
public void onCarpetRuleChanges(ParsedRule<?> rule, ServerCommandSource source) { } public void onCarpetRuleChanges(ParsedRule<?> rule, ServerCommandSource source) { }
@@ -50,6 +50,7 @@ import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.FallingBlockEntity; import net.minecraft.entity.FallingBlockEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.pathing.NavigationType; import net.minecraft.entity.ai.pathing.NavigationType;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.Item; import net.minecraft.item.Item;
@@ -61,6 +62,7 @@ import net.minecraft.item.SwordItem;
import net.minecraft.item.TridentItem; import net.minecraft.item.TridentItem;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.network.packet.s2c.play.ExplosionS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ChunkTicket; import net.minecraft.server.world.ChunkTicket;
import net.minecraft.server.world.ChunkTicketType; import net.minecraft.server.world.ChunkTicketType;
@@ -79,6 +81,7 @@ import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
import net.minecraft.world.Heightmap; import net.minecraft.world.Heightmap;
import net.minecraft.world.LightType; import net.minecraft.world.LightType;
@@ -88,6 +91,7 @@ import net.minecraft.world.biome.Biome;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.chunk.ChunkStatus;
import net.minecraft.world.chunk.WorldChunk; import net.minecraft.world.chunk.WorldChunk;
import net.minecraft.world.explosion.Explosion;
import net.minecraft.world.gen.ChunkRandom; import net.minecraft.world.gen.ChunkRandom;
import net.minecraft.world.gen.chunk.ChunkGenerator; import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.feature.ConfiguredStructureFeature; import net.minecraft.world.gen.feature.ConfiguredStructureFeature;
@@ -96,6 +100,7 @@ import net.minecraft.world.level.ServerWorldProperties;
import net.minecraft.world.poi.PointOfInterest; import net.minecraft.world.poi.PointOfInterest;
import net.minecraft.world.poi.PointOfInterestStorage; import net.minecraft.world.poi.PointOfInterestStorage;
import net.minecraft.world.poi.PointOfInterestType; import net.minecraft.world.poi.PointOfInterestType;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -970,6 +975,88 @@ public class WorldAccess {
return success ? LazyValue.TRUE : LazyValue.FALSE; return success ? LazyValue.TRUE : LazyValue.FALSE;
}); });
expression.addLazyFunction("create_explosion", -1, (c, t, lv) ->
{
if (lv.isEmpty())
throw new InternalExpressionException("'create_explosion' requires at least a position to explode");
CarpetContext cc = (CarpetContext)c;
float powah = 4.0f;
Explosion.DestructionType mode = Explosion.DestructionType.BREAK;
boolean createFire = false;
Entity source = null;
LivingEntity attacker = null;
Vector3Argument location = Vector3Argument.findIn(cc, lv, 0, false, true);
Vec3d pos = location.vec;
if (lv.size() > location.offset)
{
powah = NumericValue.asNumber(lv.get(location.offset).evalValue(c), "explosion power").getFloat();
if (powah < 0) throw new InternalExpressionException("Explosion power cannot be negative");
if (lv.size() > location.offset+1)
{
String strval = lv.get(location.offset+1).evalValue(c).getString();
try {
mode = Explosion.DestructionType.valueOf(strval.toUpperCase(Locale.ROOT));
}
catch (IllegalArgumentException ile) { throw new InternalExpressionException("Illegal explosions block behaviour: "+strval); }
if (lv.size() > location.offset+2)
{
createFire = lv.get(location.offset+2).evalValue(c, Context.BOOLEAN).getBoolean();
if (lv.size() > location.offset+3)
{
Value enVal= lv.get(location.offset+3).evalValue(c);
if (enVal.isNull()) {} // is null already
else if (enVal instanceof EntityValue)
{
source = ((EntityValue) enVal).getEntity();
}
else
{
throw new InternalExpressionException("Fourth parameter of the explosion has to be an entity, not "+enVal.getTypeString());
}
if (lv.size() > location.offset+4)
{
enVal = lv.get(location.offset+4).evalValue(c);
if (enVal.isNull()) {} // is null already
else if (enVal instanceof EntityValue)
{
Entity attackingEntity = ((EntityValue) enVal).getEntity();
if (attackingEntity instanceof LivingEntity)
{
attacker = (LivingEntity) attackingEntity;
}
else throw new InternalExpressionException("Attacking entity needs to be a living thing, "+
ValueConversions.of(Registry.ENTITY_TYPE.getId(attackingEntity.getType())).getString() +" ain't it.");
}
else
{
throw new InternalExpressionException("Fifth parameter of the explosion has to be a living entity, not "+enVal.getTypeString());
}
}
}
}
}
}
LivingEntity theAttacker = attacker;
float thePowah = powah;
// copy of ServerWorld.createExplosion #TRACK#
Explosion explosion = new Explosion(cc.s.getWorld(), source, null, null, pos.x, pos.y, pos.z, powah, createFire, mode){
@Override
public @Nullable LivingEntity getCausingEntity() {
return theAttacker;
}
};
explosion.collectBlocksAndDamageEntities();
explosion.affectWorld(false);
if (mode == Explosion.DestructionType.NONE) explosion.clearAffectedBlocks();
cc.s.getWorld().getPlayers().forEach(spe -> {
if (spe.squaredDistanceTo(pos) < 4096.0D)
spe.networkHandler.sendPacket(new ExplosionS2CPacket(pos.x, pos.y, pos.z, thePowah, explosion.getAffectedBlocks(), explosion.getAffectedPlayers().get(spe)));
});
return LazyValue.TRUE;
});
// TODO rename to use_item // TODO rename to use_item
expression.addLazyFunction("place_item", -1, (c, t, lv) -> expression.addLazyFunction("place_item", -1, (c, t, lv) ->
{ {
@@ -99,6 +99,12 @@ public class EntityValue extends Value
entity = e; entity = e;
} }
public static Value of(Entity e)
{
if (e == null) return Value.NULL;
return new EntityValue(e);
}
private static final Map<String, EntitySelector> selectorCache = new HashMap<>(); private static final Map<String, EntitySelector> selectorCache = new HashMap<>();
public static Collection<? extends Entity > getEntitiesFromSelector(ServerCommandSource source, String selector) public static Collection<? extends Entity > getEntitiesFromSelector(ServerCommandSource source, String selector)
{ {
@@ -328,3 +328,32 @@ __on_close() ->
print('App is closing for '+player()); print('App is closing for '+player());
logger('App is closing for '+player()); logger('App is closing for '+player());
); );
__on_explosion(pos, power, source, causer, mode, fire) ->
(
print('');
print('__on_explosion(pos, power, source, causer, mode, fire)');
print('explosion:');
print(' - pos: '+pos);
print(' - power: '+power);
print(' - source: '+source);
print(' - causer: '+causer);
print(' - mode: '+mode);
print(' - fire: '+fire);
);
__on_explosion_outcome(pos, power, source, causer, mode, fire, blocks, entities) ->
(
print('');
print('__on_explosion_outcome(pos, power, source, causer, mode, fire, blocks, entities)');
print('explosion outcome:');
print(' - pos: '+pos);
print(' - power: '+power);
print(' - source: '+source);
print(' - causer: '+causer);
print(' - mode: '+mode);
print(' - fire: '+fire);
print(' - number or affected blocks: '+length(blocks));
print(' - number of affected entities: '+length(entities));
);