Compare commits

..
21 Commits
Author SHA1 Message Date
glowredman 4a94c1ba90 Remove isModLoaded check for GTNH Lib (#172) 2024-07-11 08:44:35 -05:00
Jason Mitchell 0fc382dd13 Update dependencies.gradle (#170)
Fix server test
2024-07-11 03:31:46 -05:00
Jason Mitchell 04964e15e4 hard dep on gtnhlib 2024-07-10 14:09:43 -07:00
Jason Mitchell 085ccc9d21 Try a CasList, since the Collections.synchronizedList actually needed the reads to be synchronized... 2024-07-10 13:40:46 -07:00
Dream Master 1903589e29 update 2024-07-08 13:26:52 +07:00
Ethryan 46971bbe0e Rename Dark Iron Bars to Dark Steel (#167) 2024-07-05 13:20:31 +07:00
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
Martin Robertz fb4c9bde59 update 2024-05-09 10:02:46 +02:00
Oleg Ivanov bd47a39c83 Add config entries for Farming Station particles (#162)
* Decrease number of Farming Station particles

* Set default values for range & number of particles to original
2024-05-08 20:48:35 +02:00
Martin Robertz 43d74c9a7a update 2024-04-24 21:47:04 +02:00
PT400C Jomcraft 6d3a631bb0 Improve FarmingStation portal texture rendering (#157) 2024-04-24 21:26:51 +02:00
Martin Robertz ccdef03296 update 2024-04-18 20:42:39 +02:00
Drathonix 56e163c234 Conduit Replacement Retains Connection Data (#160)
* Replacing Conduits Now maintains all Connection Settings

* Only write/read connection nbt.

* Use Correct Connectionset
2024-04-18 10:24:59 +02:00
Martin Robertz 8ecec5b096 update 2024-02-28 20:07:25 +01:00
boubou19GitHub GTNH Actionsgithub-actions[bot]
4e3fbc7667 Reduce allocation spam in capacitor banks (#155)
* reduce memory allocation

* update dep

* use public

* wrong dep

* spotlessApply (#156)

Co-authored-by: GitHub GTNH Actions <>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-02-25 23:26:17 +01:00
25 changed files with 667 additions and 357 deletions

No files matched your search

+12 -12
View File
@@ -1,22 +1,22 @@
// Add your dependencies here
dependencies {
api('com.github.GTNewHorizons:EnderCore:0.4.1:dev') {transitive = false}
compileOnly('com.github.GTNewHorizons:ForestryMC:4.8.4:dev')
compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.5.19-GTNH:dev')
compileOnly("com.github.GTNewHorizons:GTNHLib:0.2.7:dev")
api('com.github.GTNewHorizons:EnderCore:0.4.6:dev') {transitive = false}
compileOnly('com.github.GTNewHorizons:ForestryMC:4.9.7:dev')
compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.6.14-GTNH:dev')
api("com.github.GTNewHorizons:GTNHLib:0.3.2: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.0:api') {transitive = false}
compileOnly('com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-325-GTNH:api') {transitive = false}
compileOnly('com.github.GTNewHorizons:waila:1.8.1: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.45.71:dev') {transitive = false}
compileOnly('com.github.GTNewHorizons:Railcraft:9.15.5:api') {transitive = false}
compileOnly('com.github.GTNewHorizons:StorageDrawers:1.13.3-GTNH:api') {transitive = false}
compileOnly('com.github.GTNewHorizons:Chisel:2.14.1-GTNH:dev') {transitive = false}
compileOnly('com.github.GTNewHorizons:OpenComputers:1.10.6-GTNH:api') {transitive = false}
compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.48.68: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.1-GTNH:dev') {transitive = false}
compileOnly('com.github.GTNewHorizons:OpenComputers:1.10.11-GTNH:api') {transitive = false}
compileOnly('curse.maven:minefactory-reloaded-66672:2366150') // https://www.curseforge.com/minecraft/mc-mods/minefactory-reloaded/files/2366150
compileOnly('thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev')
compileOnly('curse.maven:ee3-65509:2305023') // https://www.curseforge.com/minecraft/mc-mods/ee3/files/2305023
@@ -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-alpha29:api') {transitive = false}
compileOnlyApi('com.github.GTNewHorizons:Angelica:1.0.0-alpha52:api') {transitive = false}
}
+1 -1
View File
@@ -117,7 +117,7 @@ minimizeShadowedDependencies = true
# If disabled, won't rename the shadowed classes.
relocateShadowedDependencies = true
# Adds the GTNH maven, CurseMaven, IC2/Player maven, and some more well-known 1.7.10 repositories.
# Adds the GTNH maven, CurseMaven, Modrinth, and some more well-known 1.7.10 repositories.
includeWellKnownRepositories = true
# Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven.
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-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.14'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.23'
}
@@ -186,7 +186,7 @@ import crazypants.util.EE3Util;
modid = MODID,
name = MOD_NAME,
version = VERSION,
dependencies = "required-after:CoFHLib@(1.0.3B3,);after:endercore;after:MineFactoryReloaded;after:Forestry;after:Waila@[1.5.8,);after:Thaumcraft;after:appliedenergistics2@[rv2-beta-8,);after:chisel",
dependencies = "required-after:CoFHLib@(1.0.3B3,);after:endercore;after:MineFactoryReloaded;after:Forestry;after:Waila@[1.5.8,);after:Thaumcraft;after:appliedenergistics2@[rv2-beta-8,);after:chisel;required-after:gtnhlib@[0.2.10,)",
guiFactory = "crazypants.enderio.config.ConfigFactoryEIO")
public class EnderIO {
@@ -67,7 +67,6 @@ public abstract class AbstractItemConduit extends Item implements IConduitItem {
if (MicroblocksUtil.supportMicroblocks() && tryAddToMicroblocks(stack, player, world, x, y, z, side)) {
return true;
}
BlockCoord placeAt = Util.canPlaceItem(stack, EnderIO.blockConduitBundle, player, world, x, y, z, side);
if (placeAt != null) {
if (!world.isRemote) {
@@ -84,9 +83,7 @@ public abstract class AbstractItemConduit extends Item implements IConduitItem {
stack.stackSize--;
}
return true;
} else {
ForgeDirection dir = ForgeDirection.values()[side];
int placeX = x + dir.offsetX;
int placeY = y + dir.offsetY;
@@ -116,7 +113,6 @@ public abstract class AbstractItemConduit extends Item implements IConduitItem {
}
}
}
return false;
}
@@ -162,8 +158,7 @@ public abstract class AbstractItemConduit extends Item implements IConduitItem {
System.out.println("AbstractItemConduit.onItemUse: Conduit null.");
return false;
}
bundle.removeConduit(existingConduit);
bundle.addConduit(newConduit);
bundle.replaceConduit(existingConduit, newConduit);
if (!player.capabilities.isCreativeMode) {
stack.stackSize--;
for (ItemStack drop : existingConduit.getDrops()) {
@@ -49,6 +49,8 @@ public interface IConduitBundle extends IInternalPowerHandler, IFluidHandler, II
void addConduit(IConduit conduit);
void replaceConduit(IConduit original, IConduit replacement);
void removeConduit(IConduit conduit);
Collection<IConduit> getConduits();
@@ -25,6 +25,7 @@ import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
import com.enderio.core.client.render.BoundingBox;
import com.gtnewhorizon.gtnhlib.concurrent.cas.CasList;
import appeng.api.networking.IGridNode;
import appeng.api.util.AECableType;
@@ -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 = new CasList<>();
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;
@@ -404,6 +405,29 @@ public class TileConduitBundle extends TileEntityEio implements IConduitBundle {
dirty();
}
@Override
public void replaceConduit(IConduit original, IConduit replacement) {
if (worldObj.isRemote) {
return;
}
// If you're wondering why I am not using conduit.writeToNBT, it is because there is some data that should not
// persist, some of which causes crashes with energy conduits.
NBTTagCompound[] originalData = new NBTTagCompound[ForgeDirection.values().length];
for (ForgeDirection conduitConnection : original.getExternalConnections()) {
NBTTagCompound tag = new NBTTagCompound();
original.writeConnectionSettingsToNBT(conduitConnection, tag);
originalData[conduitConnection.ordinal()] = tag;
}
removeConduit(original);
addConduit(replacement);
for (int i = 0; i < originalData.length; i++) {
NBTTagCompound nbt = originalData[i];
if (nbt != null) {
replacement.readConduitSettingsFromNBT(ForgeDirection.values()[i], nbt);
}
}
}
@Override
public void removeConduit(IConduit conduit) {
if (conduit != null) {
@@ -513,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;
}
@@ -175,6 +175,34 @@ public final class Config {
*/
public static int teleportStaffFailedBlinkDistance = 64;
/**
* Sets the teleport staff right-click action.
*
* <p>
* Values:
* <ul>
* <li><b>0:</b> Do nothing
* <li><b>1:</b> Teleport to look
* <li><b>2:</b> Teleport to anchor
* <li><b>3:</b> Teleport to anchor, or to look if no anchor <em>(default)</em>
* </ul>
*/
public static int teleportStaffAction = 3;
/**
* Sets the teleport staff sneak right-click action.
*
* <p>
* Values:
* <ul>
* <li><b>0:</b> Do nothing
* <li><b>1:</b> Teleport to look <em>(default)</em>
* <li><b>2:</b> Teleport to anchor
* <li><b>3:</b> Teleport to anchor, or to look if no anchor
* </ul>
*/
public static int teleportStaffSneakAction = 1;
public static int enderIoRange = 8;
public static boolean enderIoMeAccessEnabled = true;
@@ -361,6 +389,8 @@ public final class Config {
"TwilightForest:item.steeleafHoe", "TwilightForest:item.ironwoodHoe", "IC2:itemToolBronzeHoe" };
public static List<ItemStack> farmHoes = new ArrayList<ItemStack>();
public static int farmSaplingReserveAmount = 8;
public static double farmParticlesMaxRange = 64;
public static int farmParticlesCount = 15;
public static int magnetPowerUsePerSecondRF = 1;
public static int magnetPowerCapacityRF = 100000;
@@ -1269,6 +1299,27 @@ public final class Config {
"Number of blocks teleported when no block is being looked at.")
.getInt(teleportStaffFailedBlinkDistance);
teleportStaffAction = config.get(
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)")
.getInt(teleportStaffAction);
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(
sectionEfficiency.name,
"enderIoRange",
@@ -2060,6 +2111,18 @@ public final class Config {
+ "always shear all leaves.")
.getInt(farmSaplingReserveAmount);
farmParticlesMaxRange = config.get(
sectionFarm.name,
"farmParticlesMaxRange",
farmParticlesMaxRange,
"The max range of the farm action particles.").getDouble(farmParticlesMaxRange);
farmParticlesCount = config.get(
sectionFarm.name,
"farmParticlesCount",
farmParticlesCount,
"The number of particles produces by farm action.").getInt(farmParticlesCount);
combustionGeneratorUseOpaqueModel = config
.get(
sectionAesthetic.name,
@@ -129,7 +129,7 @@ public class CapBankRenderer extends TileEntitySpecialRenderer implements ISimpl
nw.setMaxEnergyStoredL(CapBankType.getTypeFromMeta(item.getItemDamage()).getMaxEnergyStored());
nw.setEnergyStored(PowerHandlerUtil.getStoredEnergyForItem(item));
GaugeInfo gi = new GaugeInfo(1, 0);
GaugeInfo gi = GaugeInfo.DEFAULT;
GaugeKey key = new GaugeKey(ForgeDirection.SOUTH, FillGauge.Type.SINGLE);
fillGaugeRenderer.doRender(nw, RenderUtil.BRIGHTNESS_MAX, gi, key);
// key = new GaugeKey(ForgeDirection.EAST, FillGauge.Type.SINGLE);
@@ -1,6 +1,5 @@
package crazypants.enderio.machine.capbank.render;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -32,6 +31,7 @@ public class FillGauge implements IInfoRenderer, IResourceManagerReloadListener
private static final double HEIGHT = 0.75;
private static final double VERT_BORDER = (1 - HEIGHT) / 2;
private static final double WIDTH = 0.25;
private final Vertex[] newVerts = new Vertex[] { new Vertex(), new Vertex(), new Vertex(), new Vertex() };
enum Type {
SINGLE,
@@ -95,8 +95,8 @@ public class FillGauge implements IInfoRenderer, IResourceManagerReloadListener
if (ratio <= 0) {
return;
}
double maxY = ratio * info.height;
if (maxY <= info.yPosition) {
double maxY = ratio * info.getHeight();
if (maxY <= info.getyPosition()) {
// empty
return;
}
@@ -105,26 +105,24 @@ public class FillGauge implements IInfoRenderer, IResourceManagerReloadListener
Tessellator.instance.addTranslation((float) offset.x, (float) offset.y, (float) offset.z);
List<Vertex> verts = levelVertexCache.get(key);
if (maxY >= info.yPosition + 1) {
if (maxY >= info.getyPosition() + 1) {
// full bar
RenderUtil.addVerticesToTessellator(verts, Tessellator.instance);
} else {
// need to render partial bar
double myMaxY = maxY - info.yPosition;
double myMaxY = maxY - info.getyPosition();
if (info.type == Type.BOTTOM || info.type == Type.SINGLE) {
// If we have some power and we are the bottom bit of the display,
// always show at least a little bit in the bar
myMaxY = Math.max(0.2, myMaxY);
}
List<Vertex> newVerts = new ArrayList<Vertex>();
for (Vertex v : verts) {
v = new Vertex(v);
newVerts.add(v);
if (v.y() > myMaxY) {
v.setXYZ(v.x(), myMaxY, v.z());
v.setUV(v.u(), barMinV + (float) (myMaxY * barHeightV));
for (int i = 0; i < verts.size(); i++) {
newVerts[i].set(verts.get(i));
if (newVerts[i].y() > myMaxY) {
newVerts[i].setXYZ(newVerts[i].x(), myMaxY, newVerts[i].z());
newVerts[i].setUV(newVerts[i].u(), barMinV + (float) (myMaxY * barHeightV));
}
}
RenderUtil.addVerticesToTessellator(newVerts, Tessellator.instance);
@@ -136,7 +134,7 @@ public class FillGauge implements IInfoRenderer, IResourceManagerReloadListener
private GaugeInfo getGaugeInfo(TileCapBank cb, ForgeDirection dir) {
if (!cb.getType().isMultiblock()) {
return new GaugeInfo(1, 0);
return GaugeInfo.DEFAULT;
}
int height = 1;
@@ -240,8 +238,10 @@ public class FillGauge implements IInfoRenderer, IResourceManagerReloadListener
static class GaugeInfo {
int height;
int yPosition;
public static final GaugeInfo DEFAULT = new GaugeInfo(1, 0);
private int height;
private int yPosition;
Type type;
GaugeInfo(int height, int position) {
@@ -262,6 +262,14 @@ public class FillGauge implements IInfoRenderer, IResourceManagerReloadListener
}
return Type.MIDDLE;
}
public int getHeight() {
return height;
}
public int getyPosition() {
return yPosition;
}
}
static class GaugeKey {
@@ -21,6 +21,14 @@ import crazypants.enderio.machine.power.PowerDisplayUtil;
public class IoDisplay implements IInfoRenderer {
private float previousAverageInput;
private float previousAverageOutput;
String averageInputText = "0";
String averageOutputText = "0";
HeadingText heading1;
HeadingText heading2;
@Override
public void render(TileCapBank cb, ForgeDirection dir, double x, double y, double z, float partialTick) {
if (dir.offsetY != 0) {
@@ -137,10 +145,8 @@ public class IoDisplay implements IInfoRenderer {
nw.requestPowerUpdate(cb, 20);
HeadingText heading1 = HeadingText.STABLE;
HeadingText heading2 = null;
String text1;
String text2 = "";
heading1 = HeadingText.STABLE;
heading2 = null;
FontRenderer fr = Minecraft.getMinecraft().fontRenderer;
float size = 0.15f * Math.min(info.width, info.height);
@@ -150,8 +156,14 @@ public class IoDisplay implements IInfoRenderer {
if (info.height * 3 >= info.width * 4) {
heading1 = HeadingText.INPUT;
heading2 = HeadingText.OUTPUT;
text1 = getChangeText(nw.getAverageInputPerTick(), fr);
text2 = getChangeText(nw.getAverageOutputPerTick(), fr);
if (previousAverageInput != nw.getAverageInputPerTick()) {
averageInputText = getChangeText(nw.getAverageInputPerTick(), fr);
previousAverageInput = nw.getAverageInputPerTick();
}
if (previousAverageOutput != nw.getAverageOutputPerTick()) {
averageOutputText = getChangeText(nw.getAverageOutputPerTick(), fr);
previousAverageOutput = nw.getAverageOutputPerTick();
}
offset = -size * 2.5f;
} else {
int change = Math.round(nw.getAverageChangePerTick());
@@ -160,7 +172,10 @@ public class IoDisplay implements IInfoRenderer {
} else if (change < 0) {
heading1 = HeadingText.LOSS;
}
text1 = getChangeText(change, fr);
if (change != previousAverageInput) {
averageInputText = getChangeText(change, fr);
previousAverageInput = change;
}
offset = -size;
}
@@ -184,9 +199,9 @@ public class IoDisplay implements IInfoRenderer {
GL11.glDisable(GL11.GL_LIGHTING);
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
offset = drawText(heading1, text1, offset, scale, size, fr);
offset = drawText(heading1, averageInputText, offset, scale, size, fr);
if (heading2 != null) {
drawText(heading2, text2, offset, scale, size, fr);
drawText(heading2, averageOutputText, offset, scale, size, fr);
}
GL11.glEnable(GL11.GL_LIGHTING);
@@ -35,7 +35,12 @@ public class FarmingStationRenderer extends TechneMachineRenderer<TileFarmStatio
bb = bb.translate(x, y, z);
tessellator.setColorOpaque_F(1, 1, 1);
tessellator.setBrightness(0xF000F0);
CubeRenderer.get().render(bb, override != null ? override : Blocks.portal.getBlockTextureFromSide(1));
IIcon ico = override != null ? override : Blocks.portal.getBlockTextureFromSide(1);
float x1 = ico.getInterpolatedU(3);
float x2 = ico.getInterpolatedU(13);
float y1 = ico.getInterpolatedV(6);
float y2 = ico.getInterpolatedV(10);
CubeRenderer.get().render(bb, x1, x2, y1, y2);
}
}
@@ -9,6 +9,7 @@ import com.enderio.core.common.util.BlockCoord;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import crazypants.enderio.config.Config;
import crazypants.util.ClientUtil;
import io.netty.buffer.ByteBuf;
@@ -51,11 +52,7 @@ public class PacketFarmAction implements IMessage, IMessageHandler<PacketFarmAct
@Override
public IMessage onMessage(PacketFarmAction message, MessageContext ctx) {
for (BlockCoord bc : message.coords) {
for (int i = 0; i < 15; i++) {
ClientUtil.spawnFarmParcticles(rand, bc);
}
}
ClientUtil.spawnFarmParticles(rand, message.coords, Config.farmParticlesCount);
return null;
}
}
@@ -458,8 +458,9 @@ public class TileFarmStation extends AbstractPoweredTaskEntity {
IHarvestResult harvest = FarmersCommune.instance.harvestBlock(this, bc, block, meta);
if (harvest != null && harvest.getDrops() != null) {
PacketFarmAction pkt = new PacketFarmAction(harvest.getHarvestedBlocks());
PacketHandler.INSTANCE
.sendToAllAround(pkt, new TargetPoint(worldObj.provider.dimensionId, bc.x, bc.y, bc.z, 64));
PacketHandler.INSTANCE.sendToAllAround(
pkt,
new TargetPoint(worldObj.provider.dimensionId, bc.x, bc.y, bc.z, Config.farmParticlesMaxRange));
for (EntityItem ei : harvest.getDrops()) {
if (ei != null) {
insertHarvestDrop(ei, bc);
@@ -487,7 +488,12 @@ public class TileFarmStation extends AbstractPoweredTaskEntity {
inventory[minFirtSlot] = farmerJoe.inventory.mainInventory[0];
PacketHandler.INSTANCE.sendToAllAround(
new PacketFarmAction(bc),
new TargetPoint(worldObj.provider.dimensionId, bc.x, bc.y, bc.z, 64));
new TargetPoint(
worldObj.provider.dimensionId,
bc.x,
bc.y,
bc.z,
Config.farmParticlesMaxRange));
if (inventory[minFirtSlot] != null && inventory[minFirtSlot].stackSize == 0) {
inventory[minFirtSlot] = null;
}
@@ -15,6 +15,7 @@ import cpw.mods.fml.relauncher.SideOnly;
import crazypants.enderio.EnderIO;
import crazypants.enderio.ModObject;
import crazypants.enderio.api.teleport.TravelSource;
import crazypants.enderio.config.Config;
import crazypants.enderio.machine.power.PowerDisplayUtil;
public class ItemTeleportStaff extends ItemTravelStaff {
@@ -56,14 +57,30 @@ public class ItemTeleportStaff extends ItemTravelStaff {
@Override
public ItemStack onItemRightClick(ItemStack equipped, World world, EntityPlayer player) {
if (world.isRemote) {
if (player.isSneaking()) {
TravelController.instance
.activateTravelAccessable(equipped, world, player, TravelSource.TELEPORT_STAFF);
} else {
TravelController.instance.doTeleport(player);
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);
player.swingItem();
break;
case 3:
TravelController.instance
.activateTravelAccessable(equipped, world, player, TravelSource.TELEPORT_STAFF, true);
player.swingItem();
break;
}
}
player.swingItem();
return equipped;
}
@@ -3,10 +3,8 @@ package crazypants.enderio.teleport;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.TreeMap;
import javax.annotation.Nullable;
@@ -32,6 +30,7 @@ import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.event.world.WorldEvent;
import com.enderio.core.common.util.BlockCoord;
import com.enderio.core.common.util.Util;
@@ -41,10 +40,12 @@ import com.enderio.core.common.vecmath.VecmathUtil;
import com.enderio.core.common.vecmath.Vector2d;
import com.enderio.core.common.vecmath.Vector3d;
import com.google.common.collect.MultimapBuilder;
import com.google.common.collect.RowSortedTable;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Table;
import com.google.common.collect.TreeBasedTable;
import com.gtnewhorizon.gtnhlib.GTNHLib;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ObfuscationReflectionHelper;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
@@ -148,8 +149,9 @@ public class TravelController {
// target must be a valid selectedCoord
// selectedCoord can either be a block right above/below when the player is on anchor...
if (on.x == x && on.z == z) return null;
// or another anchor
TileEntity maybeAnchor = target.getTileEntity(toTp.worldObj);
// or another anchor. We need to look one block below because TP goes above the anchor.
BlockCoord belowTarget = target.getLocation(ForgeDirection.DOWN);
TileEntity maybeAnchor = belowTarget.getTileEntity(toTp.worldObj);
if (!(maybeAnchor instanceof ITravelAccessable)) return "not anchor";
ITravelAccessable anchor = (ITravelAccessable) maybeAnchor;
if (!isValidTarget(toTp, target, TravelSource.BLOCK)) {
@@ -190,12 +192,36 @@ public class TravelController {
}
public boolean activateTravelAccessable(ItemStack equipped, World world, EntityPlayer player, TravelSource source) {
return activateTravelAccessable(equipped, world, player, source, false);
}
public boolean activateTravelAccessable(ItemStack equipped, World world, EntityPlayer player, TravelSource source,
boolean alsoDoTeleport) {
if (!hasTarget()) {
if (alsoDoTeleport) {
Optional<BlockCoord> destinationOptional = findTeleportDestination(player);
if (destinationOptional.isPresent()) {
BlockCoord destination = destinationOptional.get();
PacketLongDistanceTravelEvent p = new PacketLongDistanceTravelEvent(
player,
false,
source,
true,
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) {
@@ -243,7 +269,10 @@ public class TravelController {
sample.add(eye);
// we test against our feets location
sample.y -= playerHeight;
if (doBlinkAround(player, source, sample, true)) {
Optional<BlockCoord> destinationOptional = findNearbyDestination(player, source, sample);
if (destinationOptional.isPresent()
&& travelToLocation(player, source, destinationOptional.get(), true)) {
return true;
}
}
@@ -280,7 +309,9 @@ public class TravelController {
// we test against our feets location
sample.y -= playerHeight;
if (doBlinkAround(player, source, sample, false)) {
Optional<BlockCoord> destinationOptional = findNearbyDestination(player, source, sample);
if (destinationOptional.isPresent()
&& travelToLocation(player, source, destinationOptional.get(), false)) {
return true;
}
teleDistance++;
@@ -296,7 +327,9 @@ public class TravelController {
// we test against our feets location
sample.y -= playerHeight;
if (doBlinkAround(player, source, sample, false)) {
Optional<BlockCoord> destinationOptional = findNearbyDestination(player, source, sample);
if (destinationOptional.isPresent()
&& travelToLocation(player, source, destinationOptional.get(), false)) {
return true;
}
sampleDistance--;
@@ -308,114 +341,13 @@ public class TravelController {
/** This is the teleport staff super-teleport. */
public boolean doTeleport(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;
// Special case: if the targeted block is too close, we'll try to teleport through it.
if (teleDistance < 3) {
distanceIncrement = 2;
}
for (int i = 0; i < 8; i++) {
teleDistance += distanceIncrement;
sample.set(look);
sample.scale(teleDistance);
sample.add(eye);
// we test against our feets location
sample.y -= playerHeight;
if (doBlinkAround(player, source, sample, false)) {
return true;
}
Optional<BlockCoord> destinationOptional = findTeleportDestination(player);
if (destinationOptional.isPresent()) {
return travelToLocation(player, TravelSource.TELEPORT_STAFF_BLINK, destinationOptional.get(), false);
}
return false;
}
/** Returns empty optional if no travel destination was found. */
public Optional<BlockCoord> findTravelDestination(EntityPlayer player, TravelSource source) {
Vector3d eye = Util.getEyePositionEio(player);
Vector3d look = Util.getLookVecEio(player);
// Map of distance to coordinate for eligible travel destinations (within angle).
Map<Double, BlockCoord> distanceMap = new TreeMap<>();
// Limit the max distance at which we'll display an out of range message.
// Otherwise, you could trigger the message for any travel anchor on the entire server.
double maxMessageDistance = 1.25 * source.getMaxDistanceTravelled();
boolean displayOutOfRangeMessage = false;
for (BlockCoord p : travelDestinations.get(player.worldObj.provider.dimensionId)) {
Vector3d block = new Vector3d(p.x + 0.5, p.y + 0.5, p.z + 0.5);
block.sub(eye);
double distance = block.length();
if (distance > maxMessageDistance) {
continue;
}
block.normalize();
double angle = Math.acos(look.dot(block));
// Roughly 5 degrees
if (angle < 0.087) {
if (distance > source.getMaxDistanceTravelled()) {
displayOutOfRangeMessage = true;
} else {
distanceMap.put(distance, p);
}
}
}
if (displayOutOfRangeMessage && distanceMap.isEmpty()) {
showMessage(player, new ChatComponentTranslation("enderio.blockTravelPlatform.outOfRange"));
}
return distanceMap.values().stream().findFirst();
}
private boolean isBlackListedBlock(EntityPlayer player, MovingObjectPosition pos, Block hitBlock) {
UniqueIdentifier ui = GameRegistry.findUniqueIdentifierFor(hitBlock);
if (ui == null) {
@@ -426,36 +358,6 @@ public class TravelController {
|| !Config.travelStaffBlinkThroughUnbreakableBlocksEnabled);
}
private boolean doBlinkAround(EntityPlayer player, TravelSource source, Vector3d sample, boolean conserveMomentum) {
if (travelToLocation(
player,
source,
new BlockCoord((int) Math.floor(sample.x), (int) Math.floor(sample.y), (int) Math.floor(sample.z)),
conserveMomentum)) {
return true;
}
if (travelToLocation(
player,
source,
new BlockCoord((int) Math.floor(sample.x), (int) Math.floor(sample.y) + 1, (int) Math.floor(sample.z)),
conserveMomentum)) {
return true;
}
if (!Config.travelStaffSearchOptimize) {
if (travelToLocation(
player,
source,
new BlockCoord(
(int) Math.floor(sample.x),
(int) Math.floor(sample.y) - 1,
(int) Math.floor(sample.z)),
conserveMomentum)) {
return true;
}
}
return false;
}
public boolean showTargets() {
return showTargets && selectionEnabled;
}
@@ -492,6 +394,13 @@ public class TravelController {
.getBlock(selectedCoord.x, selectedCoord.y, selectedCoord.z) == EnderIO.blockEnderIo;
}
@SubscribeEvent
public void onWorldLoad(WorldEvent.Load e) {
if (!e.world.isRemote) {
travelDestinations.removeAll(e.world.provider.dimensionId);
}
}
@SubscribeEvent
@SideOnly(Side.CLIENT)
public void onRender(RenderWorldLastEvent event) {
@@ -527,7 +436,7 @@ public class TravelController {
}
onBlockCoord = getActiveTravelBlock(player);
boolean onBlock = onBlockCoord != null;
showTargets = onBlock || isTravelItemActive(player, false);
showTargets = onBlock || (isTravelItemActive(player, false) && !shouldHideTargets(player));
if (showTargets) {
updateSelectedTarget(player);
} else {
@@ -619,6 +528,16 @@ 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) {
return false;
}
int action = ep.isSneaking() ? Config.teleportStaffSneakAction : Config.teleportStaffAction;
return action < 2;
}
/** Returns null if no travel item is in inventory/baubles. */
@Nullable
public TravelSource getTravelItemTravelSource(EntityPlayer ep, boolean checkInventoryAndBaubles) {
@@ -713,43 +632,201 @@ 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(
player,
source,
new BlockCoord((int) Math.floor(sample.x), (int) Math.floor(sample.y), (int) Math.floor(sample.z)));
if (destinationOptional.isPresent()) {
return destinationOptional;
}
destinationOptional = findValidDestination(
player,
source,
new BlockCoord((int) Math.floor(sample.x), (int) Math.floor(sample.y) + 1, (int) Math.floor(sample.z)));
if (destinationOptional.isPresent()) {
return destinationOptional;
}
if (!Config.travelStaffSearchOptimize) {
destinationOptional = findValidDestination(
player,
source,
new BlockCoord(
(int) Math.floor(sample.x),
(int) Math.floor(sample.y) - 1,
(int) Math.floor(sample.z)));
if (destinationOptional.isPresent()) {
return destinationOptional;
}
}
return Optional.empty();
}
/**
* Returns the provided position if it's valid, or returns empty optional if unsuccessful.
*
* <p>
* To be precise: if the destination is a travel anchor or other block, then the returned coordinates will be one
* block higher, to place the player on top of the block.
*/
public Optional<BlockCoord> findValidDestination(EntityPlayer player, TravelSource source, BlockCoord coord) {
// Are we trying to travel to a block (anchor or telepad)?
boolean travelToBlock = source != TravelSource.STAFF_BLINK && source != TravelSource.TELEPORT_STAFF_BLINK;
BlockCoord destination = coord;
if (travelToBlock) {
TileEntity te = player.worldObj.getTileEntity(coord.x, coord.y, coord.z);
if (te instanceof ITravelAccessable) {
ITravelAccessable ta = (ITravelAccessable) te;
if (!ta.canBlockBeAccessed(player)) {
showMessage(player, new ChatComponentTranslation("enderio.gui.travelAccessable.unauthorised"));
return Optional.empty();
}
}
// We actually want to go on top of the block.
destination = coord.getLocation(ForgeDirection.UP);
}
if (!isInRangeTarget(player, destination, source.getMaxDistanceTravelledSq())) {
if (travelToBlock) {
showMessage(player, new ChatComponentTranslation("enderio.blockTravelPlatform.outOfRange"));
}
return Optional.empty();
}
if (!isValidTarget(player, destination, source)) {
if (travelToBlock) {
showMessage(player, new ChatComponentTranslation("enderio.blockTravelPlatform.invalidTarget"));
}
return Optional.empty();
}
return Optional.of(destination);
}
public boolean travelToSelectedTarget(EntityPlayer player, TravelSource source, boolean conserveMomentum) {
return travelToLocation(player, source, selectedCoord, conserveMomentum);
}
public boolean travelToLocation(EntityPlayer player, TravelSource source, BlockCoord coord,
boolean conserveMomentum) {
if (source != TravelSource.STAFF_BLINK && source != TravelSource.TELEPORT_STAFF_BLINK) {
TileEntity te = player.worldObj.getTileEntity(coord.x, coord.y, coord.z);
if (te instanceof ITravelAccessable) {
ITravelAccessable ta = (ITravelAccessable) te;
if (!ta.canBlockBeAccessed(player)) {
showMessage(player, new ChatComponentTranslation("enderio.gui.travelAccessable.unauthorised"));
return false;
}
}
Optional<BlockCoord> destinationOptional = findValidDestination(player, source, coord);
if (!destinationOptional.isPresent()) {
return false;
}
BlockCoord destination = destinationOptional.get();
int requiredPower = 0;
requiredPower = getRequiredPower(player, source, coord);
requiredPower = getRequiredPower(player, source, destination);
if (requiredPower < 0) {
return false;
}
if (!isInRangeTarget(player, coord, source.getMaxDistanceTravelledSq())) {
if (source != TravelSource.STAFF_BLINK && source != TravelSource.TELEPORT_STAFF_BLINK) {
showMessage(player, new ChatComponentTranslation("enderio.blockTravelPlatform.outOfRange"));
}
return false;
}
if (!isValidTarget(player, coord, source)) {
if (source != TravelSource.STAFF_BLINK && source != TravelSource.TELEPORT_STAFF_BLINK) {
showMessage(player, new ChatComponentTranslation("enderio.blockTravelPlatform.invalidTarget"));
}
return false;
}
if (doClientTeleport(player, coord, source, requiredPower, conserveMomentum)) {
if (doClientTeleport(player, destinationOptional.get(), source, requiredPower, conserveMomentum)) {
for (int i = 0; i < 6; ++i) {
player.worldObj.spawnParticle(
"portal",
@@ -764,6 +841,17 @@ public class TravelController {
return true;
}
public boolean isValidTarget(EntityPlayer player, BlockCoord bc, TravelSource source) {
if (bc == null) {
return false;
}
World w = player.worldObj;
BlockCoord baseLoc = bc;
return canTeleportTo(player, source, baseLoc, w)
&& canTeleportTo(player, source, baseLoc.getLocation(ForgeDirection.UP), w);
}
public int getRequiredPower(EntityPlayer player, TravelSource source, BlockCoord coord) {
if (!isTravelItemActive(player, true)) {
return 0;
@@ -808,21 +896,6 @@ public class TravelController {
return Math.sqrt(getDistanceSquared(player, coord));
}
private boolean isValidTarget(EntityPlayer player, BlockCoord bc, TravelSource source) {
if (bc == null) {
return false;
}
World w = player.worldObj;
BlockCoord baseLoc = bc;
if (source != TravelSource.STAFF_BLINK && source != TravelSource.TELEPORT_STAFF_BLINK) {
// targeting a block so go one up
baseLoc = bc.getLocation(ForgeDirection.UP);
}
return canTeleportTo(player, source, baseLoc, w)
&& canTeleportTo(player, source, baseLoc.getLocation(ForgeDirection.UP), w);
}
private boolean canTeleportTo(EntityPlayer player, TravelSource source, BlockCoord bc, World w) {
if (bc.y < 1) {
return false;
@@ -904,6 +977,7 @@ public class TravelController {
if (selectedBlock instanceof ITravelAccessable) {
ITravelAccessable travelBlock = (ITravelAccessable) selectedBlock;
BlockCoord targetBlock = new BlockCoord(currentBlock.x, y, currentBlock.z);
BlockCoord destination = targetBlock.getLocation(ForgeDirection.UP);
if (Config.travelAnchorSkipWarning) {
if (travelBlock.getRequiresPassword(player)) {
@@ -914,55 +988,67 @@ public class TravelController {
&& !travelBlock.canUiBeAccessed(player)) {
showMessage(player, new ChatComponentTranslation("enderio.gui.travelAccessable.skipPrivate"));
}
if (!isValidTarget(player, targetBlock, TravelSource.BLOCK)) {
if (!isValidTarget(player, destination, TravelSource.BLOCK)) {
showMessage(player, new ChatComponentTranslation("enderio.gui.travelAccessable.skipObstructed"));
}
}
if (travelBlock.canBlockBeAccessed(player) && isValidTarget(player, targetBlock, TravelSource.BLOCK)) {
if (travelBlock.canBlockBeAccessed(player) && isValidTarget(player, destination, TravelSource.BLOCK)) {
return targetBlock;
}
}
return null;
}
/**
* Returns a row-sorted table with angle in radians as the row, distance as the column, and block coordinate as the
* value, holding all blocks which lie within the specified viewing angle and distance.
*
* <p>
* The table is sorted by angle ascending, so the smallest angle will be first.
*
* @param player The player to search from.
* @param blocks The blocks to search through.
* @param maxAngle The maximum allowed angle, in radians.
* @param maxDistance The maximum allowed distance.
*/
private RowSortedTable<Double, Double, BlockCoord> findBlocksWithinAngle(EntityPlayer player,
Iterable<BlockCoord> blocks, double maxAngle, double maxDistance) {
Vector3d eye = Util.getEyePositionEio(player);
Vector3d look = Util.getLookVecEio(player);
// Table of angle, distance, and block coordinate holding found blocks.
// Angle is the row, so this table will automatically be sorted by angle ascending.
RowSortedTable<Double, Double, BlockCoord> foundBlocks = TreeBasedTable.create();
for (BlockCoord p : blocks) {
Vector3d block = new Vector3d(p.x + 0.5, p.y + 0.5, p.z + 0.5);
block.sub(eye);
double distance = block.length();
if (distance > maxDistance) {
continue;
}
block.normalize();
double angle = Math.acos(look.dot(block));
if (angle <= maxAngle) {
foundBlocks.put(angle, distance, p);
}
}
return foundBlocks;
}
@SideOnly(Side.CLIENT)
private void updateSelectedTarget(EntityPlayer player) {
selectedCoord = null;
if (candidates.isEmpty()) {
selectedCoord = null;
return;
}
double closestDistance = Double.MAX_VALUE;
for (BlockCoord bc : candidates.keySet()) {
if (!bc.equals(onBlockCoord)) {
double d = addRatio(bc);
if (d < closestDistance) {
selectedCoord = bc;
closestDistance = d;
}
}
}
if (selectedCoord != null) {
Vector3d blockCenter = new Vector3d(selectedCoord.x + 0.5, selectedCoord.y + 0.5, selectedCoord.z + 0.5);
Vector2d blockCenterPixel = currentView.getScreenPoint(blockCenter);
Vector2d screenMidPixel = new Vector2d(
Minecraft.getMinecraft().displayWidth,
Minecraft.getMinecraft().displayHeight);
screenMidPixel.scale(0.5);
double pixDist = blockCenterPixel.distance(screenMidPixel);
double rat = pixDist / Minecraft.getMinecraft().displayHeight;
if (rat != rat) {
rat = 0;
}
if (rat > 0.07) {
selectedCoord = null;
}
}
// Find the nearest travel anchor within roughly 10 degrees.
Optional<BlockCoord> selectedBlock = findBlocksWithinAngle(player, candidates.keySet(), 0.175, Double.MAX_VALUE)
.values().stream().findFirst();
selectedCoord = selectedBlock.orElse(null);
}
@SideOnly(Side.CLIENT)
@@ -1101,19 +1187,15 @@ public class TravelController {
}
public static void showMessage(EntityPlayer player, IChatComponent chatComponent) {
if (Loader.isModLoaded("gtnhlib")) {
if (player instanceof EntityPlayerMP) {
chatComponent.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.WHITE));
GTNHLib.proxy.sendMessageAboveHotbar((EntityPlayerMP) player, chatComponent, 60, true, true);
} else {
GTNHLib.proxy.printMessageAboveHotbar(
EnumChatFormatting.WHITE + chatComponent.getFormattedText(),
60,
true,
true);
}
if (player instanceof EntityPlayerMP) {
chatComponent.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.WHITE));
GTNHLib.proxy.sendMessageAboveHotbar((EntityPlayerMP) player, chatComponent, 60, true, true);
} else {
player.addChatComponentMessage(chatComponent);
GTNHLib.proxy.printMessageAboveHotbar(
EnumChatFormatting.WHITE + chatComponent.getFormattedText(),
60,
true,
true);
}
}
}
@@ -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());
}
}
@@ -346,10 +349,4 @@ public class TileTravelAnchor extends TileEntityEio implements ITravelAccessable
super.invalidate();
TravelController.instance.travelDestinations.remove(worldObj.provider.dimensionId, getLocation());
}
@Override
public void onChunkUnload() {
super.onChunkUnload();
TravelController.instance.travelDestinations.remove(worldObj.provider.dimensionId, getLocation());
}
}
@@ -7,7 +7,10 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.network.play.server.S12PacketEntityVelocity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.ForgeDirection;
import com.enderio.core.common.util.BlockCoord;
import com.enderio.core.common.util.Util;
@@ -18,6 +21,7 @@ import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import crazypants.enderio.Log;
import crazypants.enderio.api.teleport.IItemOfTravel;
import crazypants.enderio.api.teleport.ITravelAccessable;
import crazypants.enderio.api.teleport.TeleportEntityEvent;
import crazypants.enderio.api.teleport.TravelSource;
import crazypants.enderio.teleport.ItemTeleportStaff;
@@ -30,13 +34,27 @@ public class PacketLongDistanceTravelEvent
boolean conserveMotion;
int entityId;
int source;
// Below values are for also attempting a regular blink if the long-distance anchor check fails.
boolean alsoDoTeleport;
int tpX;
int tpY;
int tpZ;
public PacketLongDistanceTravelEvent() {}
public PacketLongDistanceTravelEvent(Entity entity, boolean conserveMotion, TravelSource source) {
this(entity, conserveMotion, source, false, 0, 0, 0);
}
public PacketLongDistanceTravelEvent(Entity entity, boolean conserveMotion, TravelSource source,
boolean alsoDoTeleport, int tpX, int tpY, int tpZ) {
this.conserveMotion = conserveMotion;
this.entityId = entity instanceof EntityPlayer ? -1 : entity.getEntityId();
this.source = source.ordinal();
this.alsoDoTeleport = alsoDoTeleport;
this.tpX = tpX;
this.tpY = tpY;
this.tpZ = tpZ;
}
@Override
@@ -44,6 +62,10 @@ public class PacketLongDistanceTravelEvent
buf.writeBoolean(conserveMotion);
buf.writeInt(entityId);
buf.writeInt(source);
buf.writeBoolean(alsoDoTeleport);
buf.writeInt(tpX);
buf.writeInt(tpY);
buf.writeInt(tpZ);
}
@Override
@@ -51,6 +73,10 @@ public class PacketLongDistanceTravelEvent
conserveMotion = buf.readBoolean();
entityId = buf.readInt();
source = buf.readInt();
alsoDoTeleport = buf.readBoolean();
tpX = buf.readInt();
tpY = buf.readInt();
tpZ = buf.readInt();
}
@Override
@@ -69,7 +95,14 @@ public class PacketLongDistanceTravelEvent
TravelSource source = TravelSource.values()[message.source];
if (!validate(toTp, source)) {
if (!validate(
toTp,
source,
message.conserveMotion,
message.alsoDoTeleport,
message.tpX,
message.tpY,
message.tpZ)) {
Log.LOGGER.warn(
Log.securityMarker,
"Player {} tried to tp without valid prereq.",
@@ -77,35 +110,82 @@ public class PacketLongDistanceTravelEvent
return null;
}
doServerTeleport(toTp, message.conserveMotion, source);
doServerTeleport(
toTp,
message.conserveMotion,
source,
message.alsoDoTeleport,
message.tpX,
message.tpY,
message.tpZ);
return null;
}
private static boolean validate(EntityPlayerMP toTp, TravelSource source) {
private static boolean validate(EntityPlayerMP toTp, TravelSource source, boolean conserveMotion,
boolean alsoDoTeleport, int tpX, int tpY, int tpZ) {
ItemStack equippedItem = toTp.getCurrentEquippedItem();
switch (source) {
case STAFF:
// Not allowed to do teleport staff teleport with regular staff.
if (alsoDoTeleport) {
return false;
}
return equippedItem != null && equippedItem.getItem() instanceof IItemOfTravel
&& ((IItemOfTravel) equippedItem.getItem()).isActive(toTp, equippedItem);
case TELEPORT_STAFF:
// tp staff is creative version of traveling staff
// no energy check or anything else needed
// but the player must actually be equipped with one of these
if (alsoDoTeleport) {
String error = TravelController.instance
.validatePacketTravelEvent(toTp, tpX, tpY, tpZ, 0, conserveMotion, source);
if (error != null) {
return false;
}
}
return equippedItem != null && equippedItem.getItem() instanceof ItemTeleportStaff;
default:
// all other types are not allowed
return false;
}
}
public static boolean doServerTeleport(Entity toTp, boolean conserveMotion, TravelSource source) {
EntityPlayer player = toTp instanceof EntityPlayer ? (EntityPlayer) toTp : null;
Optional<BlockCoord> travelDestination = TravelController.instance.findTravelDestination(player, source);
if (!travelDestination.isPresent()) {
public static boolean doServerTeleport(Entity toTp, boolean conserveMotion, TravelSource source,
boolean alsoDoTeleport, int tpX, int tpY, int tpZ) {
if (!(toTp instanceof EntityPlayer)) {
return false;
}
BlockCoord destination = travelDestination.get();
EntityPlayer player = (EntityPlayer) toTp;
Optional<BlockCoord> travelDestination = TravelController.instance.findTravelDestination(player, source);
if (!travelDestination.isPresent()) {
if (alsoDoTeleport) {
return PacketTravelEvent.doServerTeleport(toTp, tpX, tpY, tpZ, 0, conserveMotion, source);
}
return false;
}
BlockCoord targetBlock = travelDestination.get();
TileEntity te = player.worldObj.getTileEntity(targetBlock.x, targetBlock.y, targetBlock.z);
if (te instanceof ITravelAccessable) {
ITravelAccessable ta = (ITravelAccessable) te;
if (!ta.canBlockBeAccessed(player)) {
TravelController
.showMessage(player, new ChatComponentTranslation("enderio.gui.travelAccessable.unauthorised"));
return false;
}
}
// We're teleporting to a block, so go one above.
BlockCoord destination = targetBlock.getLocation(ForgeDirection.UP);
if (!TravelController.instance.isValidTarget(player, destination, source)) {
TravelController
.showMessage(player, new ChatComponentTranslation("enderio.blockTravelPlatform.invalidTarget"));
return false;
}
int x = destination.x;
int y = destination.y;
int z = destination.z;
@@ -113,7 +193,7 @@ public class PacketLongDistanceTravelEvent
if (powerUse < 0) {
return false;
}
if (player != null && player.getCurrentEquippedItem() != null
if (player.getCurrentEquippedItem() != null
&& player.getCurrentEquippedItem().getItem() instanceof IItemOfTravel) {
int used = ((IItemOfTravel) player.getCurrentEquippedItem().getItem())
.canExtractInternal(player.getCurrentEquippedItem(), powerUse);
@@ -134,32 +214,26 @@ public class PacketLongDistanceTravelEvent
toTp.playSound(source.sound, 1.0F, 1.0F);
if (player != null) {
player.setPositionAndUpdate(x + 0.5, y + 1.1, z + 0.5);
} else {
toTp.setPosition(x, y, z);
player.setPositionAndUpdate(x + 0.5, y + 0.1, z + 0.5);
player.worldObj.playSoundEffect(x, y, z, source.sound, 1.0F, 1.0F);
player.fallDistance = 0;
if (conserveMotion) {
Vector3d velocityVex = Util.getLookVecEio(player);
S12PacketEntityVelocity p = new S12PacketEntityVelocity(
toTp.getEntityId(),
velocityVex.x,
velocityVex.y,
velocityVex.z);
((EntityPlayerMP) player).playerNetServerHandler.sendPacket(p);
}
toTp.worldObj.playSoundEffect(x, y, z, source.sound, 1.0F, 1.0F);
toTp.fallDistance = 0;
if (player != null) {
if (conserveMotion) {
Vector3d velocityVex = Util.getLookVecEio(player);
S12PacketEntityVelocity p = new S12PacketEntityVelocity(
toTp.getEntityId(),
velocityVex.x,
velocityVex.y,
velocityVex.z);
((EntityPlayerMP) player).playerNetServerHandler.sendPacket(p);
}
if (powerUse > 0 && player.getCurrentEquippedItem() != null
&& player.getCurrentEquippedItem().getItem() instanceof IItemOfTravel) {
ItemStack item = player.getCurrentEquippedItem().copy();
((IItemOfTravel) item.getItem()).extractInternal(item, powerUse);
toTp.setCurrentItemOrArmor(0, item);
}
if (powerUse > 0 && player.getCurrentEquippedItem() != null
&& player.getCurrentEquippedItem().getItem() instanceof IItemOfTravel) {
ItemStack item = player.getCurrentEquippedItem().copy();
((IItemOfTravel) item.getItem()).extractInternal(item, powerUse);
toTp.setCurrentItemOrArmor(0, item);
}
return true;
@@ -118,7 +118,7 @@ public class PacketTravelEvent implements IMessage, IMessageHandler<PacketTravel
toTp.playSound(source.sound, 1.0F, 1.0F);
if (player != null) {
player.setPositionAndUpdate(x + 0.5, y + 1.1, z + 0.5);
player.setPositionAndUpdate(x + 0.5, y + 0.1, z + 0.5);
} else {
toTp.setPosition(x, y, z);
}
+33 -12
View File
@@ -1,10 +1,14 @@
package crazypants.util;
import java.util.List;
import java.util.Random;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.EffectRenderer;
import net.minecraft.client.particle.EntityPortalFX;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import com.enderio.core.common.util.BlockCoord;
@@ -47,18 +51,35 @@ public class ClientUtil {
con.readFromNBT(pkt.tc, TileConduitBundle.NBT_VERSION);
}
public static void spawnFarmParcticles(Random rand, BlockCoord bc) {
double xOff = 0.5 + (rand.nextDouble() - 0.5) * 1.1;
double yOff = 0.5 + (rand.nextDouble() - 0.5) * 0.2;
double zOff = 0.5 + (rand.nextDouble() - 0.5) * 1.1;
Minecraft.getMinecraft().theWorld.spawnParticle(
"portal",
bc.x + xOff,
bc.y + yOff,
bc.z + zOff,
(rand.nextDouble() - 0.5) * 1.5,
-rand.nextDouble(),
(rand.nextDouble() - 0.5) * 1.5);
public static void spawnFarmParticles(Random rand, List<BlockCoord> coords, int particlesCount) {
// 0 = All, 1 = Decreased, 2 = Minimal
int particleSetting = Minecraft.getMinecraft().gameSettings.particleSetting;
if (particleSetting >= 2 /* Minimal */) {
return;
}
int particles = particleSetting == 0 ? particlesCount /* All */
: (particlesCount / 2) /* Decreased */;
World world = Minecraft.getMinecraft().theWorld;
EffectRenderer effectRenderer = Minecraft.getMinecraft().effectRenderer;
for (BlockCoord bc : coords) {
for (int i = 0; i < particles; i++) {
double xOff = 0.5 + (rand.nextDouble() - 0.5) * 1.1;
double yOff = 0.5 + (rand.nextDouble() - 0.5) * 0.2;
double zOff = 0.5 + (rand.nextDouble() - 0.5) * 1.1;
effectRenderer.addEffect(
new EntityPortalFX(
world,
bc.x + xOff,
bc.y + yOff,
bc.z + zOff,
(rand.nextDouble() - 0.5) * 1.5,
-rand.nextDouble(),
(rand.nextDouble() - 0.5) * 1.5));
}
}
}
public static void setTankNBT(PacketCombustionTank message, int x, int y, int z) {
@@ -150,7 +150,7 @@ enderio.silicon.name=Silicon
enderio.conduitBinder.name=Conduit Binder
enderio.binderComposite.name=Binder Composite
enderio.phasedIronNugget.name=Pulsating Iron Nugget
tile.blockDarkIronBars.name=Dark Iron Bars
tile.blockDarkIronBars.name=Dark Steel Bars
tile.blockSoulariumBars.name=Soularium Bars
tile.blockEndSteelBars.name=End Steel Bars
tile.blockEndermanSkull.name=Enderman Skull