Compare commits

..
7 Commits
Author SHA1 Message Date
Martin Robertz 4ccecf7bc0 update 2024-07-02 23:50:19 +02:00
Jason Mitchell 92fb58f0c6 Work around CME
* Not entirely sure why it's being concurrently modified.. so let's just make it safe for now
2024-06-30 14:15:24 -07:00
Martin Robertz 54c6db0afc update 2024-06-05 22:49:08 +02:00
OvermindDL1 84d9dcaf00 Fix another thread data race issue introduced in #164. 2024-06-04 21:53:01 -07:00
Jason Mitchell af923d1977 Probably less thread unsafe. (#164) 2024-06-04 18:53:14 -07:00
Martin Robertz efb918fc6d update 2024-06-02 23:05:27 +02:00
6447ffb4d5 Tweaks to EnderIO travel + teleportation (#158)
* Tweak teleport staff controls

* Fix comment

* Fix logic

* spotlessApply (#159)

Co-authored-by: GitHub GTNH Actions <>

* Add configs for teleport staff actions

* Various TP fixes

* Allow TP to unloaded anchor
* Improve TP through wall by checking every 0.5 instead of 2 distance
* Fix blink placing player one block too high
* Fix anchor being incorrectly selected sometimes by constraining to visual angle

* Add server-side handling for two-in-one teleport action

* Clear stored anchors on world load

* Check for obstructed anchor on long-distance teleport

* Check anchor accessibility and require `player != null`

* Handle server-side `travelToLocation`

* Limit backwards teleport check

* 2-in-1 TP: find destination client-side

* spotlessApply (#161)

Co-authored-by: GitHub GTNH Actions <>

* Don't conserve momentum

* Address review comments

* Refactor packet instantiation

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-06-02 17:20:23 +02:00
12 changed files with 181 additions and 217 deletions

No files matched your search

+7 -7
View File
@@ -2,17 +2,17 @@
dependencies {
api('com.github.GTNewHorizons:EnderCore:0.4.6:dev') {transitive = false}
compileOnly('com.github.GTNewHorizons:ForestryMC:4.9.0:dev')
compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.6.0-GTNH:dev')
compileOnly("com.github.GTNewHorizons:GTNHLib:0.2.11:dev")
compileOnly('com.github.GTNewHorizons:ForestryMC:4.9.7:dev')
compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.6.11-GTNH:dev')
compileOnly("com.github.GTNewHorizons:GTNHLib:0.3.1:dev")
compileOnly('com.github.GTNewHorizons:BuildCraft:7.1.39:dev')
api('curse.maven:cofh-lib-220333:2388748') // https://www.curseforge.com/minecraft/mc-mods/cofh-lib/files/2388748
shadowImplementation('cglib:cglib-nodep:3.3.0')
compileOnly('com.github.GTNewHorizons:waila:1.7.3:api') {transitive = false}
compileOnly('com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-400-GTNH:api') {transitive = false}
compileOnly('com.github.GTNewHorizons:waila:1.8.0:api') {transitive = false}
compileOnly('com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-405-GTNH:api') {transitive = false}
compileOnly('com.github.GTNewHorizons:Baubles:1.0.4:dev') {transitive = false}
compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.46.18:dev') {transitive = false}
compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.48.62:dev') {transitive = false}
compileOnly('com.github.GTNewHorizons:Railcraft:9.15.8:api') {transitive = false}
compileOnly('com.github.GTNewHorizons:StorageDrawers:1.13.5-GTNH:api') {transitive = false}
compileOnly('com.github.GTNewHorizons:Chisel:2.15.0-GTNH:dev') {transitive = false}
@@ -24,5 +24,5 @@ dependencies {
compileOnly(rfg.deobf('curse.maven:mekanism-268560:2475797')) // https://www.curseforge.com/minecraft/mc-mods/mekanism/files/2475797
compileOnly(rfg.deobf('maven.modrinth:immibis-microblocks:59.1.2')) // https://modrinth.com/mod/immibis-microblocks/version/59.1.2
compileOnlyApi('com.github.GTNewHorizons:Angelica:1.0.0-alpha50:api') {transitive = false}
compileOnlyApi('com.github.GTNewHorizons:Angelica:1.0.0-alpha52:api') {transitive = false}
}
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+1 -1
View File
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
+1 -1
View File
@@ -17,7 +17,7 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.22'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.23'
}
@@ -2,6 +2,7 @@ package crazypants.enderio.conduit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
@@ -66,7 +67,7 @@ public class TileConduitBundle extends TileEntityEio implements IConduitBundle {
public static final short NBT_VERSION = 1;
private final List<IConduit> conduits = new ArrayList<IConduit>();
private final List<IConduit> conduits = Collections.synchronizedList(new ArrayList<>());
private Block facadeId = null;
private int facadeMeta = 0;
@@ -74,9 +75,9 @@ public class TileConduitBundle extends TileEntityEio implements IConduitBundle {
private boolean facadeChanged;
private final List<CollidableComponent> cachedCollidables = new ArrayList<CollidableComponent>();
private final List<CollidableComponent> cachedCollidables = new ArrayList<>();
private final List<CollidableComponent> cachedConnectors = new ArrayList<CollidableComponent>();
private final List<CollidableComponent> cachedConnectors = new ArrayList<>();
private boolean conduitsDirty = true;
private boolean collidablesDirty = true;
@@ -536,7 +537,7 @@ public class TileConduitBundle extends TileEntityEio implements IConduitBundle {
@Override
public List<CollidableComponent> getConnectors() {
List<CollidableComponent> result = new ArrayList<CollidableComponent>();
List<CollidableComponent> result = new ArrayList<>();
addConnectors(result);
return result;
}
@@ -2,10 +2,11 @@ package crazypants.enderio.conduit.liquid;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
@@ -113,27 +114,29 @@ public class LiquidConduitRenderer extends DefaultConduitRenderer implements IRe
}
}
private static Map<CollidableComponent, Map<Fluid, List<CachableRenderStatement>>> cache = new WeakHashMap<CollidableComponent, Map<Fluid, List<CachableRenderStatement>>>();
private static final Map<CollidableComponent, Map<Fluid, List<CachableRenderStatement>>> cache = Collections
.synchronizedMap(new WeakHashMap<>());
public static List<CachableRenderStatement> computeFluidOutlineToCache(CollidableComponent component, Fluid fluid,
double scaleFactor, float outlineWidth) {
Map<Fluid, List<CachableRenderStatement>> cache0 = cache.get(component);
if (cache0 == null) {
cache0 = new HashMap<Fluid, List<CachableRenderStatement>>();
cache.put(component, cache0);
}
// Only init once per component across all threads so the cache stays accurate.
Map<Fluid, List<CachableRenderStatement>> cache0 = cache
.computeIfAbsent(component, _k -> new ConcurrentHashMap<>());
// The rest of this function 'should' be in a `computeIfAbsent` as well for:
// `cache0.computeIfAbsent(fluid, _k -> ...)` but that won't cause a bug in this case,
// just a bit more garbage.
List<CachableRenderStatement> data = cache0.get(fluid);
if (data != null) {
return data;
}
data = new ArrayList<CachableRenderStatement>();
cache0.put(fluid, data);
data = new ArrayList<>();
IIcon texture = fluid.getStillIcon();
if (texture == null) {
texture = fluid.getIcon();
if (texture == null) {
cache0.put(fluid, data);
return data;
}
}
@@ -192,6 +195,7 @@ public class LiquidConduitRenderer extends DefaultConduitRenderer implements IRe
}
}
}
cache0.put(fluid, data);
return data;
}
@@ -174,8 +174,6 @@ public final class Config {
* The distance travelled when no block is found within {@link #teleportStaffMaxBlinkDistance}.
*/
public static int teleportStaffFailedBlinkDistance = 64;
/** If true, use the original staff of teleportation controls. */
public static boolean teleportStaffOriginalControls = false;
/**
* Sets the teleport staff right-click action.
@@ -188,9 +186,6 @@ public final class Config {
* <li><b>2:</b> Teleport to anchor
* <li><b>3:</b> Teleport to anchor, or to look if no anchor <em>(default)</em>
* </ul>
*
* <p>
* Overridden if {@link #teleportStaffOriginalControls} is true.
*/
public static int teleportStaffAction = 3;
@@ -205,9 +200,6 @@ public final class Config {
* <li><b>2:</b> Teleport to anchor
* <li><b>3:</b> Teleport to anchor, or to look if no anchor
* </ul>
*
* <p>
* Overridden if {@link #teleportStaffOriginalControls} is true.
*/
public static int teleportStaffSneakAction = 1;
@@ -1307,35 +1299,25 @@ public final class Config {
"Number of blocks teleported when no block is being looked at.")
.getInt(teleportStaffFailedBlinkDistance);
teleportStaffOriginalControls = config.get(
sectionPersonal.name,
"teleportStaffOriginalControls",
teleportStaffOriginalControls,
"If true, the staff of teleportation will use its original controls: R-Click for teleport to look, Shift R-Click for teleport to anchor.")
.getBoolean(teleportStaffOriginalControls);
teleportStaffAction = config.get(
sectionPersonal.name,
sectionStaff.name,
"teleportStaffAction",
teleportStaffAction,
"Sets the action for right-click with the staff of teleportation. Values:\n" + " 0: Do nothing\n"
+ " 1: Teleport to look\n"
+ " 2: Teleport to anchor\n"
+ " 3: Teleport to anchor, or look if no anchor (default)\n"
+ "Overridden if teleportStaffOriginalControls is true.")
+ " 3: Teleport to anchor, or look if no anchor (default)")
.getInt(teleportStaffAction);
teleportStaffSneakAction = config
.get(
sectionPersonal.name,
"teleportStaffSneakAction",
teleportStaffSneakAction,
"Sets the action for sneak right-click with the staff of teleportation. Values:\n"
+ " 0: Do nothing\n"
+ " 1: Teleport to look (default)\n"
+ " 2: Teleport to anchor\n"
+ " 3: Teleport to anchor, or look if no anchor\n"
+ "Overridden if teleportStaffOriginalControls is true.")
teleportStaffSneakAction = config.get(
sectionStaff.name,
"teleportStaffSneakAction",
teleportStaffSneakAction,
"Sets the action for sneak right-click with the staff of teleportation. Values:\n"
+ " 0: Do nothing\n"
+ " 1: Teleport to look (default)\n"
+ " 2: Teleport to anchor\n"
+ " 3: Teleport to anchor, or look if no anchor")
.getInt(teleportStaffSneakAction);
enderIoRange = config.get(
@@ -154,8 +154,7 @@ public class KeyTracker {
if (player != null) {
ItemStack travelItem = player.getHeldItem();
if (travelItem == null || travelItem.getItem() == null
|| !(travelItem.getItem() instanceof IItemOfTravel)
|| !((IItemOfTravel) travelItem.getItem()).isActive(player, travelItem)) {
|| !(travelItem.getItem() instanceof IItemOfTravel)) {
travelItem = TravelController.instance.findTravelItemInInventoryOrBaubles(player);
}
@@ -386,15 +386,7 @@ public class ItemDarkSteelSword extends ItemSword
@Override
public boolean isActive(EntityPlayer ep, ItemStack equipped) {
if (ep != null && equipped != null && isTravelUpgradeActive(ep, equipped)) {
// Only "active" if held while sneaking. But still "active" for the purposes of travel keybind if not held
if (isEquipped(ep)) {
return ep.isSneaking();
} else {
return true;
}
}
return false;
return isTravelUpgradeActive(ep, equipped);
}
@Override
@@ -408,12 +400,12 @@ public class ItemDarkSteelSword extends ItemSword
}
private boolean isTravelUpgradeActive(EntityPlayer ep, ItemStack equipped) {
return ep != null && equipped != null && TravelUpgrade.loadFromItem(equipped) != null;
return isEquipped(ep) && ep.isSneaking() && TravelUpgrade.loadFromItem(equipped) != null;
}
@Override
public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) {
if (isActive(player, stack)) {
if (isTravelUpgradeActive(player, stack)) {
if (world.isRemote) {
if (TravelController.instance.activateTravelAccessable(stack, world, player, TravelSource.STAFF)) {
player.swingItem();
@@ -57,38 +57,28 @@ public class ItemTeleportStaff extends ItemTravelStaff {
@Override
public ItemStack onItemRightClick(ItemStack equipped, World world, EntityPlayer player) {
if (world.isRemote) {
if (Config.teleportStaffOriginalControls) {
if (player.isSneaking()) {
int action = player.isSneaking() ? Config.teleportStaffSneakAction : Config.teleportStaffAction;
switch (action) {
case 0:
// Do nothing.
break;
case 1:
TravelController.instance.doTeleport(player);
player.swingItem();
break;
case 2:
TravelController.instance
.activateTravelAccessable(equipped, world, player, TravelSource.TELEPORT_STAFF);
} else {
TravelController.instance.doTeleport(player);
}
player.swingItem();
} else {
int action = player.isSneaking() ? Config.teleportStaffSneakAction : Config.teleportStaffAction;
switch (action) {
case 0:
// Do nothing.
break;
player.swingItem();
break;
case 1:
TravelController.instance.doTeleport(player);
player.swingItem();
break;
case 2:
TravelController.instance
.activateTravelAccessable(equipped, world, player, TravelSource.TELEPORT_STAFF);
player.swingItem();
break;
case 3:
TravelController.instance
.activateTravelAccessable(equipped, world, player, TravelSource.TELEPORT_STAFF, true);
player.swingItem();
break;
}
case 3:
TravelController.instance
.activateTravelAccessable(equipped, world, player, TravelSource.TELEPORT_STAFF, true);
player.swingItem();
break;
}
}
return equipped;
@@ -116,12 +106,6 @@ public class ItemTeleportStaff extends ItemTravelStaff {
return power;
}
@Override
public int getEnergyStored(ItemStack item) {
// Has infinite energy, always report as being full of energy for any validation-code purposes.
return this.capacity;
}
@Override
@SideOnly(Side.CLIENT)
public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List par3List) {
@@ -163,8 +163,7 @@ public class TravelController {
case STAFF_BLINK:
if (Config.travelStaffKeybindEnabled) {
if (equippedItem == null || equippedItem.getItem() == null
|| !(equippedItem.getItem() instanceof IItemOfTravel)
|| !((IItemOfTravel) equippedItem.getItem()).isActive(toTp, equippedItem)) {
|| !(equippedItem.getItem() instanceof IItemOfTravel)) {
equippedItem = findTravelItemInInventoryOrBaubles(toTp);
}
}
@@ -200,12 +199,11 @@ public class TravelController {
public boolean activateTravelAccessable(ItemStack equipped, World world, EntityPlayer player, TravelSource source,
boolean alsoDoTeleport) {
if (!hasTarget()) {
PacketLongDistanceTravelEvent p = new PacketLongDistanceTravelEvent(player, false, source);
if (alsoDoTeleport) {
Optional<BlockCoord> destinationOptional = findTeleportDestination(player);
if (destinationOptional.isPresent()) {
BlockCoord destination = destinationOptional.get();
p = new PacketLongDistanceTravelEvent(
PacketLongDistanceTravelEvent p = new PacketLongDistanceTravelEvent(
player,
false,
source,
@@ -213,12 +211,18 @@ public class TravelController {
destination.x,
destination.y,
destination.z);
PacketHandler.INSTANCE.sendToServer(p);
// We have no way of knowing if it will succeed, so just return false.
return false;
}
}
PacketLongDistanceTravelEvent p = new PacketLongDistanceTravelEvent(player, false, source);
PacketHandler.INSTANCE.sendToServer(p);
// We have no way of knowing if it will succeed, so just return false.
return false;
}
BlockCoord target = selectedCoord;
TileEntity te = world.getTileEntity(target.x, target.y, target.z);
if (te instanceof ITravelAccessable) {
@@ -340,111 +344,11 @@ public class TravelController {
public boolean doTeleport(EntityPlayer player) {
Optional<BlockCoord> destinationOptional = findTeleportDestination(player);
if (destinationOptional.isPresent()) {
return travelToLocation(player, TravelSource.TELEPORT_STAFF_BLINK, destinationOptional.get(), true);
return travelToLocation(player, TravelSource.TELEPORT_STAFF_BLINK, destinationOptional.get(), false);
}
return false;
}
/** Finds the destination for the teleport staff super-teleport, or returns empty optional if unsuccessful. */
public Optional<BlockCoord> findTeleportDestination(EntityPlayer player) {
TravelSource source = TravelSource.TELEPORT_STAFF_BLINK;
Vector3d eye = Util.getEyePositionEio(player);
Vector3d look = Util.getLookVecEio(player);
double playerHeight = player.yOffset;
// +2 to compensate for the standard distance decrement of -2
double teleDistance = Config.teleportStaffFailedBlinkDistance + 2;
Vec3 eye3 = Vec3.createVectorHelper(eye.x, eye.y, eye.z);
// rayTraceBlocks has a limit of 200 distance.
double maxDistance = Config.teleportStaffMaxBlinkDistance;
double currDistance = 0;
Vec3 pos = eye3;
boolean loop = true;
while (loop) {
double distance = 200;
if (maxDistance - currDistance < 200) {
distance = maxDistance - currDistance;
loop = false;
}
Vector3d sample = new Vector3d(look);
sample.scale(distance);
sample.add(eye);
Vec3 end = Vec3.createVectorHelper(sample.x, sample.y, sample.z);
MovingObjectPosition p = player.worldObj
.rayTraceBlocks(pos, end, !Config.travelStaffBlinkThroughClearBlocksEnabled);
if (p != null) {
teleDistance = VecmathUtil.distance(eye, new Vector3d(p.blockX + 0.5, p.blockY + 0.5, p.blockZ + 0.5));
break;
}
pos = end;
currDistance += distance;
}
Vector3d sample = new Vector3d(look);
sample.scale(Config.teleportStaffMaxBlinkDistance);
sample.add(eye);
Vec3 end = Vec3.createVectorHelper(sample.x, sample.y, sample.z);
MovingObjectPosition p = player.worldObj
.rayTraceBlocks(eye3, end, !Config.travelStaffBlinkThroughClearBlocksEnabled);
if (p != null) {
teleDistance = VecmathUtil.distance(eye, new Vector3d(p.blockX + 0.5, p.blockY + 0.5, p.blockZ + 0.5));
}
double distanceIncrement = -2;
int maxIter = Math.min(8, (int) teleDistance / 2);
// Special case: if the targeted block is too close, we'll try to teleport through it.
if (teleDistance < 4) {
distanceIncrement = 0.5;
maxIter = 32;
}
for (int i = 0; i < maxIter; i++) {
teleDistance += distanceIncrement;
sample.set(look);
sample.scale(teleDistance);
sample.add(eye);
// we test against our feets location
sample.y -= playerHeight;
Optional<BlockCoord> destinationOptional = findNearbyDestination(player, source, sample);
if (destinationOptional.isPresent()) {
return destinationOptional;
}
}
return Optional.empty();
}
/** Finds a long-distance travel anchor, or returns empty optional if unsuccessful. */
public Optional<BlockCoord> findTravelDestination(EntityPlayer player, TravelSource source) {
double maxDistance = source.getMaxDistanceTravelled();
double maxMessageDistance = 1.25 * maxDistance;
// Find possible destinations within about 5 degrees.
RowSortedTable<Double, Double, BlockCoord> possibleDestinations = findBlocksWithinAngle(
player,
travelDestinations.get(player.worldObj.provider.dimensionId),
0.087,
maxMessageDistance);
for (Table.Cell<Double, Double, BlockCoord> cell : possibleDestinations.cellSet()) {
if (cell.getColumnKey() <= maxDistance) {
return Optional.of(cell.getValue());
}
}
if (!possibleDestinations.isEmpty()) {
// We found at least one block within maxMessageDistance, but no blocks within maxDistance.
showMessage(player, new ChatComponentTranslation("enderio.blockTravelPlatform.outOfRange"));
}
return Optional.empty();
}
private boolean isBlackListedBlock(EntityPlayer player, MovingObjectPosition pos, Block hitBlock) {
UniqueIdentifier ui = GameRegistry.findUniqueIdentifierFor(hitBlock);
if (ui == null) {
@@ -625,9 +529,9 @@ public class TravelController {
return getTravelItemTravelSource(ep, checkInventoryAndBaubles) != null;
}
/** Currently, we only hide travel targets for the teleport staff, in certain action modes. */
public boolean shouldHideTargets(EntityPlayer ep) {
if (getTravelItemTravelSource(ep, false) != TravelSource.TELEPORT_STAFF
|| Config.teleportStaffOriginalControls) {
if (getTravelItemTravelSource(ep, false) != TravelSource.TELEPORT_STAFF) {
return false;
}
@@ -644,8 +548,7 @@ public class TravelController {
ItemStack equipped = ep.getCurrentEquippedItem();
if (checkInventoryAndBaubles) {
if (equipped == null || !(equipped.getItem() instanceof IItemOfTravel)
|| !((IItemOfTravel) equipped.getItem()).isActive(ep, equipped)) {
if (equipped == null || !(equipped.getItem() instanceof IItemOfTravel)) {
equipped = findTravelItemInInventoryOrBaubles(ep);
}
}
@@ -674,8 +577,7 @@ public class TravelController {
ItemStack travelItem = null;
for (int i = 0; i < ep.inventory.getSizeInventory(); i++) {
ItemStack stack = ep.inventory.getStackInSlot(i);
if (stack != null && stack.getItem() instanceof IItemOfTravel
&& ((IItemOfTravel) stack.getItem()).isActive(ep, stack)) {
if (stack != null && stack.getItem() instanceof IItemOfTravel) {
travelItem = stack;
break;
}
@@ -686,8 +588,7 @@ public class TravelController {
if (baubles != null) {
for (int i = 0; i < baubles.getSizeInventory(); i++) {
ItemStack stack = baubles.getStackInSlot(i);
if (stack != null && stack.getItem() instanceof IItemOfTravel
&& ((IItemOfTravel) stack.getItem()).isActive(ep, stack)) {
if (stack != null && stack.getItem() instanceof IItemOfTravel) {
travelItem = stack;
break;
}
@@ -711,8 +612,7 @@ public class TravelController {
int travelItemSlot = -1;
for (int i = 0; i < ep.inventory.getSizeInventory(); i++) {
ItemStack stack = ep.inventory.getStackInSlot(i);
if (stack != null && stack.getItem() instanceof IItemOfTravel
&& ((IItemOfTravel) stack.getItem()).isActive(ep, stack)) {
if (stack != null && (stack.getItem() instanceof IItemOfTravel)) {
travelItemSlot = i;
break;
}
@@ -723,8 +623,7 @@ public class TravelController {
if (baubles != null) {
for (int i = 0; i < baubles.getSizeInventory(); i++) {
ItemStack stack = baubles.getStackInSlot(i);
if (stack != null && stack.getItem() instanceof IItemOfTravel
&& ((IItemOfTravel) stack.getItem()).isActive(ep, stack)) {
if (stack != null && stack.getItem() instanceof IItemOfTravel) {
travelItemSlot = -(i + 2);
break;
}
@@ -734,6 +633,106 @@ public class TravelController {
return travelItemSlot;
}
/** Finds the destination for the teleport staff super-teleport, or returns empty optional if unsuccessful. */
public Optional<BlockCoord> findTeleportDestination(EntityPlayer player) {
TravelSource source = TravelSource.TELEPORT_STAFF_BLINK;
Vector3d eye = Util.getEyePositionEio(player);
Vector3d look = Util.getLookVecEio(player);
double playerHeight = player.yOffset;
// +2 to compensate for the standard distance decrement of -2
double teleDistance = Config.teleportStaffFailedBlinkDistance + 2;
Vec3 eye3 = Vec3.createVectorHelper(eye.x, eye.y, eye.z);
// rayTraceBlocks has a limit of 200 distance.
double maxDistance = Config.teleportStaffMaxBlinkDistance;
double currDistance = 0;
Vec3 pos = eye3;
boolean loop = true;
while (loop) {
double distance = 200;
if (maxDistance - currDistance < 200) {
distance = maxDistance - currDistance;
loop = false;
}
Vector3d sample = new Vector3d(look);
sample.scale(distance);
sample.add(eye);
Vec3 end = Vec3.createVectorHelper(sample.x, sample.y, sample.z);
MovingObjectPosition p = player.worldObj
.rayTraceBlocks(pos, end, !Config.travelStaffBlinkThroughClearBlocksEnabled);
if (p != null) {
teleDistance = VecmathUtil.distance(eye, new Vector3d(p.blockX + 0.5, p.blockY + 0.5, p.blockZ + 0.5));
break;
}
pos = end;
currDistance += distance;
}
Vector3d sample = new Vector3d(look);
sample.scale(Config.teleportStaffMaxBlinkDistance);
sample.add(eye);
Vec3 end = Vec3.createVectorHelper(sample.x, sample.y, sample.z);
MovingObjectPosition p = player.worldObj
.rayTraceBlocks(eye3, end, !Config.travelStaffBlinkThroughClearBlocksEnabled);
if (p != null) {
teleDistance = VecmathUtil.distance(eye, new Vector3d(p.blockX + 0.5, p.blockY + 0.5, p.blockZ + 0.5));
}
double distanceIncrement = -2;
int maxIter = Math.min(8, (int) teleDistance / 2);
// Special case: if the targeted block is too close, we'll try to teleport through it.
if (teleDistance < 4) {
distanceIncrement = 0.5;
maxIter = 32;
}
for (int i = 0; i < maxIter; i++) {
teleDistance += distanceIncrement;
sample.set(look);
sample.scale(teleDistance);
sample.add(eye);
// we test against our feets location
sample.y -= playerHeight;
Optional<BlockCoord> destinationOptional = findNearbyDestination(player, source, sample);
if (destinationOptional.isPresent()) {
return destinationOptional;
}
}
return Optional.empty();
}
/** Finds a long-distance travel anchor, or returns empty optional if unsuccessful. */
public Optional<BlockCoord> findTravelDestination(EntityPlayer player, TravelSource source) {
double maxDistance = source.getMaxDistanceTravelled();
double maxMessageDistance = 1.25 * maxDistance;
// Find possible destinations within about 5 degrees.
RowSortedTable<Double, Double, BlockCoord> possibleDestinations = findBlocksWithinAngle(
player,
travelDestinations.get(player.worldObj.provider.dimensionId),
0.087,
maxMessageDistance);
for (Table.Cell<Double, Double, BlockCoord> cell : possibleDestinations.cellSet()) {
if (cell.getColumnKey() <= maxDistance) {
return Optional.of(cell.getValue());
}
}
if (!possibleDestinations.isEmpty()) {
// We found at least one block within maxMessageDistance, but no blocks within maxDistance.
showMessage(player, new ChatComponentTranslation("enderio.blockTravelPlatform.outOfRange"));
}
return Optional.empty();
}
/** Finds a valid destination near the provided vector, or returns empty optional if unsuccessful. */
private Optional<BlockCoord> findNearbyDestination(EntityPlayer player, TravelSource source, Vector3d sample) {
Optional<BlockCoord> destinationOptional = findValidDestination(
@@ -337,6 +337,9 @@ public class TileTravelAnchor extends TileEntityEio implements ITravelAccessable
public void validate() {
super.validate();
if (isTravelSource()) {
// Note: travelDestinations is a SetMultimap, which does not allow duplicate entries.
// So it's okay if this gets called multiple times with the same BlockCoord.
// Though, I think that it's not currently getting called multiple times, anyway.
TravelController.instance.travelDestinations.put(worldObj.provider.dimensionId, getLocation());
}
}