From 7b00952653646275577f2bff3000bc48b84f70af Mon Sep 17 00:00:00 2001
From: BisUmTo <31419791+BisUmTo@users.noreply.github.com>
Date: Thu, 8 Apr 2021 23:05:13 +0200
Subject: [PATCH] Added onExplosion Scarpet Event (#620)
* Added onExplosion Scarpet Event
* Reverted changes to Full.md
* Grammar corrections by James103
Co-authored-by: James103 <37945304+James103@users.noreply.github.com>
* Separated Explosion Mixins
Applied Ghoulboy78 suggestion.
WARNING: 'blocks' list is now empty if 'explosionNoBlockDamage' carpet rule is set to 'true'
* List Value from Triple
Suggested by Gnembon
* Explosion Mixin priority
Suggestion by Gnembon
* Added affectedEntities parameter
* Updated docs
* Optimizing calls
* Update src/main/java/carpet/helpers/OptimizedExplosion.java
* Update docs/scarpet/api/Events.md
Co-authored-by: gnembon <41132274+gnembon@users.noreply.github.com>
* Update docs/scarpet/api/Events.md
Co-authored-by: gnembon <41132274+gnembon@users.noreply.github.com>
* Update src/main/java/carpet/mixins/Explosion_scarpetEventMixin.java
Co-authored-by: gnembon <41132274+gnembon@users.noreply.github.com>
Co-authored-by: James103 <37945304+James103@users.noreply.github.com>
Co-authored-by: gnembon <41132274+gnembon@users.noreply.github.com>
---
docs/scarpet/api/Events.md | 7 +-
docs/scarpet/resources/editors/idea/4.txt | 3 +-
.../scarpet/resources/editors/npp/scarpet.xml | 1 +
.../carpet/helpers/OptimizedExplosion.java | 19 ++++-
.../mixins/Explosion_scarpetEventMixin.java | 69 +++++++++++++++++++
.../java/carpet/script/CarpetEventServer.java | 20 ++++++
src/main/resources/carpet.mixins.json | 1 +
7 files changed, 117 insertions(+), 3 deletions(-)
create mode 100644 src/main/java/carpet/mixins/Explosion_scarpetEventMixin.java
diff --git a/docs/scarpet/api/Events.md b/docs/scarpet/api/Events.md
index e646df83..061f00f0 100644
--- a/docs/scarpet/api/Events.md
+++ b/docs/scarpet/api/Events.md
@@ -79,6 +79,11 @@ at the same time.
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.
+### `__on_explosion(pos, power, source, create_fire, blocks, entities)`
+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.
+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.
+
### `__on_carpet_rule_changes(rule, new_value)`
Triggered when a carpet mod rule is changed. It includes extension rules, not using default `/carpet` command,
which will then be namespaced as `namespace:rule`.
@@ -107,7 +112,7 @@ Example events that may cause it to happen is releasing a bow. The event is trig
the request, however the `item_tuple` is provided representing the item that the player started with. You can use that and
compare with the currently held item for a delta.
-### `__on_player_finishes_using_item(player, item_tuple, hand))`
+### `__on_player_finishes_using_item(player, item_tuple, hand)`
Player using of an item is done. This is controlled server side and is responsible for such events as finishing
eating. The event is triggered after confirming that the action is valid, and sending the feedback back
to the client, but before triggering it and its effects in game.
diff --git a/docs/scarpet/resources/editors/idea/4.txt b/docs/scarpet/resources/editors/idea/4.txt
index a921bb46..e11b1bd5 100644
--- a/docs/scarpet/resources/editors/idea/4.txt
+++ b/docs/scarpet/resources/editors/idea/4.txt
@@ -42,4 +42,5 @@ __on_player_deals_damage(player, amount, entity) ->
__on_player_dies(player) ->
__on_player_respawns(player) ->
__on_player_disconnects(player, reason) ->
-__on_player_connects(player) ->
+__on_player_connects(player) ->
+__on_explosion(pos, power, source, create_fire, blocks, entities) ->
diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml
index b10e15e4..4940cfe3 100644
--- a/docs/scarpet/resources/editors/npp/scarpet.xml
+++ b/docs/scarpet/resources/editors/npp/scarpet.xml
@@ -139,6 +139,7 @@
__on_player_respawns
__on_player_disconnects
__on_player_connects
+ __on_explosion
$
00' 01\ 02' 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
diff --git a/src/main/java/carpet/helpers/OptimizedExplosion.java b/src/main/java/carpet/helpers/OptimizedExplosion.java
index 1c124ce5..5d164adb 100644
--- a/src/main/java/carpet/helpers/OptimizedExplosion.java
+++ b/src/main/java/carpet/helpers/OptimizedExplosion.java
@@ -48,6 +48,8 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
+import static carpet.script.CarpetEventServer.Event.EXPLOSION;
+
public class OptimizedExplosion
{
private static List entitylist;
@@ -68,9 +70,14 @@ public class OptimizedExplosion
private static ArrayList chances = new ArrayList<>();
private static BlockPos blastChanceLocation;
+ // Creating entity list for scarpet event
+ private static List entityList = new ArrayList<>();
+
public static void doExplosionA(Explosion e, ExplosionLogHelper eLogger) {
ExplosionAccessor eAccess = (ExplosionAccessor) e;
+ entityList.clear();
+boolean eventNeeded = EXPLOSION.isNeeded();
blastCalc(e);
if (!CarpetSettings.explosionNoBlockDamage) {
@@ -156,6 +163,11 @@ public class OptimizedExplosion
densityCache.put(pair, density);
}
+ // If it is needed, it saves the entity
+ if (eventNeeded) {
+ entityList.add(entity);
+ }
+
double d10 = (1.0D - d12) * density;
entity.damage(e.getDamageSource(),
(float) ((int) ((d10 * d10 + d10) / 2.0D * 7.0D * (double) f3 + 1.0D)));
@@ -195,6 +207,11 @@ public class OptimizedExplosion
double posY = eAccess.getY();
double posZ = eAccess.getZ();
+ // If it is needed, calls scarpet event
+ if (EXPLOSION.isNeeded()) {
+ EXPLOSION.onExplosion((ServerWorld) world, eAccess.getX(), eAccess.getY(), eAccess.getZ(), eAccess.getPower(), e.getDamageSource(), eAccess.isCreateFire(), e.getAffectedBlocks(), entityList);
+ }
+
boolean damagesTerrain = eAccess.getDestructionType() != Explosion.DestructionType.NONE;
// explosionSound incremented till disabling the explosion particles and sound
@@ -598,4 +615,4 @@ public class OptimizedExplosion
);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/carpet/mixins/Explosion_scarpetEventMixin.java b/src/main/java/carpet/mixins/Explosion_scarpetEventMixin.java
new file mode 100644
index 00000000..d0ae56a3
--- /dev/null
+++ b/src/main/java/carpet/mixins/Explosion_scarpetEventMixin.java
@@ -0,0 +1,69 @@
+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.damage.DamageSource;
+import net.minecraft.server.world.ServerWorld;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Vec3d;
+import net.minecraft.world.World;
+import net.minecraft.world.explosion.Explosion;
+import net.minecraft.world.explosion.ExplosionBehavior;
+import org.spongepowered.asm.mixin.Final;
+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;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static carpet.script.CarpetEventServer.Event.EXPLOSION;
+
+@Mixin(value = Explosion.class, priority = 990)
+public abstract class Explosion_scarpetEventMixin
+{
+ @Shadow @Final private World world;
+ @Shadow @Final private double x;
+ @Shadow @Final private double y;
+ @Shadow @Final private double z;
+ @Shadow @Final private float power;
+ @Shadow @Final private DamageSource damageSource;
+ @Shadow @Final private boolean createFire;
+ @Shadow @Final private List affectedBlocks;
+ private List affectedEntities;
+
+ @Inject(method = "(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"))
+ 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())
+ {
+ affectedEntities = new ArrayList<>();
+ }
+ }
+
+ @Inject(method = "collectBlocksAndDamageEntities", locals= LocalCapture.CAPTURE_FAILHARD, at=@At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;damage(Lnet/minecraft/entity/damage/DamageSource;F)Z"))
+ private void onExplosion(CallbackInfo ci, Set s1, float f1, int i1, int i2, int i3, int i4, int i5, int i6, List l1, Vec3d v1, int i7, Entity entity)
+ {
+ if (affectedEntities != null)
+ {
+ affectedEntities.add(entity);
+ }
+ }
+
+ @Inject(method = "affectWorld", at = @At("HEAD"))
+ private void onExplosion(boolean spawnParticles, CallbackInfo ci)
+ {
+ if (EXPLOSION.isNeeded())
+ {
+ EXPLOSION.onExplosion((ServerWorld) world, x, y, z, power, damageSource, createFire, affectedBlocks, affectedEntities);
+ }
+ }
+}
diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java
index 3c1c084d..7324bb4c 100644
--- a/src/main/java/carpet/script/CarpetEventServer.java
+++ b/src/main/java/carpet/script/CarpetEventServer.java
@@ -865,6 +865,25 @@ public class CarpetEventServer
);
}
};
+ public static final Event EXPLOSION = new Event("explosion", 6, true)
+ {
+ @Override
+ public void onExplosion(ServerWorld world, double x, double y, double z, float power, DamageSource source, boolean createFire, List affectedBlocks, List affectedEntities)
+ {
+ handler.call(
+ () -> Arrays.asList(
+ ListValue.fromTriple(x, y, z),
+ new NumericValue(power),
+ source.getAttacker()==null?Value.NULL:new EntityValue(source.getAttacker()),
+ createFire?Value.TRUE:Value.FALSE,
+ new ListValue(affectedBlocks.stream().map(
+ b -> new BlockValue(world.getBlockState(b),world,b)
+ ).collect(Collectors.toList())),
+ new ListValue(affectedEntities.stream().map(EntityValue::new).collect(Collectors.toList()))
+ ), () -> CarpetServer.minecraft_server.getCommandSource().withWorld(world)
+ );
+ }
+ };
public static String getEntityLoadEventName(EntityType extends Entity> et)
{
@@ -985,6 +1004,7 @@ public class CarpetEventServer
public void onSlotSwitch(ServerPlayerEntity player, int from, int to) {}
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 affectedBlocks, List affectedEntities) { }
public void onWorldEvent(ServerWorld world, BlockPos pos) { }
public void onWorldEventFlag(ServerWorld world, BlockPos pos, int flag) { }
diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json
index f945eb81..0d18197f 100644
--- a/src/main/resources/carpet.mixins.json
+++ b/src/main/resources/carpet.mixins.json
@@ -129,6 +129,7 @@
"TntBlockMixin",
"ExplosionMixin",
"ExplosionAccessor",
+ "Explosion_scarpetEventMixin",
"TntEntityMixin",
"ProjectileEntityMixin",