mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-01 19:46:42 +01:00
Some magic changes and added multi-gem interactions
This commit is contained in:
parent
9a91586921
commit
8b3de321f0
19 changed files with 173 additions and 29 deletions
|
@ -83,7 +83,7 @@ public class DisguiseCommand {
|
|||
static int reveal(ServerCommandSource source, PlayerEntity player) {
|
||||
Pony iplayer = Pony.of(player);
|
||||
iplayer.getEffect(DisguiseSpell.class).ifPresent(disguise -> {
|
||||
disguise.setDead();
|
||||
disguise.onDestroyed(iplayer);
|
||||
});
|
||||
|
||||
if (player.getEntityWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) {
|
||||
|
|
|
@ -53,7 +53,7 @@ public class Creature implements Ponylike<LivingEntity>, Caster<LivingEntity> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T extends MagicEffect> T getEffect(Class<T> type, boolean update) {
|
||||
public <T> T getEffect(Class<T> type, boolean update) {
|
||||
return effectDelegate.get(type, update);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.util.UUID;
|
|||
|
||||
import com.minelittlepony.unicopia.magic.Affinity;
|
||||
import com.minelittlepony.unicopia.magic.Caster;
|
||||
import com.minelittlepony.unicopia.magic.EtherialListener;
|
||||
import com.minelittlepony.unicopia.magic.MagicEffect;
|
||||
import com.minelittlepony.unicopia.magic.TossedMagicEffect;
|
||||
import com.minelittlepony.unicopia.magic.spell.SpellRegistry;
|
||||
|
@ -34,6 +35,7 @@ import net.minecraft.server.world.ServerWorld;
|
|||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.EntityHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
|
@ -52,6 +54,8 @@ public class ProjectileEntity extends ThrownItemEntity implements IMagicals, Adv
|
|||
|
||||
private UUID ownerUuid;
|
||||
|
||||
private BlockPos lastBlockPos;
|
||||
|
||||
public ProjectileEntity(EntityType<ProjectileEntity> type, World world) {
|
||||
super(type, world);
|
||||
}
|
||||
|
@ -133,7 +137,7 @@ public class ProjectileEntity extends ThrownItemEntity implements IMagicals, Adv
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T extends MagicEffect> T getEffect(Class<T> type, boolean update) {
|
||||
public <T> T getEffect(Class<T> type, boolean update) {
|
||||
return effectDelegate.get(type, update);
|
||||
}
|
||||
|
||||
|
@ -178,6 +182,12 @@ public class ProjectileEntity extends ThrownItemEntity implements IMagicals, Adv
|
|||
}
|
||||
|
||||
if (hasEffect()) {
|
||||
if (lastBlockPos == null || !lastBlockPos.equals(getBlockPos())) {
|
||||
notifyNearbySpells(getEffect(), lastBlockPos, 6, EtherialListener.REMOVED);
|
||||
lastBlockPos = getBlockPos();
|
||||
notifyNearbySpells(getEffect(), 6, EtherialListener.ADDED);
|
||||
}
|
||||
|
||||
if (getEffect().isDead()) {
|
||||
remove();
|
||||
} else {
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.item.UItems;
|
|||
import com.minelittlepony.unicopia.magic.Affinity;
|
||||
import com.minelittlepony.unicopia.magic.Castable;
|
||||
import com.minelittlepony.unicopia.magic.Caster;
|
||||
import com.minelittlepony.unicopia.magic.EtherialListener;
|
||||
import com.minelittlepony.unicopia.magic.MagicEffect;
|
||||
import com.minelittlepony.unicopia.magic.spell.SpellRegistry;
|
||||
import com.minelittlepony.unicopia.network.EffectSync;
|
||||
|
@ -44,7 +45,7 @@ import net.minecraft.world.GameRules;
|
|||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.explosion.Explosion.DestructionType;
|
||||
|
||||
public class SpellcastEntity extends MobEntityWithAi implements IMagicals, Caster<LivingEntity>, InAnimate, PickedItemSupplier {
|
||||
public class SpellcastEntity extends MobEntityWithAi implements IMagicals, Caster<LivingEntity>, EtherialListener, InAnimate, PickedItemSupplier {
|
||||
|
||||
private static final TrackedData<Integer> LEVEL = DataTracker.registerData(SpellcastEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||
private static final TrackedData<Optional<UUID>> OWNER = DataTracker.registerData(SpellcastEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
|
||||
|
@ -110,7 +111,7 @@ public class SpellcastEntity extends MobEntityWithAi implements IMagicals, Caste
|
|||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T extends MagicEffect> T getEffect(@Nullable Class<T> type, boolean update) {
|
||||
public <T> T getEffect(@Nullable Class<T> type, boolean update) {
|
||||
return effectDelegate.get(type, update);
|
||||
}
|
||||
|
||||
|
@ -267,7 +268,7 @@ public class SpellcastEntity extends MobEntityWithAi implements IMagicals, Caste
|
|||
@Override
|
||||
public void remove() {
|
||||
if (hasEffect()) {
|
||||
getEffect().setDead();
|
||||
getEffect().onDestroyed(this);
|
||||
}
|
||||
super.remove();
|
||||
}
|
||||
|
@ -362,4 +363,14 @@ public class SpellcastEntity extends MobEntityWithAi implements IMagicals, Caste
|
|||
compound.put("effect", SpellRegistry.instance().serializeEffectToNBT(getEffect()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNearbySpellChange(Caster<?> source, MagicEffect effect, int newState) {
|
||||
if (hasEffect()) {
|
||||
EtherialListener listener = getEffect(EtherialListener.class, true);
|
||||
if (listener != null) {
|
||||
listener.onNearbySpellChange(source, effect, newState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -382,7 +382,7 @@ public class Pony implements Caster<PlayerEntity>, Ponylike<PlayerEntity>, Trans
|
|||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T extends MagicEffect> T getEffect(@Nullable Class<T> type, boolean update) {
|
||||
public <T> T getEffect(@Nullable Class<T> type, boolean update) {
|
||||
return effectDelegate.get(type, update);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.stream.Stream;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.AwaitTickQueue;
|
||||
import com.minelittlepony.unicopia.entity.IMagicals;
|
||||
import com.minelittlepony.unicopia.entity.Owned;
|
||||
import com.minelittlepony.unicopia.particles.ParticleSource;
|
||||
|
@ -39,7 +40,7 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
|
|||
* Returns null if no such effect exists for this caster.
|
||||
*/
|
||||
@Nullable
|
||||
<T extends MagicEffect> T getEffect(@Nullable Class<T> type, boolean update);
|
||||
<T> T getEffect(@Nullable Class<T> type, boolean update);
|
||||
|
||||
/**
|
||||
* Gets the active effect for this caster updating it if needed.
|
||||
|
@ -134,4 +135,16 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
|
|||
default Stream<Entity> findAllEntitiesInRange(double radius) {
|
||||
return VecHelper.findAllEntitiesInRange(getEntity(), getWorld(), getOrigin(), radius);
|
||||
}
|
||||
|
||||
default void notifyNearbySpells(MagicEffect sender, BlockPos origin, double radius, int newState) {
|
||||
AwaitTickQueue.enqueueTask(w -> {
|
||||
VecHelper.findAllEntitiesInRange(getEntity(), getWorld(), origin, radius).filter(i -> i instanceof EtherialListener).forEach(i -> {
|
||||
((EtherialListener)i).onNearbySpellChange(this, sender, newState);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
default void notifyNearbySpells(MagicEffect sender, double radius, int newState) {
|
||||
notifyNearbySpells(sender, getOrigin(), radius, newState);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package com.minelittlepony.unicopia.magic;
|
||||
|
||||
/**
|
||||
* A change listener for when a magic spell is either placed or destroyed in the world.
|
||||
*/
|
||||
public interface EtherialListener {
|
||||
int REMOVED = 0x0;
|
||||
int ADDED = 0x1;
|
||||
|
||||
/**
|
||||
* Called when a nearby spell is added or removed.
|
||||
*
|
||||
* @param source The casting source of the sending spell
|
||||
* @param effect The spell that dispatched the event
|
||||
* @param state The new state
|
||||
*/
|
||||
void onNearbySpellChange(Caster<?> source, MagicEffect effect, int state);
|
||||
}
|
|
@ -65,6 +65,13 @@ public interface MagicEffect extends NbtSerialisable, Affine {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a gem is destroyed.
|
||||
*/
|
||||
default void onDestroyed(Caster<?> caster) {
|
||||
setDead();
|
||||
}
|
||||
|
||||
default boolean handleProjectileImpact(ProjectileEntity projectile) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.magic;
|
|||
/**
|
||||
* Magic effects that can be suppressed by other nearby effects.
|
||||
*/
|
||||
public interface SuppressableEffect extends MagicEffect {
|
||||
public interface Suppressable {
|
||||
|
||||
/**
|
||||
* Returns true if this spell is currently still suppressed.
|
|
@ -7,14 +7,13 @@ import javax.annotation.Nullable;
|
|||
|
||||
import com.minelittlepony.unicopia.entity.SpellcastEntity;
|
||||
import com.minelittlepony.unicopia.magic.Caster;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Box;
|
||||
|
||||
public abstract class AbstractAttachableSpell extends AbstractSpell {
|
||||
public abstract class AbstractLinkedSpell extends AbstractSpell {
|
||||
|
||||
protected boolean searching = true;
|
||||
|
|
@ -1,18 +1,33 @@
|
|||
package com.minelittlepony.unicopia.magic.spell;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.magic.Affinity;
|
||||
import com.minelittlepony.unicopia.magic.Caster;
|
||||
import com.minelittlepony.unicopia.magic.EtherialListener;
|
||||
import com.minelittlepony.unicopia.magic.MagicEffect;
|
||||
import com.minelittlepony.unicopia.particles.MagicParticleEffect;
|
||||
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
import com.minelittlepony.unicopia.util.VecHelper;
|
||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class AttractiveSpell extends ShieldSpell {
|
||||
public class AttractiveSpell extends ShieldSpell implements EtherialListener {
|
||||
|
||||
@Nullable
|
||||
private BlockPos homingPos;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
|
@ -44,9 +59,21 @@ public class AttractiveSpell extends ShieldSpell {
|
|||
return 10 + (caster.getCurrentLevel() * 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Entity> getTargets(Caster<?> source, double radius) {
|
||||
|
||||
if (homingPos != null) {
|
||||
return VecHelper.findAllEntitiesInRange(source.getEntity(), source.getWorld(), source.getOrigin(), radius)
|
||||
.filter(i -> i instanceof ItemEntity)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return super.getTargets(source, radius);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyRadialEffect(Caster<?> source, Entity target, double distance, double radius) {
|
||||
Vec3d pos = source.getOriginVector();
|
||||
Vec3d pos = homingPos == null ? source.getOriginVector() : new Vec3d(homingPos);
|
||||
|
||||
double force = 2.5F / distance;
|
||||
|
||||
|
@ -74,4 +101,37 @@ public class AttractiveSpell extends ShieldSpell {
|
|||
|
||||
target.setVelocity(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNearbySpellChange(Caster<?> source, MagicEffect effect, int newState) {
|
||||
if (effect instanceof ChargingSpell && !isDead()) {
|
||||
if (newState == ADDED) {
|
||||
if (homingPos == null) {
|
||||
homingPos = source.getOrigin();
|
||||
}
|
||||
setDirty(true);
|
||||
} else if (homingPos.equals(source.getOrigin())) {
|
||||
setDead();
|
||||
setDirty(true);
|
||||
source.notifyNearbySpells(this, 5, REMOVED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toNBT(CompoundTag compound) {
|
||||
super.toNBT(compound);
|
||||
if (homingPos != null) {
|
||||
compound.put("homingPos", NbtSerialisable.writeBlockPos(homingPos));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromNBT(CompoundTag compound) {
|
||||
super.fromNBT(compound);
|
||||
if (compound.contains("homingPos")) {
|
||||
homingPos = NbtSerialisable.readBlockPos(compound.getCompound("homingPos"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ public class ChangelingTrapSpell extends AbstractSpell implements TossedMagicEff
|
|||
|
||||
if (caster.isLocal()) {
|
||||
if (struggleCounter <= 0) {
|
||||
setDead();
|
||||
onDestroyed(caster);
|
||||
setDirty(true);
|
||||
|
||||
WorldEvent.DESTROY_BLOCK.play(caster.getWorld(), origin, Blocks.SLIME_BLOCK.getDefaultState());
|
||||
|
@ -166,7 +166,7 @@ public class ChangelingTrapSpell extends AbstractSpell implements TossedMagicEff
|
|||
struggleCounter = 10;
|
||||
|
||||
if (caster.isLocal() && caster.getWorld().random.nextInt(3) == 0) {
|
||||
setDead();
|
||||
onDestroyed(caster);
|
||||
|
||||
CuccoonEntity cuccoon = UEntities.CUCCOON.create(caster.getWorld());
|
||||
cuccoon.copyPositionAndRotation(caster.getEntity());
|
||||
|
|
|
@ -3,6 +3,8 @@ package com.minelittlepony.unicopia.magic.spell;
|
|||
import com.minelittlepony.unicopia.entity.SpellcastEntity;
|
||||
import com.minelittlepony.unicopia.magic.Affinity;
|
||||
import com.minelittlepony.unicopia.magic.Caster;
|
||||
import com.minelittlepony.unicopia.magic.EtherialListener;
|
||||
import com.minelittlepony.unicopia.magic.MagicEffect;
|
||||
import com.minelittlepony.unicopia.particles.MagicParticleEffect;
|
||||
import com.minelittlepony.unicopia.util.shape.Shape;
|
||||
import com.minelittlepony.unicopia.util.shape.Line;
|
||||
|
@ -10,7 +12,7 @@ import com.minelittlepony.unicopia.util.shape.Line;
|
|||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class ChargingSpell extends AbstractAttachableSpell {
|
||||
public class ChargingSpell extends AbstractLinkedSpell implements EtherialListener {
|
||||
|
||||
private static final Box searchArea = new Box(-15, -15, -15, 15, 15, 15);
|
||||
|
||||
|
@ -71,4 +73,24 @@ public class ChargingSpell extends AbstractAttachableSpell {
|
|||
|
||||
return !isDead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaced(Caster<?> caster) {
|
||||
caster.notifyNearbySpells(this, 12, ADDED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
super.onDestroyed(caster);
|
||||
caster.notifyNearbySpells(this, 12, REMOVED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNearbySpellChange(Caster<?> source, MagicEffect effect, int newState) {
|
||||
if (effect instanceof AttractiveSpell && !isDead()) {
|
||||
setDead();
|
||||
setDirty(true);
|
||||
source.notifyNearbySpells(this, 12, newState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import net.minecraft.util.math.BlockPos;
|
|||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class DarknessSpell extends AbstractAttachableSpell {
|
||||
public class DarknessSpell extends AbstractLinkedSpell {
|
||||
|
||||
private static final Box searchArea = new Box(-5, -5, -5, 5, 5, 5);
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import com.minelittlepony.unicopia.magic.CasterUtils;
|
|||
import com.minelittlepony.unicopia.magic.AttachedMagicEffect;
|
||||
import com.minelittlepony.unicopia.magic.Caster;
|
||||
import com.minelittlepony.unicopia.magic.MagicEffect;
|
||||
import com.minelittlepony.unicopia.magic.SuppressableEffect;
|
||||
import com.minelittlepony.unicopia.magic.Suppressable;
|
||||
import com.minelittlepony.unicopia.particles.MagicParticleEffect;
|
||||
import com.minelittlepony.unicopia.particles.UParticles;
|
||||
import com.minelittlepony.unicopia.util.projectile.ProjectileUtil;
|
||||
|
@ -45,7 +45,7 @@ import net.minecraft.entity.vehicle.MinecartEntity;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
public class DisguiseSpell extends AbstractSpell implements AttachedMagicEffect, SuppressableEffect, FlightPredicate, HeightPredicate {
|
||||
public class DisguiseSpell extends AbstractSpell implements AttachedMagicEffect, Suppressable, FlightPredicate, HeightPredicate {
|
||||
|
||||
@Nonnull
|
||||
private String entityId = "";
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.minelittlepony.unicopia.magic.spell;
|
|||
|
||||
import com.minelittlepony.unicopia.magic.Affinity;
|
||||
import com.minelittlepony.unicopia.magic.Caster;
|
||||
import com.minelittlepony.unicopia.magic.SuppressableEffect;
|
||||
import com.minelittlepony.unicopia.magic.Suppressable;
|
||||
import com.minelittlepony.unicopia.particles.MagicParticleEffect;
|
||||
import com.minelittlepony.unicopia.util.shape.Shape;
|
||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||
|
@ -32,7 +32,7 @@ public class RevealingSpell extends AbstractSpell {
|
|||
@Override
|
||||
public boolean update(Caster<?> source) {
|
||||
source.findAllSpellsInRange(15).forEach(e -> {
|
||||
SuppressableEffect spell = e.getEffect(SuppressableEffect.class, false);
|
||||
Suppressable spell = e.getEffect(Suppressable.class, false);
|
||||
|
||||
if (spell != null && spell.isVulnerable(source, this)) {
|
||||
spell.onSuppressed(source);
|
||||
|
|
|
@ -66,7 +66,7 @@ public class ShieldSpell extends AbstractRangedAreaSpell implements AttachedMagi
|
|||
cost *= costMultiplier / 5F;
|
||||
|
||||
if (!source.subtractEnergyCost(cost)) {
|
||||
setDead();
|
||||
onDestroyed(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,21 +84,25 @@ public class ShieldSpell extends AbstractRangedAreaSpell implements AttachedMagi
|
|||
return true;
|
||||
}
|
||||
|
||||
protected int applyEntities(Caster<?> source) {
|
||||
double radius = getDrawDropOffRange(source);
|
||||
protected List<Entity> getTargets(Caster<?> source, double radius) {
|
||||
|
||||
Entity owner = source.getOwner();
|
||||
|
||||
boolean ownerIsValid = source.getAffinity() != Affinity.BAD && EquinePredicates.PLAYER_UNICORN.test(owner);
|
||||
|
||||
Vec3d origin = source.getOriginVector();
|
||||
|
||||
List<Entity> targets = source.findAllEntitiesInRange(radius)
|
||||
return source.findAllEntitiesInRange(radius)
|
||||
.filter(entity -> !(ownerIsValid && (
|
||||
entity.equals(owner)
|
||||
|| (entity instanceof PlayerEntity && owner instanceof PlayerEntity && Pony.equal((PlayerEntity)entity, (PlayerEntity)owner)))))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected int applyEntities(Caster<?> source) {
|
||||
double radius = getDrawDropOffRange(source);
|
||||
|
||||
Vec3d origin = source.getOriginVector();
|
||||
|
||||
List<Entity> targets = getTargets(source, radius);
|
||||
targets.forEach(i -> {
|
||||
try {
|
||||
double dist = i.getPos().distanceTo(origin);
|
||||
|
|
|
@ -84,7 +84,7 @@ public class SiphoningSpell extends AbstractRangedAreaSpell {
|
|||
|
||||
if (maxHealthGain <= 0) {
|
||||
if (source.getWorld().random.nextInt(30) == 0) {
|
||||
setDead();
|
||||
onDestroyed(source);
|
||||
} else {
|
||||
e.damage(damage, e.getHealth() / 4);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ public class EffectSync {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E extends MagicEffect> E get(Class<E> type, boolean update) {
|
||||
public <E> E get(Class<E> type, boolean update) {
|
||||
if (!update) {
|
||||
if (effect == null || type == null || type.isAssignableFrom(effect.getClass())) {
|
||||
return (E)effect;
|
||||
|
|
Loading…
Reference in a new issue