This commit is contained in:
parent
ca7a57e381
commit
82b663ac31
|
@ -1,6 +1,5 @@
|
||||||
package net.hoosiertransfer.Alfheim.lighting;
|
package net.hoosiertransfer.Alfheim.lighting;
|
||||||
|
|
||||||
import net.hoosiertransfer.Alfheim.IChunkLightingData;
|
|
||||||
import net.hoosiertransfer.Alfheim.util.ClampUtil;
|
import net.hoosiertransfer.Alfheim.util.ClampUtil;
|
||||||
import net.hoosiertransfer.Alfheim.util.DeduplicatedLongQueue;
|
import net.hoosiertransfer.Alfheim.util.DeduplicatedLongQueue;
|
||||||
import net.hoosiertransfer.teavm.ReentrantLock;
|
import net.hoosiertransfer.teavm.ReentrantLock;
|
||||||
|
@ -35,20 +34,17 @@ public class LightingEngine {
|
||||||
|
|
||||||
private boolean updating = false;
|
private boolean updating = false;
|
||||||
|
|
||||||
private static final int
|
private static final int L_X = 26,
|
||||||
L_X = 26,
|
|
||||||
L_Y = 8,
|
L_Y = 8,
|
||||||
L_Z = 26,
|
L_Z = 26,
|
||||||
L_L = 4;
|
L_L = 4;
|
||||||
|
|
||||||
private static final int
|
private static final int S_Z = 0,
|
||||||
S_Z = 0,
|
|
||||||
S_X = S_Z + L_Z,
|
S_X = S_Z + L_Z,
|
||||||
S_Y = S_X + L_X,
|
S_Y = S_X + L_X,
|
||||||
S_L = S_Y + L_Y;
|
S_L = S_Y + L_Y;
|
||||||
|
|
||||||
private static final long
|
private static final long M_X = (1L << L_X) - 1,
|
||||||
M_X = (1L << L_X) - 1,
|
|
||||||
M_Y = (1L << L_Y) - 1,
|
M_Y = (1L << L_Y) - 1,
|
||||||
M_Z = (1L << L_Z) - 1,
|
M_Z = (1L << L_Z) - 1,
|
||||||
M_L = (1L << L_L) - 1,
|
M_L = (1L << L_L) - 1,
|
||||||
|
@ -61,7 +57,8 @@ public class LightingEngine {
|
||||||
static {
|
static {
|
||||||
for (byte i = 0; i < 6; ++i) {
|
for (byte i = 0; i < 6; ++i) {
|
||||||
final Vec3i offset = EnumFacing._VALUES[i].getDirectionVec();
|
final Vec3i offset = EnumFacing._VALUES[i].getDirectionVec();
|
||||||
neighborShifts[i] = ((long) offset.getY() << S_Y) | ((long) offset.getX() << S_X) | ((long) offset.getZ() << S_Z);
|
neighborShifts[i] = ((long) offset.getY() << S_Y) | ((long) offset.getX() << S_X)
|
||||||
|
| ((long) offset.getZ() << S_Z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +111,10 @@ public class LightingEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processLightUpdatesForType(final EnumSkyBlock lightType) {
|
public void processLightUpdatesForType(final EnumSkyBlock lightType) {
|
||||||
// We only want to perform updates if we're being called from a tick event on the client.
|
// We only want to perform updates if we're being called from a tick event on
|
||||||
// There are many locations in the client code that will end up making calls to this method, usually from other threads.
|
// the client.
|
||||||
|
// There are many locations in the client code that will end up making calls to
|
||||||
|
// this method, usually from other threads.
|
||||||
if (world.isRemote && !isCallingFromMainThread())
|
if (world.isRemote && !isCallingFromMainThread())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -158,26 +157,35 @@ public class LightingEngine {
|
||||||
if (lock.tryLock())
|
if (lock.tryLock())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If we cannot lock, something has gone wrong... Only one thread should ever acquire the lock.
|
// If we cannot lock, something has gone wrong... Only one thread should ever
|
||||||
// Validate that we're on the right thread immediately, so we can gather information.
|
// acquire the lock.
|
||||||
// It is NEVER valid to call World methods from a thread other than the owning thread of the world instance.
|
// Validate that we're on the right thread immediately, so we can gather
|
||||||
|
// information.
|
||||||
|
// It is NEVER valid to call World methods from a thread other than the owning
|
||||||
|
// thread of the world instance.
|
||||||
final Thread current = Thread.currentThread();
|
final Thread current = Thread.currentThread();
|
||||||
|
|
||||||
if (current != ownerThread) {
|
if (current != ownerThread) {
|
||||||
final IllegalAccessException illegalAccessException = new IllegalAccessException(String.format("World is owned by '%s' (ID: %s)," + " but was accessed from thread '%s' (ID: %s)", ownerThread.getName(), ownerThread.getId(), current.getName(), current.getId()));
|
final IllegalAccessException illegalAccessException = new IllegalAccessException(
|
||||||
|
String.format("World is owned by '%s' (ID: %s)," + " but was accessed from thread '%s' (ID: %s)",
|
||||||
|
ownerThread.getName(), ownerThread.threadId(), current.getName(), current.threadId()));
|
||||||
|
|
||||||
System.out.println(
|
System.out.println(
|
||||||
"Something (likely another mod) has attempted to modify the world's state from the wrong thread!\n" +
|
"Something (likely another mod) has attempted to modify the world's state from the wrong thread!\n"
|
||||||
|
+
|
||||||
"This is *bad practice* and can cause severe issues in your game.\n" +
|
"This is *bad practice* and can cause severe issues in your game.\n" +
|
||||||
"Alfheim has done as best as it can to mitigate this violation, but it may negatively impact performance or introduce stalls.\n" +
|
"Alfheim has done as best as it can to mitigate this violation, but it may negatively impact performance or introduce stalls.\n"
|
||||||
"In a future release, this violation may result in a hard crash instead of the current soft warning.\n" +
|
+
|
||||||
|
"In a future release, this violation may result in a hard crash instead of the current soft warning.\n"
|
||||||
|
+
|
||||||
"You should report this issue to our issue tracker with the following stacktrace information.");
|
"You should report this issue to our issue tracker with the following stacktrace information.");
|
||||||
|
|
||||||
illegalAccessException.printStackTrace();
|
illegalAccessException.printStackTrace();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the lock to be released. This will likely introduce unwanted stalls, but will mitigate the issue.
|
// Wait for the lock to be released. This will likely introduce unwanted stalls,
|
||||||
|
// but will mitigate the issue.
|
||||||
lock.lock();
|
lock.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,9 +214,12 @@ public class LightingEngine {
|
||||||
final byte newLight = calculateNewLightFromCursor(lightType);
|
final byte newLight = calculateNewLightFromCursor(lightType);
|
||||||
|
|
||||||
if (oldLight < newLight)
|
if (oldLight < newLight)
|
||||||
initialBrightenings.enqueue(((long) newLight << S_L) | currentData); // Don't enqueue directly for brightening to avoid duplicate scheduling
|
initialBrightenings.enqueue(((long) newLight << S_L) | currentData); // Don't enqueue directly for
|
||||||
|
// brightening to avoid duplicate
|
||||||
|
// scheduling
|
||||||
else if (oldLight > newLight)
|
else if (oldLight > newLight)
|
||||||
initialDarkenings.enqueue(currentData); // Don't enqueue directly for darkening to avoid duplicate scheduling
|
initialDarkenings.enqueue(currentData); // Don't enqueue directly for darkening to avoid duplicate
|
||||||
|
// scheduling
|
||||||
}
|
}
|
||||||
|
|
||||||
profiler.endStartSection("enqueueBrightening");
|
profiler.endStartSection("enqueueBrightening");
|
||||||
|
@ -222,7 +233,14 @@ public class LightingEngine {
|
||||||
final byte newLight = (byte) (currentData >> S_L & M_L);
|
final byte newLight = (byte) (currentData >> S_L & M_L);
|
||||||
|
|
||||||
if (newLight > getCursorCachedLight(lightType))
|
if (newLight > getCursorCachedLight(lightType))
|
||||||
enqueueBrightening(currentPos, currentData & M_POS, newLight, currentChunk, lightType); // Sets the light to newLight to only schedule once. Clear leading bits of curData for later
|
enqueueBrightening(currentPos, currentData & M_POS, newLight, currentChunk, lightType); // Sets the
|
||||||
|
// light to
|
||||||
|
// newLight to
|
||||||
|
// only schedule
|
||||||
|
// once. Clear
|
||||||
|
// leading bits
|
||||||
|
// of curData
|
||||||
|
// for later
|
||||||
}
|
}
|
||||||
|
|
||||||
profiler.endStartSection("enqueueDarkening");
|
profiler.endStartSection("enqueueDarkening");
|
||||||
|
@ -236,12 +254,14 @@ public class LightingEngine {
|
||||||
final byte oldLight = getCursorCachedLight(lightType);
|
final byte oldLight = getCursorCachedLight(lightType);
|
||||||
|
|
||||||
if (oldLight != 0)
|
if (oldLight != 0)
|
||||||
enqueueDarkening(currentPos, currentData, oldLight, currentChunk, lightType); // Sets the light to zero to only schedule once
|
enqueueDarkening(currentPos, currentData, oldLight, currentChunk, lightType); // Sets the light to zero
|
||||||
|
// to only schedule once
|
||||||
}
|
}
|
||||||
|
|
||||||
profiler.endStartSection("process");
|
profiler.endStartSection("process");
|
||||||
|
|
||||||
// Iterate through enqueued updates (brightening and darkening in parallel) from brightest to darkest so that we only need to iterate once
|
// Iterate through enqueued updates (brightening and darkening in parallel) from
|
||||||
|
// brightest to darkest so that we only need to iterate once
|
||||||
for (byte currentLight = MAX_LIGHT_LEVEL; currentLight >= 0; --currentLight) {
|
for (byte currentLight = MAX_LIGHT_LEVEL; currentLight >= 0; --currentLight) {
|
||||||
currentQueue = darkeningQueues[currentLight];
|
currentQueue = darkeningQueues[currentLight];
|
||||||
|
|
||||||
|
@ -264,7 +284,8 @@ public class LightingEngine {
|
||||||
|
|
||||||
// Only darken neighbors if we indeed became darker
|
// Only darken neighbors if we indeed became darker
|
||||||
if (calculateNewLightFromCursor(luminosity, opacity, lightType) < currentLight) {
|
if (calculateNewLightFromCursor(luminosity, opacity, lightType) < currentLight) {
|
||||||
// Need to calculate new light value from neighbors IGNORING neighbors which are scheduled for darkening
|
// Need to calculate new light value from neighbors IGNORING neighbors which are
|
||||||
|
// scheduled for darkening
|
||||||
byte newLight = luminosity;
|
byte newLight = luminosity;
|
||||||
|
|
||||||
fetchNeighborDataFromCursor(lightType);
|
fetchNeighborDataFromCursor(lightType);
|
||||||
|
@ -282,18 +303,27 @@ public class LightingEngine {
|
||||||
|
|
||||||
final MutableBlockPos neighborPos = neighborInfo.mutableBlockPos;
|
final MutableBlockPos neighborPos = neighborInfo.mutableBlockPos;
|
||||||
|
|
||||||
if (currentLight - getPosOpacity(neighborPos, neighborChunk.getBlockState(neighborPos)) >= neighborLight) /*Schedule neighbor for darkening if we possibly light it*/ {
|
if (currentLight - getPosOpacity(neighborPos, neighborChunk
|
||||||
|
.getBlockState(neighborPos)) >= neighborLight) /*
|
||||||
|
* Schedule neighbor for darkening if we
|
||||||
|
* possibly light it
|
||||||
|
*/ {
|
||||||
enqueueDarkening(neighborPos, neighborInfo.key, neighborLight, neighborChunk, lightType);
|
enqueueDarkening(neighborPos, neighborInfo.key, neighborLight, neighborChunk, lightType);
|
||||||
} else /* Only use for new light calculation if not */ {
|
} else /* Only use for new light calculation if not */ {
|
||||||
// If we can't darken the neighbor, no one else can (because of processing order) -> safe to let us be illuminated by it
|
// If we can't darken the neighbor, no one else can (because of processing
|
||||||
|
// order) -> safe to let us be illuminated by it
|
||||||
newLight = (byte) Math.max(newLight, neighborLight - opacity);
|
newLight = (byte) Math.max(newLight, neighborLight - opacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule brightening since light level was set to 0
|
// Schedule brightening since light level was set to 0
|
||||||
enqueueBrighteningFromCursor(newLight, lightType);
|
enqueueBrighteningFromCursor(newLight, lightType);
|
||||||
} else /*We didn't become darker, so we need to re-set our initial light value (was set to zero) and notify neighbors*/ {
|
} else /*
|
||||||
enqueueBrighteningFromCursor(currentLight, lightType); // Do not spread to neighbors immediately to avoid scheduling multiple times
|
* We didn't become darker, so we need to re-set our initial light value (was
|
||||||
|
* set to zero) and notify neighbors
|
||||||
|
*/ {
|
||||||
|
enqueueBrighteningFromCursor(currentLight, lightType); // Do not spread to neighbors immediately to
|
||||||
|
// avoid scheduling multiple times
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +335,8 @@ public class LightingEngine {
|
||||||
while (nextItem()) {
|
while (nextItem()) {
|
||||||
final byte oldLight = getCursorCachedLight(lightType);
|
final byte oldLight = getCursorCachedLight(lightType);
|
||||||
|
|
||||||
// Only process this if nothing else has happened at this position since scheduling
|
// Only process this if nothing else has happened at this position since
|
||||||
|
// scheduling
|
||||||
if (oldLight == currentLight) {
|
if (oldLight == currentLight) {
|
||||||
world.notifyLightSet(currentPos);
|
world.notifyLightSet(currentPos);
|
||||||
|
|
||||||
|
@ -346,14 +377,16 @@ public class LightingEngine {
|
||||||
neighborChunk = neighborInfo.chunk = getChunk(neighborPos);
|
neighborChunk = neighborInfo.chunk = getChunk(neighborPos);
|
||||||
|
|
||||||
if (neighborChunk != null) {
|
if (neighborChunk != null) {
|
||||||
final ExtendedBlockStorage neighborSection = neighborChunk.getBlockStorageArray()[neighborPos.getY() >> 4];
|
final ExtendedBlockStorage neighborSection = neighborChunk
|
||||||
|
.getBlockStorageArray()[neighborPos.getY() >> 4];
|
||||||
|
|
||||||
neighborInfo.light = getCachedLightFor(neighborChunk, neighborSection, neighborPos, lightType);
|
neighborInfo.light = getCachedLightFor(neighborChunk, neighborSection, neighborPos, lightType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte getCachedLightFor(final Chunk chunk, final ExtendedBlockStorage storage, final BlockPos blockPos, final EnumSkyBlock type) {
|
private static byte getCachedLightFor(final Chunk chunk, final ExtendedBlockStorage storage,
|
||||||
|
final BlockPos blockPos, final EnumSkyBlock type) {
|
||||||
final int x = blockPos.getX() & 15;
|
final int x = blockPos.getX() & 15;
|
||||||
final int y = blockPos.getY();
|
final int y = blockPos.getY();
|
||||||
final int z = blockPos.getZ() & 15;
|
final int z = blockPos.getZ() & 15;
|
||||||
|
@ -363,7 +396,8 @@ public class LightingEngine {
|
||||||
else if (type == EnumSkyBlock.SKY)
|
else if (type == EnumSkyBlock.SKY)
|
||||||
return !chunk.getWorld().provider.getHasNoSky() ? (byte) storage.getExtSkylightValue(x, y & 15, z) : 0;
|
return !chunk.getWorld().provider.getHasNoSky() ? (byte) storage.getExtSkylightValue(x, y & 15, z) : 0;
|
||||||
else
|
else
|
||||||
return type == EnumSkyBlock.BLOCK ? (byte) storage.getExtBlocklightValue(x, y & 15, z) : (byte) type.defaultLightValue;
|
return type == EnumSkyBlock.BLOCK ? (byte) storage.getExtBlocklightValue(x, y & 15, z)
|
||||||
|
: (byte) type.defaultLightValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte calculateNewLightFromCursor(final EnumSkyBlock lightType) {
|
private byte calculateNewLightFromCursor(final EnumSkyBlock lightType) {
|
||||||
|
@ -409,7 +443,8 @@ public class LightingEngine {
|
||||||
|
|
||||||
final BlockPos neighborBlockPos = neighborInfo.mutableBlockPos;
|
final BlockPos neighborBlockPos = neighborInfo.mutableBlockPos;
|
||||||
|
|
||||||
final byte newLight = (byte) (currentLight - getPosOpacity(neighborBlockPos, neighborChunk.getBlockState(neighborBlockPos)));
|
final byte newLight = (byte) (currentLight
|
||||||
|
- getPosOpacity(neighborBlockPos, neighborChunk.getBlockState(neighborBlockPos)));
|
||||||
|
|
||||||
if (newLight > neighborInfo.light)
|
if (newLight > neighborInfo.light)
|
||||||
enqueueBrightening(neighborBlockPos, neighborInfo.key, newLight, neighborChunk, lightType);
|
enqueueBrightening(neighborBlockPos, neighborInfo.key, newLight, neighborChunk, lightType);
|
||||||
|
@ -420,24 +455,28 @@ public class LightingEngine {
|
||||||
enqueueBrightening(currentPos, currentData, newLight, currentChunk, lightType);
|
enqueueBrightening(currentPos, currentData, newLight, currentChunk, lightType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enqueueBrightening(final BlockPos blockPos, final long longPos, final byte newLight, final Chunk chunk, final EnumSkyBlock lightType) {
|
private void enqueueBrightening(final BlockPos blockPos, final long longPos, final byte newLight, final Chunk chunk,
|
||||||
|
final EnumSkyBlock lightType) {
|
||||||
brighteningQueues[newLight].enqueue(longPos);
|
brighteningQueues[newLight].enqueue(longPos);
|
||||||
|
|
||||||
chunk.setLightFor(lightType, blockPos, newLight);
|
chunk.setLightFor(lightType, blockPos, newLight);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enqueueDarkening(final BlockPos blockPos, final long longPos, final byte oldLight, final Chunk chunk, final EnumSkyBlock lightType) {
|
private void enqueueDarkening(final BlockPos blockPos, final long longPos, final byte oldLight, final Chunk chunk,
|
||||||
|
final EnumSkyBlock lightType) {
|
||||||
darkeningQueues[oldLight].enqueue(longPos);
|
darkeningQueues[oldLight].enqueue(longPos);
|
||||||
|
|
||||||
chunk.setLightFor(lightType, blockPos, 0);
|
chunk.setLightFor(lightType, blockPos, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MutableBlockPos decodeWorldCoord(final MutableBlockPos mutableBlockPos, final long longPos) {
|
private static MutableBlockPos decodeWorldCoord(final MutableBlockPos mutableBlockPos, final long longPos) {
|
||||||
return mutableBlockPos.setPos((int) (longPos >> S_X & M_X) - (1 << L_X - 1), (int) (longPos >> S_Y & M_Y), (int) (longPos >> S_Z & M_Z) - (1 << L_Z - 1));
|
return mutableBlockPos.setPos((int) (longPos >> S_X & M_X) - (1 << L_X - 1), (int) (longPos >> S_Y & M_Y),
|
||||||
|
(int) (longPos >> S_Z & M_Z) - (1 << L_Z - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long encodeWorldCoord(final BlockPos pos) {
|
private static long encodeWorldCoord(final BlockPos pos) {
|
||||||
return ((long) pos.getY() << S_Y) | ((long) pos.getX() + (1 << L_X - 1) << S_X) | ((long) pos.getZ() + (1 << L_Z - 1) << S_Z);
|
return ((long) pos.getY() << S_Y) | ((long) pos.getX() + (1 << L_X - 1) << S_X)
|
||||||
|
| ((long) pos.getZ() + (1 << L_Z - 1) << S_Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean nextItem() {
|
private boolean nextItem() {
|
||||||
|
@ -464,7 +503,9 @@ public class LightingEngine {
|
||||||
|
|
||||||
private byte getCursorCachedLight(final EnumSkyBlock lightType) {
|
private byte getCursorCachedLight(final EnumSkyBlock lightType) {
|
||||||
return currentChunk.alfheim$getCachedLightFor(lightType, currentPos);
|
return currentChunk.alfheim$getCachedLightFor(lightType, currentPos);
|
||||||
// return ((IChunkLightingData) currentChunk).alfheim$getCachedLightFor(lightType, currentPos); // OK TEAVM YOU ARE THE WORST THING I HAVE HAD TO WORK WITH YET
|
// return ((IChunkLightingData)
|
||||||
|
// currentChunk).alfheim$getCachedLightFor(lightType, currentPos); // OK TEAVM
|
||||||
|
// YOU ARE THE WORST THING I HAVE HAD TO WORK WITH YET
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte getCursorLuminosity(final IBlockState state, final EnumSkyBlock lightType) {
|
private byte getCursorLuminosity(final IBlockState state, final EnumSkyBlock lightType) {
|
||||||
|
@ -475,7 +516,8 @@ public class LightingEngine {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (byte) ClampUtil.clampMinFirst(LightUtil.getLightValueForState(state, world, currentPos), 0, MAX_LIGHT_LEVEL);
|
return (byte) ClampUtil.clampMinFirst(LightUtil.getLightValueForState(state, world, currentPos), 0,
|
||||||
|
MAX_LIGHT_LEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte getPosOpacity(final BlockPos blockPos, final IBlockState blockState) {
|
private byte getPosOpacity(final BlockPos blockPos, final IBlockState blockState) {
|
||||||
|
@ -486,7 +528,6 @@ public class LightingEngine {
|
||||||
return world.getChunkProvider().getLoadedChunk(blockPos.getX() >> 4, blockPos.getZ() >> 4);
|
return world.getChunkProvider().getLoadedChunk(blockPos.getX() >> 4, blockPos.getZ() >> 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static final class NeighborInfo {
|
private static final class NeighborInfo {
|
||||||
|
|
||||||
public final MutableBlockPos mutableBlockPos = new MutableBlockPos();
|
public final MutableBlockPos mutableBlockPos = new MutableBlockPos();
|
||||||
|
|
|
@ -14,14 +14,21 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer;
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2023-2024 lax1dude. All Rights Reserved.
|
* Copyright (c) 2023-2024 lax1dude. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
* DISCLAIMED.
|
||||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* DIRECT,
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
* (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE)
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
|
@ -117,7 +124,8 @@ public class VFile2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertNotRelative() {
|
public void assertNotRelative() {
|
||||||
if(isRelative()) throw new EaglerFileSystemException("Relative paths are not allowed: " + path);
|
if (isRelative())
|
||||||
|
throw new EaglerFileSystemException("Relative paths are not allowed: " + path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canRead() {
|
public boolean canRead() {
|
||||||
|
|
Loading…
Reference in New Issue