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>
This commit is contained in:
authored and GitHub committed 2021-04-08 18:05:13 -03:00
1 parent 9702262787
commit 7b00952653
7 files changed
+117 -3

No files matched your search

+6 -1
View File
@@ -79,6 +79,11 @@ 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)`
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)` ### `__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,
which will then be namespaced as `namespace:rule`. 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 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. 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 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 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. to the client, but before triggering it and its effects in game.
+2 -1
View File
@@ -42,4 +42,5 @@ __on_player_deals_damage(player, amount, entity) ->
__on_player_dies(player) -> __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) ->
@@ -139,6 +139,7 @@
__on_player_respawns __on_player_respawns
__on_player_disconnects __on_player_disconnects
__on_player_connects __on_player_connects
__on_explosion
</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>
@@ -48,6 +48,8 @@ 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;
public class OptimizedExplosion public class OptimizedExplosion
{ {
private static List<Entity> entitylist; private static List<Entity> entitylist;
@@ -68,9 +70,14 @@ public class OptimizedExplosion
private static ArrayList<Float> chances = new ArrayList<>(); private static ArrayList<Float> chances = new ArrayList<>();
private static BlockPos blastChanceLocation; private static BlockPos blastChanceLocation;
// Creating entity list for scarpet event
private static List<Entity> entityList = new ArrayList<>();
public static void doExplosionA(Explosion e, ExplosionLogHelper eLogger) { public static void doExplosionA(Explosion e, ExplosionLogHelper eLogger) {
ExplosionAccessor eAccess = (ExplosionAccessor) e; ExplosionAccessor eAccess = (ExplosionAccessor) e;
entityList.clear();
boolean eventNeeded = EXPLOSION.isNeeded();
blastCalc(e); blastCalc(e);
if (!CarpetSettings.explosionNoBlockDamage) { if (!CarpetSettings.explosionNoBlockDamage) {
@@ -156,6 +163,11 @@ public class OptimizedExplosion
densityCache.put(pair, density); densityCache.put(pair, density);
} }
// If it is needed, it saves the entity
if (eventNeeded) {
entityList.add(entity);
}
double d10 = (1.0D - d12) * density; double d10 = (1.0D - d12) * density;
entity.damage(e.getDamageSource(), entity.damage(e.getDamageSource(),
(float) ((int) ((d10 * d10 + d10) / 2.0D * 7.0D * (double) f3 + 1.0D))); (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 posY = eAccess.getY();
double posZ = eAccess.getZ(); 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; boolean damagesTerrain = eAccess.getDestructionType() != Explosion.DestructionType.NONE;
// explosionSound incremented till disabling the explosion particles and sound // explosionSound incremented till disabling the explosion particles and sound
@@ -598,4 +615,4 @@ public class OptimizedExplosion
); );
} }
} }
} }
@@ -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<BlockPos> affectedBlocks;
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",
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<BlockPos> s1, float f1, int i1, int i2, int i3, int i4, int i5, int i6, List<Entity> 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);
}
}
}
@@ -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<BlockPos> affectedBlocks, List<Entity> 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) 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 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 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) { }
+1
View File
@@ -129,6 +129,7 @@
"TntBlockMixin", "TntBlockMixin",
"ExplosionMixin", "ExplosionMixin",
"ExplosionAccessor", "ExplosionAccessor",
"Explosion_scarpetEventMixin",
"TntEntityMixin", "TntEntityMixin",
"ProjectileEntityMixin", "ProjectileEntityMixin",