Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Issues related to fireworks and fused explosives #4117

Merged
merged 12 commits into from
Aug 25, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@

public interface FusedExplosiveBridge {

boolean bridge$isPrimed();

int bridge$getFuseDuration();

void bridge$setFuseDuration(int fuseTicks);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,14 @@
*/
package org.spongepowered.common.data.provider.entity;

import com.google.common.collect.ImmutableList;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.Fireworks;
import org.spongepowered.api.data.Keys;
import org.spongepowered.common.accessor.world.entity.EntityAccessor;
import org.spongepowered.common.accessor.world.entity.projectile.FireworkRocketEntityAccessor;
import org.spongepowered.common.data.provider.DataProviderRegistrator;
import org.spongepowered.common.util.FireworkUtil;
import org.spongepowered.common.util.SpongeTicks;

import java.util.OptionalInt;

public final class FireworkRocketData {

private FireworkRocketData() {
Expand All @@ -47,27 +43,22 @@ public static void register(final DataProviderRegistrator registrator) {
.asMutable(FireworkRocketEntity.class)
.create(Keys.FIREWORK_EFFECTS)
.get(h -> FireworkUtil.getFireworkEffects(h).orElse(null))
.set(FireworkUtil::setFireworkEffects)
.resetOnDelete(ImmutableList.of())
.setAnd(FireworkUtil::setFireworkEffects)
.deleteAnd(FireworkUtil::removeFireworkEffects)
.create(Keys.FIREWORK_FLIGHT_MODIFIER)
.get(h -> {
final ItemStack item = FireworkUtil.getItem(h);
final Fireworks fireworks = item.get(DataComponents.FIREWORKS);
if (fireworks == null) {
final OptionalInt modifier = FireworkUtil.getFlightModifier(h);
if (modifier.isEmpty()) {
return null;
}
return new SpongeTicks(fireworks.flightDuration());
return new SpongeTicks(modifier.getAsInt());
})
.setAnd((h, v) -> {
final int ticks = SpongeTicks.toSaturatedIntOrInfinite(v);
if (v.isInfinite() || ticks < 0 || ticks > Byte.MAX_VALUE) {
return false;
}
final ItemStack item = FireworkUtil.getItem(h);
final Fireworks fireworks = item.get(DataComponents.FIREWORKS);
item.set(DataComponents.FIREWORKS, new Fireworks((int) v.ticks(), fireworks.explosions()));
((FireworkRocketEntityAccessor) h).accessor$lifetime(10 * ticks + ((EntityAccessor) h).accessor$random().nextInt(6) + ((EntityAccessor) h).accessor$random().nextInt(7));
return true;
return FireworkUtil.setFlightModifier(h, ticks);
});
}
// @formatter:on
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ private FusedExplosiveData() {
public static void register(final DataProviderRegistrator registrator) {
registrator
.asMutable(FusedExplosive.class)
.create(Keys.IS_PRIMED)
.get(h -> ((FusedExplosiveBridge) h).bridge$isPrimed())
.create(Keys.FUSE_DURATION)
.get(h -> new SpongeTicks(((FusedExplosiveBridge) h).bridge$getFuseDuration()))
.setAnd((h, v) -> {
final int ticks = SpongeTicks.toSaturatedIntOrInfinite(v);
if (!v.isInfinite() || ticks < 0) {
if (v.isInfinite() || ticks < 0) {
return false;
}
((FusedExplosiveBridge) h).bridge$setFuseDuration(ticks);
Expand All @@ -56,8 +58,7 @@ public static void register(final DataProviderRegistrator registrator) {
if (v.isInfinite() || ticks < 0) {
return false;
}
// TODO isPrimed on bridge?
if (h.primed().get()) {
if (((FusedExplosiveBridge) h).bridge$isPrimed()) {
((FusedExplosiveBridge) h).bridge$setFuseTicksRemaining(ticks);
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ public static void register(final DataProviderRegistrator registrator) {
.create(Keys.DETONATOR)
.get(h -> (Living) h.getOwner())
.set((h, v) -> ((PrimedTntAccessor) h).accessor$owner((LivingEntity) v))
.create(Keys.IS_PRIMED)
.get(h -> !h.isRemoved() && h.getFuse() > 0)
.create(Keys.BLOCK_STATE)
.get(h -> (BlockState) h.getBlockState())
.set((h, v) -> h.setBlockState((net.minecraft.world.level.block.state.BlockState) v));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
import org.spongepowered.api.data.Keys;
import org.spongepowered.common.data.provider.DataProviderRegistrator;
import org.spongepowered.common.util.FireworkUtil;
import org.spongepowered.common.util.SpongeTicks;

import java.util.OptionalInt;

public final class FireworkItemStackData {

Expand All @@ -37,14 +40,29 @@ private FireworkItemStackData() {

// @formatter:off
public static void register(final DataProviderRegistrator registrator) {
// TODO DataComponents.FIREWORKS - flight_duration
registrator
.asMutable(ItemStack.class)
.create(Keys.FIREWORK_EFFECTS)
.get(h -> FireworkUtil.getFireworkEffects(h).orElse(null))
.set(FireworkUtil::setFireworkEffects)
.delete(FireworkUtil::removeFireworkEffects)
.supports(h -> h.getItem() == Items.FIREWORK_ROCKET || h.getItem() == Items.FIREWORK_STAR);
.setAnd(FireworkUtil::setFireworkEffects)
.deleteAnd(FireworkUtil::removeFireworkEffects)
.supports(h -> h.getItem() == Items.FIREWORK_ROCKET || h.getItem() == Items.FIREWORK_STAR)
.create(Keys.FIREWORK_FLIGHT_MODIFIER)
.get(h -> {
final OptionalInt modifier = FireworkUtil.getFlightModifier(h);
if (modifier.isEmpty()) {
return null;
}
return new SpongeTicks(modifier.getAsInt());
})
.setAnd((h, v) -> {
final int ticks = SpongeTicks.toSaturatedIntOrInfinite(v);
if (v.isInfinite() || ticks < 0 || ticks > Byte.MAX_VALUE) {
return false;
}
return FireworkUtil.setFlightModifier(h, ticks);
})
.supports(h -> h.getItem() == Items.FIREWORK_ROCKET);
}
// @formatter:on
}
82 changes: 63 additions & 19 deletions src/main/java/org/spongepowered/common/util/FireworkUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,47 @@
import net.minecraft.world.item.component.Fireworks;
import org.spongepowered.api.item.FireworkEffect;
import org.spongepowered.api.item.ItemTypes;
import org.spongepowered.common.accessor.world.entity.EntityAccessor;
import org.spongepowered.common.accessor.world.entity.projectile.FireworkRocketEntityAccessor;
import org.spongepowered.common.item.SpongeItemStack;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.function.Function;

public final class FireworkUtil {
public static boolean setFireworkEffects(final FireworkRocketEntity firework, final List<? extends FireworkEffect> effects) {
return updateFireworkRocketItem(firework, item -> setFireworkEffects(item, effects));
}

public static boolean setFireworkEffects(final Object object, final List<? extends FireworkEffect> effects) {
public static boolean setFireworkEffects(final ItemStack item, final List<? extends FireworkEffect> effects) {
if (effects.isEmpty()) {
return FireworkUtil.removeFireworkEffects(object);
return FireworkUtil.removeFireworkEffects(item);
}
final ItemStack item = FireworkUtil.getItem(object);

if (item.isEmpty()) {
return false;
}

if (item.getItem() == Items.FIREWORK_STAR) {
item.set(DataComponents.FIREWORK_EXPLOSION, (FireworkExplosion) (Object) effects.get(0));
item.set(DataComponents.FIREWORK_EXPLOSION, (FireworkExplosion) (Object) effects.getFirst());
return true;
} else if (item.getItem() == Items.FIREWORK_ROCKET) {
final List<FireworkExplosion> mcEffects = effects.stream().map(FireworkExplosion.class::cast).toList();
item.update(DataComponents.FIREWORKS, new Fireworks(1, Collections.emptyList()), p -> new Fireworks(p.flightDuration(), mcEffects));
return true;
}

return false;
}

public static Optional<List<FireworkEffect>> getFireworkEffects(final Object object) {
final ItemStack item = FireworkUtil.getItem(object);
public static Optional<List<FireworkEffect>> getFireworkEffects(final FireworkRocketEntity firework) {
return getFireworkEffects(getItem(firework));
}

public static Optional<List<FireworkEffect>> getFireworkEffects(final ItemStack item) {
if (item.isEmpty()) {
return Optional.empty();
}
Expand All @@ -83,8 +93,11 @@ public static Optional<List<FireworkEffect>> getFireworkEffects(final Object obj
return Optional.of(List.of((FireworkEffect) (Object) fireworkExplosion));
}

public static boolean removeFireworkEffects(final Object object) {
final ItemStack item = FireworkUtil.getItem(object);
public static boolean removeFireworkEffects(final FireworkRocketEntity firework) {
return updateFireworkRocketItem(firework, FireworkUtil::removeFireworkEffects);
}

public static boolean removeFireworkEffects(final ItemStack item) {
if (item.isEmpty()) {
return false;
}
Expand All @@ -103,23 +116,54 @@ public static boolean removeFireworkEffects(final Object object) {
return false;
}

public static ItemStack getItem(final FireworkRocketEntity firework) {
ItemStack item = firework.getEntityData().get(FireworkRocketEntityAccessor.accessor$DATA_ID_FIREWORKS_ITEM());
public static boolean setFlightModifier(final FireworkRocketEntity firework, final int modifier) {
if (updateFireworkRocketItem(firework, item -> setFlightModifier(item, modifier))) {
int lifetime = 10 * modifier + ((EntityAccessor) firework).accessor$random().nextInt(6) + ((EntityAccessor) firework).accessor$random().nextInt(7);
((FireworkRocketEntityAccessor) firework).accessor$lifetime(lifetime);
return true;
}
return false;
}

public static boolean setFlightModifier(final ItemStack item, final int modifier) {
if (item.isEmpty()) {
item = (ItemStack) (Object) new SpongeItemStack.BuilderImpl().itemType(ItemTypes.FIREWORK_ROCKET).build();
firework.getEntityData().set(FireworkRocketEntityAccessor.accessor$DATA_ID_FIREWORKS_ITEM(), item);
return false;
}
return item;

if (item.getItem() == Items.FIREWORK_ROCKET) {
item.update(DataComponents.FIREWORKS, new Fireworks(1, Collections.emptyList()), p -> new Fireworks(modifier, p.explosions()));
return true;
}
return false;
}

public static OptionalInt getFlightModifier(final FireworkRocketEntity firework) {
return getFlightModifier(getItem(firework));
}

public static OptionalInt getFlightModifier(final ItemStack item) {
final Fireworks fireworks = item.get(DataComponents.FIREWORKS);
if (fireworks == null) {
return OptionalInt.empty();
}
return OptionalInt.of(fireworks.flightDuration());
}

private static ItemStack getItem(final Object object) {
if (object instanceof ItemStack) {
return (ItemStack) object;
public static boolean updateFireworkRocketItem(final FireworkRocketEntity firework, final Function<ItemStack, Boolean> function) {
final ItemStack item = getItem(firework).copy();
if (function.apply(item)) {
firework.getEntityData().set(FireworkRocketEntityAccessor.accessor$DATA_ID_FIREWORKS_ITEM(), item);
return true;
}
if (object instanceof FireworkRocketEntity) {
return FireworkUtil.getItem((FireworkRocketEntity) object);
return false;
}

public static ItemStack getItem(final FireworkRocketEntity firework) {
ItemStack item = firework.getEntityData().get(FireworkRocketEntityAccessor.accessor$DATA_ID_FIREWORKS_ITEM());
if (item.isEmpty()) {
return (ItemStack) (Object) new SpongeItemStack.BuilderImpl().itemType(ItemTypes.FIREWORK_ROCKET).build();
}
return ItemStack.EMPTY;
return item;
}

private FireworkUtil() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public abstract class PrimedTntMixin_API extends EntityMixin_API implements Prim

@Override
public void detonate() {
this.shadow$discard();
this.shadow$explode();
this.shadow$discard();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,21 @@
public abstract class CreeperMixin_API extends MonsterMixin_API implements Creeper {

// @formatter:off
@Shadow public void shadow$ignite() { } // explode
@Shadow protected abstract void shadow$explodeCreeper();
// @formatter:on


@Override
public void detonate() {
this.shadow$ignite();
this.shadow$explodeCreeper();
}

@Override
protected Set<Value.Immutable<?>> api$getVanillaValues() {
final Set<Value.Immutable<?>> values = super.api$getVanillaValues();

values.add(this.requireValue(Keys.FUSE_DURATION).asImmutable());
values.add(this.requireValue(Keys.IS_PRIMED).asImmutable());
values.add(this.requireValue(Keys.IS_CHARGED).asImmutable());
values.add(this.requireValue(Keys.TICKS_REMAINING).asImmutable());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,11 @@
public abstract class FireworkRocketEntityMixin_API extends ProjectileMixin_API implements FireworkRocket {

// @formatter:off
@Shadow private int life;
@Shadow private int lifetime;
@Shadow protected abstract void shadow$explode();
// @formatter:on

@Override
public void detonate() {
this.life = this.lifetime + 1;
this.shadow$explode();
}

Expand All @@ -53,6 +50,7 @@ public void detonate() {
final Set<Value.Immutable<?>> values = super.api$getVanillaValues();

values.add(this.requireValue(Keys.FUSE_DURATION).asImmutable());
values.add(this.requireValue(Keys.IS_PRIMED).asImmutable());
values.add(this.requireValue(Keys.TICKS_REMAINING).asImmutable());

this.getValue(Keys.EXPLOSION_RADIUS).map(Value::asImmutable).ifPresent(values::add);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public void detonate() {
final Set<Value.Immutable<?>> values = super.api$getVanillaValues();

values.add(this.requireValue(Keys.FUSE_DURATION).asImmutable());
values.add(this.requireValue(Keys.IS_PRIMED).asImmutable());
values.add(this.requireValue(Keys.TICKS_REMAINING).asImmutable());

this.getValue(Keys.EXPLOSION_RADIUS).map(Value::asImmutable).ifPresent(values::add);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public abstract class PrimedTntMixin extends EntityMixin implements PrimedTntBri
@Nullable private LivingEntity impl$detonator;
private int bridge$explosionRadius = Constants.Entity.PrimedTNT.DEFAULT_EXPLOSION_RADIUS;
private int bridge$fuseDuration = Constants.Entity.PrimedTNT.DEFAULT_FUSE_DURATION;
private boolean impl$postPrimeTriggered = false;

@Override
public void bridge$setDetonator(final LivingEntity detonator) {
Expand All @@ -84,6 +85,11 @@ public abstract class PrimedTntMixin extends EntityMixin implements PrimedTntBri
this.bridge$explosionRadius = radius == null ? Constants.Entity.PrimedTNT.DEFAULT_EXPLOSION_RADIUS : radius;
}

@Override
public boolean bridge$isPrimed() {
return true;
}

@Override
public int bridge$getFuseDuration() {
return this.bridge$fuseDuration;
Expand All @@ -92,6 +98,7 @@ public abstract class PrimedTntMixin extends EntityMixin implements PrimedTntBri
@Override
public void bridge$setFuseDuration(final int fuseTicks) {
this.bridge$fuseDuration = fuseTicks;
this.shadow$setFuse(fuseTicks);
}

@Override
Expand Down Expand Up @@ -129,7 +136,8 @@ public abstract class PrimedTntMixin extends EntityMixin implements PrimedTntBri

@Inject(method = "tick()V", at = @At("RETURN"))
private void impl$updateTNTPushPrime(final CallbackInfo ci) {
if (this.shadow$getFuse() == this.bridge$fuseDuration - 1 && !this.shadow$level().isClientSide) {
if (!impl$postPrimeTriggered && !this.shadow$level().isClientSide) {
impl$postPrimeTriggered = true;
try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) {
if (this.impl$detonator != null) {
frame.pushCause(this.impl$detonator);
Expand All @@ -139,5 +147,4 @@ public abstract class PrimedTntMixin extends EntityMixin implements PrimedTntBri
}
}
}

}
Loading