Skip to content

Commit

Permalink
Rift Blade Entity Teleportation
Browse files Browse the repository at this point in the history
-updated mappings version to latest
-updated Forge version to recommended

-made RayTraceHelper.rayTraceForRiftTools more readable, added a range setting to it and made it stop when your head is in a solid block
-added raytrace method for entities that also works on servers

-fixed Rift Blade's teleportation to Entities feature
-added random offset and yaw change based on the durability of the Blade
-added always ending up facing the Entity after teleport

Co-Authored-By: Corail31 <[email protected]>
  • Loading branch information
Robijnvogel and Corail31 committed Jul 4, 2018
1 parent 40e22db commit 3f70141
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 106 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ dependencies {
// Minecraft, MCP, Forge, and Java versions
sourceCompatibility = targetCompatibility = "1.8"
ext.mcversion = "1.12.2"
ext.forgeversion = "14.23.2.2623"
String mcpversion = "snapshot_20180227"
ext.forgeversion = "14.23.4.2707"
String mcpversion = "snapshot_20180703"

// Mod version
version = "3.0.9"
Expand Down
36 changes: 22 additions & 14 deletions src/main/java/org/dimdev/dimdoors/shared/items/ItemRiftBlade.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,13 @@ public boolean getIsRepairable(ItemStack toRepair, ItemStack repair) {
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
ItemStack stack = player.getHeldItem(hand);
RayTraceResult hit = RayTraceHelper.rayTraceForRiftTools(world, player);
RayTraceResult hit = RayTraceHelper.rayTraceEntity(world, player, 16, 1.0F); //TODO: make the range of the Rift Blade configurable
if (hit == null) {
hit = RayTraceHelper.rayTraceForRiftTools(world, player);
}

if (world.isRemote) {
if (RayTraceHelper.isRift(hit, world) || RayTraceHelper.isLivingEntity(hit)) {
if (RayTraceHelper.isLivingEntity(hit) || RayTraceHelper.isRift(hit, world)) {
return new ActionResult<>(EnumActionResult.SUCCESS, stack);
} else {
player.sendStatusMessage(new TextComponentTranslation(getUnlocalizedName() + ".rift_miss"), true);
Expand All @@ -60,25 +63,30 @@ public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player
}
}

if (RayTraceHelper.isRift(hit, world)) {
TileEntityRift rift = (TileEntityRift) world.getTileEntity(hit.getBlockPos());
rift.teleport(player);
if (RayTraceHelper.isLivingEntity(hit)) {
double damageMultiplier = (double) stack.getItemDamage() / (double) stack.getMaxDamage();
// TODO: gaussian, instead or random
double offsetDistance = Math.random() * damageMultiplier * 7 + 2; //TODO: make these offset distances configurable
double offsetRotationYaw = (Math.random() - 0.5) * damageMultiplier * 360;

Vec3d playerVec = player.getPositionVector();
Vec3d entityVec = hit.hitVec;
Vec3d offsetDirection = playerVec.subtract(entityVec).normalize();
offsetDirection = offsetDirection.rotateYaw((float) (offsetRotationYaw * Math.PI) / 180);

BlockPos tpPos = new BlockPos(entityVec.add(offsetDirection.scale(offsetDistance)));
while (world.getBlockState(tpPos).getMaterial().blocksMovement()) tpPos = tpPos.up(); // TODO: move to ddutils
TeleportUtils.teleport(player, new Location(world, tpPos), (player.rotationYaw - (float) offsetRotationYaw) % 360, player.rotationPitch);

stack.damageItem(1, player);
return new ActionResult<>(EnumActionResult.SUCCESS, stack);
} else if (RayTraceHelper.isRift(hit, world)) {
TileEntityRift rift = (TileEntityRift) world.getTileEntity(hit.getBlockPos());
rift.teleport(player);

} else if (RayTraceHelper.isLivingEntity(hit)) {
BlockPos hitPos = hit.getBlockPos();
// TODO: gaussian, and depend on rift blade's wear
int xDiff = (int) (5 * (Math.random() - 0.5));
int zDiff = (int) (5 * (Math.random() - 0.5));
BlockPos tpPos = new BlockPos(hitPos.getX() + xDiff, hitPos.getY(), hitPos.getZ() + zDiff);
while (world.getBlockState(tpPos).getMaterial().blocksMovement()) tpPos = tpPos.up(); // TODO: move to ddutils
TeleportUtils.teleport(player, new Location(world, tpPos), player.rotationYaw, player.rotationPitch);
stack.damageItem(1, player);
return new ActionResult<>(EnumActionResult.SUCCESS, stack);
}

return new ActionResult<>(EnumActionResult.FAIL, stack);
}

Expand Down
225 changes: 135 additions & 90 deletions src/main/java/org/dimdev/dimdoors/shared/items/RayTraceHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@

import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import org.dimdev.dimdoors.DimDoors;
import org.dimdev.dimdoors.shared.blocks.IRiftProvider;
import org.dimdev.dimdoors.shared.tileentities.TileEntityFloatingRift;
import org.dimdev.dimdoors.shared.tileentities.TileEntityRift;

import java.util.List;

public final class RayTraceHelper {

public static boolean isFloatingRift(RayTraceResult hit, World world) {
Expand All @@ -28,142 +33,182 @@ public static boolean isLivingEntity(RayTraceResult hit) {
return hit != null && hit.typeOfHit == RayTraceResult.Type.ENTITY && hit.entityHit instanceof EntityLivingBase;
}

//copied from MC source code, because Vanilla MC assumes that everything without a hitbox either can never be hit OR is a liquid
//TODO: clean this up?
/**
* returns a {@code RayTraceResult} for the first {@code EntityLiving} the look vector of
* {@code player} hits within {@code range} if it can find any. If the look
* vector is blocked by a solid block, before it collides with an {@code EntityLiving}, a
* {@code RayTraceResult} for this solid block is returned instead. If it fails to find
* either, this method returns null.
*
* @param world
* @param player
* @param range
* @param partialTicks
* @return
*/
public static RayTraceResult rayTraceEntity(World world, EntityPlayer player, double range, float partialTicks) {
//TODO: make this work on a server
Vec3d playerEyesVector = player.getPositionEyes(partialTicks);
Vec3d playerLookVector = player.getLookVec();

//Make sure that the raytrace stops if there's a block inbetween
RayTraceResult firstHitBlock = RayTraceHelper.rayTraceForRiftTools(world, player, range);
if (firstHitBlock != null) {
Vec3d hitVector = firstHitBlock.hitVec;
double distance = hitVector.distanceTo(playerEyesVector);
if (distance < range) {
range = distance;
}
}

Vec3d tempVec = playerEyesVector;
Vec3d tempVec2;
for (double d = 0.2; d < range; d += 0.2) {
tempVec2 = playerEyesVector.add(playerLookVector.scale(d));
List<EntityLiving> entities = world.getEntitiesWithinAABB(EntityLiving.class, new AxisAlignedBB(tempVec.x, tempVec.y, tempVec.z, tempVec2.x, tempVec2.y, tempVec2.z));
for (EntityLiving entity : entities) {
if (entity == null) { //should never happen, but just in case
continue;
}
AxisAlignedBB entityHitbox = entity.getEntityBoundingBox();
if (entityHitbox == null) {
DimDoors.log.info("The hitbox of Entity: " + entity + " was null, somehow");
continue;
}
if (entityHitbox.contains(tempVec2)) {
return new RayTraceResult(entity);
}
}
tempVec = tempVec2;
}
return firstHitBlock;
}

public static RayTraceResult rayTraceForRiftTools(World worldIn, EntityPlayer playerIn) {
float f = playerIn.rotationPitch;
float f1 = playerIn.rotationYaw;
double d0 = playerIn.posX;
double d1 = playerIn.posY + (double) playerIn.getEyeHeight();
double d2 = playerIn.posZ;
Vec3d playerVector = new Vec3d(d0, d1, d2);
float f2 = MathHelper.cos(-f1 * 0.017453292F - (float) Math.PI);
float f3 = MathHelper.sin(-f1 * 0.017453292F - (float) Math.PI);
float f4 = -MathHelper.cos(-f * 0.017453292F);
float f5 = MathHelper.sin(-f * 0.017453292F);
float f6 = f3 * f4;
float f7 = f2 * f4;
double d3 = playerIn.getEntityAttribute(EntityPlayer.REACH_DISTANCE).getAttributeValue();
Vec3d cumulativeLookVector = playerVector.addVector((double) f6 * d3, (double) f5 * d3, (double) f7 * d3);

if (!Double.isNaN(playerVector.x) && !Double.isNaN(playerVector.y) && !Double.isNaN(playerVector.z)) {
if (!Double.isNaN(cumulativeLookVector.x) && !Double.isNaN(cumulativeLookVector.y) && !Double.isNaN(cumulativeLookVector.z)) {
int i = MathHelper.floor(cumulativeLookVector.x);
int j = MathHelper.floor(cumulativeLookVector.y);
int k = MathHelper.floor(cumulativeLookVector.z);
int l = MathHelper.floor(playerVector.x);
int i1 = MathHelper.floor(playerVector.y);
int j1 = MathHelper.floor(playerVector.z);
BlockPos blockpos = new BlockPos(l, i1, j1);
return rayTraceForRiftTools(worldIn, playerIn, playerIn.getEntityAttribute(EntityPlayer.REACH_DISTANCE).getAttributeValue());
}

//partially copied from MC source code, because Vanilla MC assumes that everything without a hitbox either can never be hit OR is a liquid
//TODO: clean this up?
public static RayTraceResult rayTraceForRiftTools(World worldIn, EntityPlayer player, double range) {

Vec3d playerLookVector = player.getLookVec();
Vec3d tempVector = player.getPositionEyes(1.0F); //this is what constantly gets shifted in the while-loop later and it starts at the eyes
Vec3d endVector = tempVector.add(playerLookVector.scale(range));

if (!Double.isNaN(tempVector.x) && !Double.isNaN(tempVector.y) && !Double.isNaN(tempVector.z)) {
if (!Double.isNaN(endVector.x) && !Double.isNaN(endVector.y) && !Double.isNaN(endVector.z)) {
int endX = MathHelper.floor(endVector.x);
int endY = MathHelper.floor(endVector.y);
int endZ = MathHelper.floor(endVector.z);
int playerX = MathHelper.floor(tempVector.x);
int playerY = MathHelper.floor(tempVector.y);
int playerZ = MathHelper.floor(tempVector.z);
BlockPos blockpos = new BlockPos(playerX, playerY, playerZ);
IBlockState iblockstate = worldIn.getBlockState(blockpos);
Block block = iblockstate.getBlock();

if (block instanceof IRiftProvider) {
RayTraceResult raytraceresult = iblockstate.collisionRayTrace(worldIn, blockpos, playerVector, cumulativeLookVector);

if (block.canCollideCheck(iblockstate, false) || block instanceof IRiftProvider) {
RayTraceResult raytraceresult = iblockstate.collisionRayTrace(worldIn, blockpos, tempVector, endVector);
if (raytraceresult != null) {
return raytraceresult;
}
}

RayTraceResult raytraceresult2 = null;
int k1 = 200;

while (k1-- >= 0) {
if (Double.isNaN(playerVector.x) || Double.isNaN(playerVector.y) || Double.isNaN(playerVector.z) || (l == i && i1 == j && j1 == k)) {

int counter = 200; //TODO: should this really be a hardcoded value?
while (counter-- >= 0) {
if (Double.isNaN(tempVector.x) || Double.isNaN(tempVector.y) || Double.isNaN(tempVector.z) || (playerX == endX && playerY == endY && playerZ == endZ)) {
return null;
}

boolean flag0 = true;
boolean flag1 = true;
boolean flag2 = true;
double d4 = 999.0D;
double d5 = 999.0D;
double d6 = 999.0D;

if (i > l) {
d4 = (double) l + 1.0D;
} else if (i < l) {
d4 = (double) l + 0.0D;
boolean xFlag = true;
boolean yFlag = true;
boolean zFlag = true;
double x1 = 999.0D;
double y1 = 999.0D;
double z1 = 999.0D;

if (endX > playerX) {
x1 = (double) playerX + 1.0D;
} else if (endX < playerX) {
x1 = (double) playerX;
} else {
flag0 = false;
xFlag = false;
}

if (j > i1) {
d5 = (double) i1 + 1.0D;
} else if (j < i1) {
d5 = (double) i1 + 0.0D;
if (endY > playerY) {
y1 = (double) playerY + 1.0D;
} else if (endY < playerY) {
y1 = (double) playerY;
} else {
flag1 = false;
yFlag = false;
}

if (k > j1) {
d6 = (double) j1 + 1.0D;
} else if (k < j1) {
d6 = (double) j1 + 0.0D;
if (endZ > playerZ) {
z1 = (double) playerZ + 1.0D;
} else if (endZ < playerZ) {
z1 = (double) playerZ;
} else {
flag2 = false;
zFlag = false;
}

double d7 = 999.0D;
double d8 = 999.0D;
double d9 = 999.0D;
double d10 = cumulativeLookVector.x - playerVector.x;
double d11 = cumulativeLookVector.y - playerVector.y;
double d12 = cumulativeLookVector.z - playerVector.z;
double x2 = endVector.x - tempVector.x;
double y2 = endVector.y - tempVector.y;
double z2 = endVector.z - tempVector.z;
double x3 = 999.0D;
double y3 = 999.0D;
double z3 = 999.0D;

if (flag0) {
d7 = (d4 - playerVector.x) / d10;
if (xFlag) {
x3 = (x1 - tempVector.x) / x2;
}

if (flag1) {
d8 = (d5 - playerVector.y) / d11;
if (yFlag) {
y3 = (y1 - tempVector.y) / y2;
}

if (flag2) {
d9 = (d6 - playerVector.z) / d12;
if (zFlag) {
z3 = (z1 - tempVector.z) / z2;
}

if (d7 == -0.0D) {
d7 = -1.0E-4D;
if (x3 == -0.0D) {
x3 = -1.0E-4D;
}

if (d8 == -0.0D) {
d8 = -1.0E-4D;
if (y3 == -0.0D) {
y3 = -1.0E-4D;
}

if (d9 == -0.0D) {
d9 = -1.0E-4D;
if (z3 == -0.0D) {
z3 = -1.0E-4D;
}

EnumFacing enumfacing;

if (d7 < d8 && d7 < d9) {
enumfacing = i > l ? EnumFacing.WEST : EnumFacing.EAST;
playerVector = new Vec3d(d4, playerVector.y + d11 * d7, playerVector.z + d12 * d7);
} else if (d8 < d9) {
enumfacing = j > i1 ? EnumFacing.DOWN : EnumFacing.UP;
playerVector = new Vec3d(playerVector.x + d10 * d8, d5, playerVector.z + d12 * d8);
if (x3 < y3 && x3 < z3) {
enumfacing = endX > playerX ? EnumFacing.WEST : EnumFacing.EAST;
tempVector = new Vec3d(x1, tempVector.y + y2 * x3, tempVector.z + z2 * x3);
} else if (y3 < z3) {
enumfacing = endY > playerY ? EnumFacing.DOWN : EnumFacing.UP;
tempVector = new Vec3d(tempVector.x + x2 * y3, y1, tempVector.z + z2 * y3);
} else {
enumfacing = k > j1 ? EnumFacing.NORTH : EnumFacing.SOUTH;
playerVector = new Vec3d(playerVector.x + d10 * d9, playerVector.y + d11 * d9, d6);
enumfacing = endZ > playerZ ? EnumFacing.NORTH : EnumFacing.SOUTH;
tempVector = new Vec3d(tempVector.x + x2 * z3, tempVector.y + y2 * z3, z1);
}

l = MathHelper.floor(playerVector.x) - (enumfacing == EnumFacing.EAST ? 1 : 0);
i1 = MathHelper.floor(playerVector.y) - (enumfacing == EnumFacing.UP ? 1 : 0);
j1 = MathHelper.floor(playerVector.z) - (enumfacing == EnumFacing.SOUTH ? 1 : 0);
blockpos = new BlockPos(l, i1, j1);
playerX = MathHelper.floor(tempVector.x) - (enumfacing == EnumFacing.EAST ? 1 : 0);
playerY = MathHelper.floor(tempVector.y) - (enumfacing == EnumFacing.UP ? 1 : 0);
playerZ = MathHelper.floor(tempVector.z) - (enumfacing == EnumFacing.SOUTH ? 1 : 0);
blockpos = new BlockPos(playerX, playerY, playerZ);
IBlockState iblockstate1 = worldIn.getBlockState(blockpos);
Block block1 = iblockstate1.getBlock();

if (block1.canCollideCheck(iblockstate1, false) || block1 instanceof IRiftProvider) {
RayTraceResult raytraceresult1 = iblockstate1.collisionRayTrace(worldIn, blockpos, playerVector, cumulativeLookVector);
RayTraceResult raytraceresult1 = iblockstate1.collisionRayTrace(worldIn, blockpos, tempVector, endVector);

if (raytraceresult1 != null) {
return raytraceresult1;
}
} else {
raytraceresult2 = new RayTraceResult(RayTraceResult.Type.MISS, playerVector, enumfacing, blockpos);
}
}
}
Expand Down

0 comments on commit 3f70141

Please sign in to comment.