mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-20 03:44:23 +01:00
Fixed long-distance travel (Part 2)
This commit is contained in:
parent
42b856aa3d
commit
1ed677eab6
6 changed files with 186 additions and 76 deletions
|
@ -80,6 +80,8 @@ public class EntitySpell extends EntityLiving implements IMagicals, ICaster<Enti
|
||||||
@Override
|
@Override
|
||||||
public void setEffect(IMagicEffect effect) {
|
public void setEffect(IMagicEffect effect) {
|
||||||
effectDelegate.set(effect);
|
effectDelegate.set(effect);
|
||||||
|
|
||||||
|
effect.onPlaced(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,8 +27,9 @@ public interface ICastable extends IMagicalItem {
|
||||||
EntitySpell spell = new EntitySpell(world);
|
EntitySpell spell = new EntitySpell(world);
|
||||||
|
|
||||||
spell.setAffinity(getAffinity(stack));
|
spell.setAffinity(getAffinity(stack));
|
||||||
spell.setEffect(effect);
|
|
||||||
spell.setLocationAndAngles(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 0, 0);
|
spell.setLocationAndAngles(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 0, 0);
|
||||||
|
spell.setEffect(effect);
|
||||||
|
|
||||||
world.spawnEntity(spell);
|
world.spawnEntity(spell);
|
||||||
|
|
||||||
return spell;
|
return spell;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.minelittlepony.unicopia.spell;
|
package com.minelittlepony.unicopia.spell;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -33,6 +34,10 @@ public interface ICaster<E extends EntityLivingBase> extends IOwned<E>, ILevelle
|
||||||
return getOwner();
|
return getOwner();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default UUID getUniqueId() {
|
||||||
|
return getEntity().getUniqueID();
|
||||||
|
}
|
||||||
|
|
||||||
default World getWorld() {
|
default World getWorld() {
|
||||||
return getEntity().getEntityWorld();
|
return getEntity().getEntityWorld();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,13 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled {
|
||||||
*/
|
*/
|
||||||
boolean getDead();
|
boolean getDead();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when first attached to a gem.
|
||||||
|
*/
|
||||||
|
default void onPlaced(ICaster<?> caster) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called every tick when attached to a player.
|
* Called every tick when attached to a player.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.spell;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -12,6 +13,7 @@ import com.minelittlepony.unicopia.entity.EntitySpell;
|
||||||
import com.minelittlepony.unicopia.entity.IMagicals;
|
import com.minelittlepony.unicopia.entity.IMagicals;
|
||||||
import com.minelittlepony.unicopia.player.IPlayer;
|
import com.minelittlepony.unicopia.player.IPlayer;
|
||||||
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
|
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
|
||||||
|
import com.minelittlepony.unicopia.util.serialisation.InbtSerialisable;
|
||||||
import com.minelittlepony.util.shape.IShape;
|
import com.minelittlepony.util.shape.IShape;
|
||||||
import com.minelittlepony.util.shape.Sphere;
|
import com.minelittlepony.util.shape.Sphere;
|
||||||
|
|
||||||
|
@ -25,6 +27,7 @@ import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.SoundCategory;
|
import net.minecraft.util.SoundCategory;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldServer;
|
||||||
|
|
||||||
public class SpellPortal extends AbstractSpell implements IUseAction {
|
public class SpellPortal extends AbstractSpell implements IUseAction {
|
||||||
|
|
||||||
|
@ -35,10 +38,6 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
|
||||||
private static final AxisAlignedBB TELEPORT_BOUNDS_VERT = new AxisAlignedBB(-1, -0.5, -1, 1, 0.5, 1);
|
private static final AxisAlignedBB TELEPORT_BOUNDS_VERT = new AxisAlignedBB(-1, -0.5, -1, 1, 0.5, 1);
|
||||||
private static final AxisAlignedBB TELEPORT_BOUNDS = new AxisAlignedBB(-0.5, -0.5, -0.5, 0.5, 3, 0.5);
|
private static final AxisAlignedBB TELEPORT_BOUNDS = new AxisAlignedBB(-0.5, -0.5, -0.5, 0.5, 3, 0.5);
|
||||||
|
|
||||||
private static final AxisAlignedBB DESTINATION_BOUNDS = new AxisAlignedBB(0, 0, 0, 1.5F, 1.5F, 1.5F);
|
|
||||||
|
|
||||||
private int cooldown = 0;
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private SpellPortal sibling = null;
|
private SpellPortal sibling = null;
|
||||||
|
|
||||||
|
@ -50,6 +49,14 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
|
||||||
|
|
||||||
private EnumFacing.Axis axis = EnumFacing.Axis.Y;
|
private EnumFacing.Axis axis = EnumFacing.Axis.Y;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private UUID casterId;
|
||||||
|
|
||||||
|
private World world;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private UUID destinationId;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "portal";
|
return "portal";
|
||||||
|
@ -64,8 +71,22 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
|
||||||
public void setDead() {
|
public void setDead() {
|
||||||
super.setDead();
|
super.setDead();
|
||||||
|
|
||||||
if (sibling != null && !sibling.getDead()) {
|
sibling = null;
|
||||||
sibling.setDead();
|
destinationId = null;
|
||||||
|
destinationPos = null;
|
||||||
|
|
||||||
|
getDestinationPortal().ifPresent(IMagicEffect::setDead);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlaced(ICaster<?> caster) {
|
||||||
|
world = caster.getWorld();
|
||||||
|
casterId = caster.getUniqueId();
|
||||||
|
position = caster.getOrigin();
|
||||||
|
|
||||||
|
if (sibling != null) {
|
||||||
|
sibling.destinationId = casterId;
|
||||||
|
sibling.destinationPos = position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +99,7 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
|
||||||
|
|
||||||
IMagicEffect other = prop.getEffect();
|
IMagicEffect other = prop.getEffect();
|
||||||
if (other instanceof SpellPortal && other != this && !other.getDead()) {
|
if (other instanceof SpellPortal && other != this && !other.getDead()) {
|
||||||
((SpellPortal)other).notifyMatched(this);
|
((SpellPortal)other).getActualInstance().setDestinationPortal(this);
|
||||||
|
|
||||||
if (!world.isRemote) {
|
if (!world.isRemote) {
|
||||||
prop.setEffect(null);
|
prop.setEffect(null);
|
||||||
|
@ -97,11 +118,14 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
|
||||||
return SpellCastResult.NONE;
|
return SpellCastResult.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyMatched(SpellPortal other) {
|
public void setDestinationPortal(SpellPortal other) {
|
||||||
if (sibling == null) {
|
if (!getDestinationPortal().isPresent()) {
|
||||||
sibling = other;
|
sibling = other;
|
||||||
other.sibling = this;
|
other.sibling = this;
|
||||||
|
|
||||||
|
destinationId = other.casterId;
|
||||||
|
other.destinationId = casterId;
|
||||||
|
|
||||||
sibling.destinationPos = position;
|
sibling.destinationPos = position;
|
||||||
destinationPos = sibling.position;
|
destinationPos = sibling.position;
|
||||||
}
|
}
|
||||||
|
@ -115,11 +139,10 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
|
||||||
@Override
|
@Override
|
||||||
public boolean update(ICaster<?> source, int level) {
|
public boolean update(ICaster<?> source, int level) {
|
||||||
if (!source.getWorld().isRemote) {
|
if (!source.getWorld().isRemote) {
|
||||||
getDestinationPortal(source.getWorld()).ifPresent(dest -> {
|
getDestinationPortal().ifPresent(dest ->
|
||||||
if (!dest.getDead()) {
|
source.getWorld().getEntitiesWithinAABB(Entity.class, getTeleportBounds().offset(source.getOrigin())).stream()
|
||||||
teleportNear(source, level);
|
.filter(this::canTeleport)
|
||||||
}
|
.forEach(i -> teleportEntity(source, dest, i)));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -154,58 +177,107 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
|
||||||
return TELEPORT_BOUNDS;
|
return TELEPORT_BOUNDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean teleportNear(ICaster<?> source, int level) {
|
protected boolean canTeleport(Entity i) {
|
||||||
return source.getWorld().getEntitiesWithinAABB(Entity.class, getTeleportBounds().offset(source.getOrigin())).stream().filter(i -> {
|
return !(i instanceof IMagicals) && i.timeUntilPortal == 0;
|
||||||
if (!(i instanceof IMagicals) && i.timeUntilPortal == 0) {
|
|
||||||
EnumFacing.Axis xi = i.getHorizontalFacing().getAxis();
|
|
||||||
|
|
||||||
if (axis != EnumFacing.Axis.Y && xi != axis) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
EnumFacing offset = i.getHorizontalFacing();
|
|
||||||
|
|
||||||
double destX = destinationPos.getX() + (i.posX - source.getOrigin().getX());
|
|
||||||
double destY = destinationPos.getY() + (i.posY - source.getOrigin().getY());
|
|
||||||
double destZ = destinationPos.getZ() + (i.posZ - source.getOrigin().getZ());
|
|
||||||
|
|
||||||
if (axis != EnumFacing.Axis.Y) {
|
|
||||||
destX += offset.getXOffset();
|
|
||||||
destY++;
|
|
||||||
destZ += offset.getZOffset();
|
|
||||||
}
|
|
||||||
|
|
||||||
i.timeUntilPortal = i.getPortalCooldown();
|
|
||||||
|
|
||||||
i.getEntityWorld().playSound(null, i.getPosition(), SoundEvents.BLOCK_END_PORTAL_FRAME_FILL, SoundCategory.PLAYERS, 1, 1);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (sibling.axis != axis) {
|
|
||||||
|
|
||||||
if (xi != sibling.axis) {
|
|
||||||
i.setPositionAndRotation(i.posX, i.posY, i.posZ, i.rotationYaw + 90, i.rotationPitch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i.setPositionAndUpdate(destX, destY, destZ);
|
|
||||||
i.getEntityWorld().playSound(null, i.getPosition(), SoundEvents.BLOCK_END_PORTAL_FRAME_FILL, SoundCategory.PLAYERS, 1, 1);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}).count() > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<SpellPortal> getDestinationPortal(World w) {
|
protected void teleportEntity(ICaster<?> source, SpellPortal dest, Entity i) {
|
||||||
if (sibling == null && destinationPos != null) {
|
EnumFacing.Axis xi = i.getHorizontalFacing().getAxis();
|
||||||
w.getBlockLightOpacity(destinationPos);
|
|
||||||
w.getEntitiesWithinAABB(EntitySpell.class, DESTINATION_BOUNDS.offset(destinationPos)).stream()
|
if (axis != EnumFacing.Axis.Y && xi != axis) {
|
||||||
.filter(i -> i.getEffect() instanceof SpellPortal)
|
return;
|
||||||
.map(i -> (SpellPortal)i.getEffect())
|
}
|
||||||
.findFirst()
|
|
||||||
.ifPresent(s -> sibling = s);
|
EnumFacing offset = i.getHorizontalFacing();
|
||||||
|
|
||||||
|
double destX = dest.position.getX() + (i.posX - source.getOrigin().getX());
|
||||||
|
double destY = dest.position.getY() + (i.posY - source.getOrigin().getY());
|
||||||
|
double destZ = dest.position.getZ() + (i.posZ - source.getOrigin().getZ());
|
||||||
|
|
||||||
|
if (axis != EnumFacing.Axis.Y) {
|
||||||
|
destX += offset.getXOffset();
|
||||||
|
destY++;
|
||||||
|
destZ += offset.getZOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
i.timeUntilPortal = i.getPortalCooldown();
|
||||||
|
|
||||||
|
i.getEntityWorld().playSound(null, i.getPosition(), SoundEvents.BLOCK_END_PORTAL_FRAME_FILL, SoundCategory.PLAYERS, 1, 1);
|
||||||
|
|
||||||
|
if (dest.axis != axis) {
|
||||||
|
if (xi != dest.axis) {
|
||||||
|
i.setPositionAndRotation(i.posX, i.posY, i.posZ, i.rotationYaw + 90, i.rotationPitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i.setPositionAndUpdate(destX, destY, destZ);
|
||||||
|
i.getEntityWorld().playSound(null, i.getPosition(), SoundEvents.BLOCK_END_PORTAL_FRAME_FILL, SoundCategory.PLAYERS, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a possibly dead portal effect into a live one by forcing the owner entity to load.
|
||||||
|
*/
|
||||||
|
protected SpellPortal getActualInstance() {
|
||||||
|
if (world instanceof WorldServer) {
|
||||||
|
Entity i = ((WorldServer)world).getEntityFromUuid(casterId);
|
||||||
|
|
||||||
|
if (i == null) {
|
||||||
|
world.getChunk(position);
|
||||||
|
i = ((WorldServer)world).getEntityFromUuid(casterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i instanceof EntitySpell) {
|
||||||
|
IMagicEffect effect = ((EntitySpell) i).getEffect();
|
||||||
|
|
||||||
|
if (effect instanceof SpellPortal) {
|
||||||
|
return (SpellPortal)effect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets or loads the destination portal.
|
||||||
|
*/
|
||||||
|
public Optional<SpellPortal> getDestinationPortal() {
|
||||||
|
|
||||||
|
if (getDead()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity i = null;
|
||||||
|
|
||||||
|
if (destinationId != null) {
|
||||||
|
i = ((WorldServer)world).getEntityFromUuid(destinationId);
|
||||||
|
|
||||||
|
if (i == null && destinationPos != null) {
|
||||||
|
world.getChunk(destinationPos);
|
||||||
|
i = ((WorldServer)world).getEntityFromUuid(destinationId);
|
||||||
|
|
||||||
|
if (i == null) {
|
||||||
|
setDead();
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i instanceof EntitySpell) {
|
||||||
|
IMagicEffect effect = ((EntitySpell) i).getEffect();
|
||||||
|
|
||||||
|
if (effect instanceof SpellPortal) {
|
||||||
|
sibling = (SpellPortal)effect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sibling != null && sibling.getDead()) {
|
||||||
|
setDead();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sibling != null && destinationPos == null) {
|
||||||
|
destinationPos = sibling.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Optional.ofNullable(sibling);
|
return Optional.ofNullable(sibling);
|
||||||
|
@ -214,13 +286,15 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
|
||||||
@Override
|
@Override
|
||||||
public void writeToNBT(NBTTagCompound compound) {
|
public void writeToNBT(NBTTagCompound compound) {
|
||||||
if (destinationPos != null) {
|
if (destinationPos != null) {
|
||||||
NBTTagCompound dest = new NBTTagCompound();
|
compound.setTag("destination", InbtSerialisable.writeBlockPos(destinationPos));
|
||||||
|
}
|
||||||
|
|
||||||
dest.setInteger("X", destinationPos.getX());
|
if (casterId != null) {
|
||||||
dest.setInteger("Y", destinationPos.getY());
|
compound.setUniqueId("casterId", casterId);
|
||||||
dest.setInteger("Z", destinationPos.getZ());
|
}
|
||||||
|
|
||||||
compound.setTag("destination", dest);
|
if (destinationId != null) {
|
||||||
|
compound.setUniqueId("destinationId", destinationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
compound.setString("axis", axis.getName2());
|
compound.setString("axis", axis.getName2());
|
||||||
|
@ -229,13 +303,15 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
|
||||||
@Override
|
@Override
|
||||||
public void readFromNBT(NBTTagCompound compound) {
|
public void readFromNBT(NBTTagCompound compound) {
|
||||||
if (compound.hasKey("destination")) {
|
if (compound.hasKey("destination")) {
|
||||||
NBTTagCompound dest = compound.getCompoundTag("destination");
|
destinationPos = InbtSerialisable.readBlockPos(compound.getCompoundTag("destination"));
|
||||||
|
}
|
||||||
|
|
||||||
destinationPos = new BlockPos(
|
if (compound.hasUniqueId("casterId")) {
|
||||||
dest.getInteger("X"),
|
casterId = compound.getUniqueId("casterId");
|
||||||
dest.getInteger("Y"),
|
}
|
||||||
dest.getInteger("Z")
|
|
||||||
);
|
if (compound.hasUniqueId("destinationId")) {
|
||||||
|
destinationId = compound.getUniqueId("destinationId");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compound.hasKey("axis")) {
|
if (compound.hasKey("axis")) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.minelittlepony.unicopia.util.serialisation;
|
package com.minelittlepony.unicopia.util.serialisation;
|
||||||
|
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
public interface InbtSerialisable {
|
public interface InbtSerialisable {
|
||||||
/**
|
/**
|
||||||
|
@ -26,4 +27,22 @@ public interface InbtSerialisable {
|
||||||
writeToNBT(compound);
|
writeToNBT(compound);
|
||||||
return compound;
|
return compound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NBTTagCompound writeBlockPos(BlockPos pos) {
|
||||||
|
NBTTagCompound dest = new NBTTagCompound();
|
||||||
|
|
||||||
|
dest.setInteger("X", pos.getX());
|
||||||
|
dest.setInteger("Y", pos.getY());
|
||||||
|
dest.setInteger("Z", pos.getZ());
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BlockPos readBlockPos(NBTTagCompound compound) {
|
||||||
|
return new BlockPos(
|
||||||
|
compound.getInteger("X"),
|
||||||
|
compound.getInteger("Y"),
|
||||||
|
compound.getInteger("Z")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue