Fixed spell levels not being saved, fixed shields, fixed the drake gem

This commit is contained in:
Sollace 2019-02-05 14:44:35 +02:00
parent 765d647018
commit 4e59f141b6
15 changed files with 254 additions and 121 deletions

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.entity;
import javax.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import com.minelittlepony.unicopia.Predicates;
@ -79,12 +81,15 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
}
@Override
public void setEffect(IMagicEffect effect) {
public void setEffect(@Nullable IMagicEffect effect) {
effectDelegate.set(effect);
effect.onPlaced(this);
if (effect != null) {
effect.onPlaced(this);
}
}
@Nullable
@Override
public IMagicEffect getEffect() {
return effectDelegate.get();
@ -174,7 +179,7 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
displayTick();
}
if (getEffect() == null) {
if (!hasEffect()) {
setDead();
} else {
if (getEffect().getDead()) {
@ -274,8 +279,8 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
}
public boolean tryLevelUp(ItemStack stack) {
if (SpellRegistry.stackHasEnchantment(stack)) {
if (!getEffect().getName().equals(SpellRegistry.getKeyFromStack(stack))) {
if (hasEffect() && SpellRegistry.stackHasEnchantment(stack)) {
if (!getEffect().getName().contentEquals(SpellRegistry.getKeyFromStack(stack))) {
return false;
}

View file

@ -1,48 +1,142 @@
package com.minelittlepony.unicopia.entity.ai;
import java.lang.reflect.Field;
import com.google.common.base.Predicate;
import com.minelittlepony.unicopia.forgebullshit.RegistryLockSpinner;
import com.minelittlepony.unicopia.spell.ICaster;
import net.minecraft.entity.Entity;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAIFollow;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.pathfinding.PathNavigate;
import net.minecraft.pathfinding.PathNavigateFlying;
import net.minecraft.pathfinding.PathNavigateGround;
import net.minecraft.pathfinding.PathNodeType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
public class EntityAIFollowCaster extends EntityAIFollow {
public class EntityAIFollowCaster<T extends EntityLivingBase> extends EntityAIBase {
protected final ICaster<?> entity;
protected final ICaster<?> casted;
private static Field __followPredicate;
protected final EntityLiving entity;
static {
try {
Field f = EntityAIFollow.class.getDeclaredFields()[1];
f.setAccessible(true);
__followPredicate = RegistryLockSpinner.makeNonFinal(f);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
__followPredicate = null;
protected EntityLivingBase owner;
protected final World world;
public final double followSpeed;
private final PathNavigate petPathfinder;
private int timeout;
public float maxDist;
public float minDist;
private float oldWaterCost;
public EntityAIFollowCaster(ICaster<T> casted, double followSpeed, float minDist, float maxDist) {
this.casted = casted;
this.entity = (EntityLiving)casted.getEntity();
this.world = casted.getWorld();
this.followSpeed = followSpeed;
this.petPathfinder = entity.getNavigator();
this.minDist = minDist;
this.maxDist = maxDist;
this.setMutexBits(3);
if (!(petPathfinder instanceof PathNavigateGround || petPathfinder instanceof PathNavigateFlying)) {
throw new IllegalArgumentException("Unsupported mob type for FollowOwnerGoal");
}
}
public EntityAIFollowCaster(ICaster<?> caster, double walkSpeed, float maxDistance, float area) {
super((EntityLiving)caster.getEntity(), walkSpeed, maxDistance, area);
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute() {
EntityLivingBase owner = casted.getOwner();
entity = caster;
if (owner == null
|| (owner instanceof EntityPlayer && ((EntityPlayer)owner).isSpectator())
|| entity.getDistanceSq(owner) < (minDist * minDist)) {
return false;
}
if (__followPredicate != null) {
try {
__followPredicate.set(this, (Predicate<EntityLivingBase>)(e -> {
Entity owner = caster.getOwner();
return e != null && (e == owner || (owner != null && owner.getUniqueID().equals(e.getUniqueID())));
}));
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
this.owner = owner;
return true;
}
@Override
public boolean shouldContinueExecuting() {
return !petPathfinder.noPath()
&& entity.getDistanceSq(owner) > (maxDist * maxDist);
}
@Override
public void startExecuting() {
timeout = 0;
oldWaterCost = entity.getPathPriority(PathNodeType.WATER);
entity.setPathPriority(PathNodeType.WATER, 0);
}
@Override
public void resetTask() {
owner = null;
petPathfinder.clearPath();
entity.setPathPriority(PathNodeType.WATER, oldWaterCost);
}
@Override
public void updateTask() {
entity.getLookHelper().setLookPositionWithEntity(owner, 10, entity.getVerticalFaceSpeed());
if (--timeout > 0) {
return;
}
timeout = 10;
if (petPathfinder.tryMoveToEntityLiving(owner, followSpeed)
|| entity.getLeashed()
|| entity.isRiding()
|| entity.getDistanceSq(owner) < 144) {
return;
}
int x = MathHelper.floor(owner.posX) - 2;
int y = MathHelper.floor(owner.getEntityBoundingBox().minY);
int z = MathHelper.floor(owner.posZ) - 2;
for (int offX = 0; offX <= 4; offX++) {
for (int offZ = 0; offZ <= 4; offZ++) {
if (canTeleport(x, y, z, offX, offZ)) {
entity.setLocationAndAngles((x + offX) + 0.5F, y, (z + offZ) + 0.5F, entity.rotationYaw, entity.rotationPitch);
petPathfinder.clearPath();
return;
}
}
}
}
}
protected boolean canTeleport(int x, int y, int z, int xOffset, int zOffset) {
if (xOffset < 1 || zOffset < 1 || xOffset > 3 || zOffset > 3) {
return true;
}
BlockPos pos = new BlockPos(x + xOffset, y - 1, z + zOffset);
IBlockState state = world.getBlockState(pos);
return state.getBlockFaceShape(world, pos, EnumFacing.DOWN) == BlockFaceShape.SOLID
&& state.canEntitySpawn(entity)
&& world.isAirBlock(pos.up())
&& world.isAirBlock(pos.up(2));
}
}

View file

@ -104,7 +104,9 @@ public class ModelGem extends ModelBase {
setLightingConditionsBrightness(0xF0F0);
Color.glColor(spell.getEffect().getTint(), 1);
if (spell.hasEffect()) {
Color.glColor(spell.getEffect().getTint(), 1);
}
int tiers = Math.min(spell.getCurrentLevel(), 5);
@ -144,10 +146,7 @@ public class ModelGem extends ModelBase {
}
protected void renderOverlay(float grow, float scale) {
body.render(scale);
}
private void setLightingConditionsBrightness(int brightness) {

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.network;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.spell.ICaster;
import com.minelittlepony.unicopia.spell.IMagicEffect;
import com.minelittlepony.unicopia.spell.SpellRegistry;
@ -9,6 +11,8 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
public class EffectSync<T extends EntityLivingBase> {
@Nullable
private IMagicEffect effect;
private final ICaster<T> owned;
@ -49,7 +53,7 @@ public class EffectSync<T extends EntityLivingBase> {
return effect;
}
public void set(IMagicEffect effect) {
public void set(@Nullable IMagicEffect effect) {
if (this.effect != null && this.effect != effect) {
this.effect.setDead();
}

View file

@ -327,12 +327,13 @@ class PlayerCapabilities implements IPlayer {
}
@Override
public void setEffect(IMagicEffect effect) {
public void setEffect(@Nullable IMagicEffect effect) {
effectDelegate.set(effect);
sendCapabilities(true);
}
@Nullable
@Override
public IMagicEffect getEffect() {
return effectDelegate.get();

View file

@ -1,17 +1,21 @@
package com.minelittlepony.unicopia.spell;
import net.minecraft.nbt.NBTTagCompound;
public abstract class AbstractSpell implements IMagicEffect {
protected boolean isDead = false;
private int strength = 0;
@Override
public int getCurrentLevel() {
return 0;
return strength;
}
@Override
public void setCurrentLevel(int level) {
strength = level;
}
@Override
@ -28,4 +32,16 @@ public abstract class AbstractSpell implements IMagicEffect {
public boolean getDead() {
return isDead;
}
@Override
public void writeToNBT(NBTTagCompound compound) {
compound.setBoolean("dead", isDead);
compound.setInteger("spell_strength", strength);
}
@Override
public void readFromNBT(NBTTagCompound compound) {
isDead = compound.getBoolean("dead");
strength = compound.getInteger("spell_strength");
}
}

View file

@ -5,6 +5,8 @@ import java.util.UUID;
import java.util.function.Consumer;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.player.IOwned;
import com.minelittlepony.util.shape.IShape;
import com.minelittlepony.util.vector.VecHelper;
@ -17,8 +19,9 @@ import net.minecraft.world.World;
public interface ICaster<E extends EntityLivingBase> extends IOwned<E>, ILevelled, IAligned {
void setEffect(IMagicEffect effect);
void setEffect(@Nullable IMagicEffect effect);
@Nullable
IMagicEffect getEffect();
default boolean hasEffect() {

View file

@ -83,4 +83,8 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned {
default boolean allowAI() {
return false;
}
default IMagicEffect copy() {
return SpellRegistry.instance().copyInstance(this);
}
}

View file

@ -18,8 +18,6 @@ import net.minecraft.util.math.Vec3d;
public class SpellCharge extends AbstractSpell {
private int desiredLevel = 0;
boolean searching = true;
private UUID targettedEntityId;
@ -115,30 +113,21 @@ public class SpellCharge extends AbstractSpell {
return 2;
}
@Override
public int getCurrentLevel() {
return desiredLevel;
}
@Override
public void setCurrentLevel(int level) {
desiredLevel = level;
}
@Override
public void writeToNBT(NBTTagCompound compound) {
super.writeToNBT(compound);
if (targettedEntityId != null) {
compound.setUniqueId("target", targettedEntityId);
}
compound.setInteger("level", desiredLevel);
}
@Override
public void readFromNBT(NBTTagCompound compound) {
super.readFromNBT(compound);
if (compound.hasKey("target")) {
targettedEntityId = compound.getUniqueId("target");
}
desiredLevel = compound.getInteger("level");
}
}

View file

@ -208,6 +208,7 @@ public class SpellDisguise extends AbstractSpell {
@Override
public void writeToNBT(NBTTagCompound compound) {
super.writeToNBT(compound);
compound.setString("entityId", entityId);
compound.setBoolean("dead", getDead());
@ -225,6 +226,8 @@ public class SpellDisguise extends AbstractSpell {
@Override
public void readFromNBT(NBTTagCompound compound) {
super.readFromNBT(compound);
String newId = compound.getString("entityId");
if (!newId.contentEquals(entityId)) {

View file

@ -49,7 +49,7 @@ public class SpellDrake extends AbstractSpell {
}
public boolean getDead() {
return super.getDead() || (piggyBackSpell != null && piggyBackSpell.getDead());
return super.getDead();
}
@Override
@ -58,28 +58,36 @@ public class SpellDrake extends AbstractSpell {
if (firstUpdate) {
firstUpdate = false;
if (source.getOwner() instanceof EntitySpell) {
EntitySpell living = (EntitySpell)source.getOwner();
if (source.getEntity() instanceof EntitySpell) {
EntitySpell living = (EntitySpell)source.getEntity();
((PathNavigateGround)living.getNavigator()).setCanSwim(false);
living.tasks.addTask(1, new EntityAISwimming(living));
living.tasks.addTask(2, new EntityAIFollowCaster(source, 1, 4, 6));
living.tasks.addTask(2, new EntityAIFollowCaster<>(source, 1, 4, 70));
}
}
if (piggyBackSpell == null) {
AxisAlignedBB bb = EFFECT_BOUNDS.offset(source.getOriginVector());
if (!source.getWorld().isRemote) {
source.getWorld().getEntitiesInAABBexcluding(source.getEntity(), bb, e -> e instanceof EntitySpell).stream()
.map(i -> (EntitySpell)i)
.filter(i -> i.getEffect() != null && !(i.getEffect() instanceof SpellDrake))
.findFirst().ifPresent(i -> {
piggyBackSpell = i.getEffect();
i.setEffect(null);
});
if (piggyBackSpell == null) {
AxisAlignedBB bb = EFFECT_BOUNDS.offset(source.getOriginVector());
source.getWorld().getEntitiesInAABBexcluding(source.getEntity(), bb, e -> e instanceof EntitySpell).stream()
.map(i -> (EntitySpell)i)
.filter(i -> i.hasEffect() && !(i.getEffect() instanceof SpellDrake))
.findFirst().ifPresent(i -> {
piggyBackSpell = i.getEffect().copy();
piggyBackSpell.onPlaced(source);
i.setEffect(null);
});
}
}
return piggyBackSpell != null && piggyBackSpell.update(source, level);
if (piggyBackSpell != null) {
piggyBackSpell.update(source, level);
}
return true;
}
@Override
@ -89,7 +97,10 @@ public class SpellDrake extends AbstractSpell {
}
}
@Override
public void writeToNBT(NBTTagCompound compound) {
super.writeToNBT(compound);
if (piggyBackSpell != null) {
compound.setTag("effect", SpellRegistry.instance().serializeEffectToNBT(piggyBackSpell));
}
@ -97,6 +108,8 @@ public class SpellDrake extends AbstractSpell {
@Override
public void readFromNBT(NBTTagCompound compound) {
super.readFromNBT(compound);
if (compound.hasKey("effect")) {
piggyBackSpell = SpellRegistry.instance().createEffectFromNBT(compound.getCompoundTag("effect"));
}

View file

@ -290,6 +290,8 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
@Override
public void writeToNBT(NBTTagCompound compound) {
super.writeToNBT(compound);
if (destinationPos != null) {
compound.setTag("destination", InbtSerialisable.writeBlockPos(destinationPos));
}
@ -307,6 +309,8 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
@Override
public void readFromNBT(NBTTagCompound compound) {
super.readFromNBT(compound);
if (compound.hasKey("destination")) {
destinationPos = InbtSerialisable.readBlockPos(compound.getCompoundTag("destination"));
}

View file

@ -53,6 +53,11 @@ public class SpellRegistry {
return null;
}
@SuppressWarnings("unchecked")
public <T extends IMagicEffect> T copyInstance(T effect) {
return (T)createEffectFromNBT(serializeEffectToNBT(effect));
}
public IMagicEffect createEffectFromNBT(NBTTagCompound compound) {
if (compound.hasKey("effect_id")) {
IMagicEffect effect = getSpellFromName(compound.getString("effect_id"));

View file

@ -13,23 +13,10 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.Vec3d;
public class SpellShield extends AbstractSpell {
private int strength = 0;
@Override
public int getCurrentLevel() {
return strength;
}
@Override
public void setCurrentLevel(int level) {
strength = level;
}
@Override
public String getName() {
return "shield";
@ -52,43 +39,51 @@ public class SpellShield extends AbstractSpell {
@Override
public void render(ICaster<?> source, int level) {
spawnParticles(source, 4 + (level * 2));
}
level = 4 + (level * 2);
protected void spawnParticles(ICaster<?> source, int strength) {
source.spawnParticles(new Sphere(true, strength), strength * 6, pos -> {
Particles.instance().spawnParticle(UParticles.UNICORN_MAGIC, false, pos, 0, 0, 0);
});
source.spawnParticles(new Sphere(true, level), level * 6, pos -> {
Particles.instance().spawnParticle(UParticles.UNICORN_MAGIC, false, pos, 0, 0, 0);
});
}
@Override
public boolean updateOnPerson(ICaster<?> source) {
update(source, strength);
if (source.getEntity().getEntityWorld().getWorldTime() % 50 == 0) {
double radius = 4 + (strength * 2);
if (!IPower.takeFromPlayer((EntityPlayer)source.getOwner(), radius/4)) {
setDead();
}
}
if (super.updateOnPerson(source)) {
if (source.getEntity().getEntityWorld().getWorldTime() % 50 == 0) {
double radius = 4 + (getCurrentLevel() * 2);
if (!IPower.takeFromPlayer((EntityPlayer)source.getOwner(), radius/4)) {
setDead();
}
}
}
return !getDead();
}
protected double getDrawDropOffRange(int level) {
return 4 + (level * 2);
}
@Override
public boolean update(ICaster<?> source, int level) {
double radius = 4 + (level * 2);
double radius = getDrawDropOffRange(level);
Entity owner = source.getOwner();
boolean ownerIsValid = source.getAffinity() != SpellAffinity.BAD && Predicates.MAGI.test(owner);
Vec3d origin = source.getOriginVector();
source.findAllEntitiesInRange(radius)
.filter(entity -> !(ownerIsValid && entity.equals(owner)))
.forEach(i -> {
double dist = Math.sqrt(i.getDistanceSq(source.getOrigin()));
try {
double dist = i.getPositionVector().distanceTo(origin);
applyRadialEffect(source, i, dist, radius);
applyRadialEffect(source, i, dist, radius);
} catch (Throwable e) {
e.printStackTrace();
}
});
return true;
@ -107,10 +102,12 @@ public class SpellShield extends AbstractSpell {
}
}
} else if (target instanceof EntityLivingBase) {
double force = Math.min(0.25F, distance);
double force = Math.max(0.1, radius / 4);
if (source.getAffinity() != SpellAffinity.BAD && target instanceof EntityPlayer) {
force *= calculateAdjustedForce(PlayerSpeciesList.instance().getPlayer((EntityPlayer)target));
} else {
force *= 0.75;
}
applyForce(pos, target, force, distance);
@ -121,12 +118,12 @@ public class SpellShield extends AbstractSpell {
* Applies a force to the given entity based on distance from the source.
*/
protected void applyForce(Vec3d pos, Entity target, double force, double distance) {
pos = target.getPositionVector().subtract(pos);
pos = target.getPositionVector().subtract(pos).normalize().scale(force);
target.addVelocity(
force / pos.x,
force / pos.y + (distance < 1 ? distance : 0),
force / pos.z
pos.x,
pos.y + (distance < 1 ? distance : 0),
pos.z
);
}
@ -163,14 +160,4 @@ public class SpellShield extends AbstractSpell {
ProjectileUtil.setThrowableHeading(projectile, normal, (float)motion.length(), 0);
}
}
@Override
public void writeToNBT(NBTTagCompound compound) {
compound.setInteger("spell_strength", strength);
}
@Override
public void readFromNBT(NBTTagCompound compound) {
strength = compound.getInteger("spell_strength");
}
}

View file

@ -23,19 +23,25 @@ public class SpellVortex extends SpellShield {
}
@Override
protected void spawnParticles(ICaster<?> source, int strength) {
public void render(ICaster<?> source, int level) {
level = 4 + (level * 2);
Vec3d pos = source.getOriginVector();
source.spawnParticles(new Sphere(false, strength), strength * 9, p -> {
source.spawnParticles(new Sphere(false, level), level * 9, p -> {
Particles.instance().spawnParticle(UParticles.UNICORN_MAGIC, false, p, p.subtract(pos));
});
}
@Override
protected double getDrawDropOffRange(int level) {
return 10 + (level * 2);
}
@Override
protected void applyRadialEffect(ICaster<?> source, Entity target, double distance, double radius) {
Vec3d pos = source.getOriginVector();
double force = 4 / distance;
double force = 2.5F / distance;
if (source.getAffinity() != SpellAffinity.BAD && target instanceof EntityPlayer) {
force *= calculateAdjustedForce(PlayerSpeciesList.instance().getPlayer((EntityPlayer)target));