alfheim lighting engine
This commit is contained in:
parent
7e49cad89c
commit
27ca7c5b40
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1334455
javascript/classes.js
1334455
javascript/classes.js
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,21 @@
|
|||
package net.hoosiertransfer.Alfheim;
|
||||
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
|
||||
public interface IChunkLightingData {
|
||||
|
||||
short[] alfheim$getNeighborLightChecks();
|
||||
|
||||
void alfheim$setNeighborLightChecks(final short[] data);
|
||||
|
||||
boolean alfheim$isLightInitialized();
|
||||
|
||||
void alfheim$setLightInitialized(final boolean lightInitialized);
|
||||
|
||||
void alfheim$setSkylightUpdatedPublic();
|
||||
|
||||
void alfheim$initNeighborLightChecks();
|
||||
|
||||
byte alfheim$getCachedLightFor(final EnumSkyBlock enumSkyBlock, final BlockPos pos);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package net.hoosiertransfer.Alfheim;
|
||||
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
public interface ILightInfoProvider {
|
||||
|
||||
int alfheim$getLightFor(final IBlockAccess iBlockAccess, final EnumSkyBlock lightType, final BlockPos blockPos);
|
||||
|
||||
boolean alfheim$useNeighborBrightness(final EnumFacing facing, final IBlockAccess blockAccess, final BlockPos blockPos);
|
||||
|
||||
int alfheim$getLightOpacity(final EnumFacing facing, final IBlockAccess blockAccess, final BlockPos blockPos);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package net.hoosiertransfer.Alfheim;
|
||||
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
|
||||
/**
|
||||
* @author Luna Lage (Desoroxxx)
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface ILightLevelProvider {
|
||||
|
||||
int alfheim$getLight(final EnumSkyBlock lightType, final BlockPos blockPos);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package net.hoosiertransfer.Alfheim;
|
||||
|
||||
public interface ILightUpdatesProcessor {
|
||||
|
||||
void alfheim$processLightUpdates();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package net.hoosiertransfer.Alfheim;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.lighting.LightingEngine;
|
||||
|
||||
/**
|
||||
* @author Luna Lage (Desoroxxx)
|
||||
* @author Angeline (@jellysquid)
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface ILightingEngineProvider {
|
||||
|
||||
LightingEngine alfheim$getLightingEngine();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package net.hoosiertransfer.Alfheim;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
public interface ILitBlock {
|
||||
int alfheim$getLightFor(final IBlockState blockState, final IBlockAccess blockAccess, final EnumSkyBlock lightType, final BlockPos blockPos);
|
||||
boolean alfheim$useNeighborBrightness(final IBlockState blockState, final EnumFacing facing, final IBlockAccess blockAccess, final BlockPos blockPos);
|
||||
int alfheim$getLightOpacity(final IBlockState blockState, final EnumFacing facing, final IBlockAccess blockAccess, final BlockPos blockPos);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package net.hoosiertransfer.Alfheim.lighting;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
public class LightUtil {
|
||||
public static int getLightValueForState(final IBlockState blockState, final IBlockAccess blockAccess, final BlockPos blockPos) {
|
||||
return blockState.getLightValue(blockAccess, blockPos);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,500 @@
|
|||
package net.hoosiertransfer.Alfheim.lighting;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.IChunkLightingData;
|
||||
import net.hoosiertransfer.Alfheim.util.ClampUtil;
|
||||
import net.hoosiertransfer.Alfheim.util.DeduplicatedLongQueue;
|
||||
import net.hoosiertransfer.teavm.ReentrantLock;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.profiler.Profiler;
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.Vec3i;
|
||||
import net.minecraft.util.BlockPos.MutableBlockPos;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
public class LightingEngine {
|
||||
private static final byte MAX_LIGHT_LEVEL = 15;
|
||||
|
||||
private final Thread ownerThread = Thread.currentThread();
|
||||
|
||||
private final World world;
|
||||
|
||||
private final Profiler profiler;
|
||||
|
||||
private final DeduplicatedLongQueue[] lightUpdateQueues = new DeduplicatedLongQueue[EnumSkyBlock.values().length];
|
||||
|
||||
private final DeduplicatedLongQueue[] darkeningQueues = new DeduplicatedLongQueue[MAX_LIGHT_LEVEL + 1];
|
||||
private final DeduplicatedLongQueue[] brighteningQueues = new DeduplicatedLongQueue[MAX_LIGHT_LEVEL + 1];
|
||||
|
||||
private final DeduplicatedLongQueue initialBrightenings;
|
||||
private final DeduplicatedLongQueue initialDarkenings;
|
||||
|
||||
private boolean updating = false;
|
||||
|
||||
private static final int
|
||||
L_X = 26,
|
||||
L_Y = 8,
|
||||
L_Z = 26,
|
||||
L_L = 4;
|
||||
|
||||
private static final int
|
||||
S_Z = 0,
|
||||
S_X = S_Z + L_Z,
|
||||
S_Y = S_X + L_X,
|
||||
S_L = S_Y + L_Y;
|
||||
|
||||
private static final long
|
||||
M_X = (1L << L_X) - 1,
|
||||
M_Y = (1L << L_Y) - 1,
|
||||
M_Z = (1L << L_Z) - 1,
|
||||
M_L = (1L << L_L) - 1,
|
||||
M_POS = (M_Y << S_Y) | (M_X << S_X) | (M_Z << S_Z);
|
||||
|
||||
private static final long Y_CHECK = 1L << (S_Y + L_Y);
|
||||
|
||||
private static final long[] neighborShifts = new long[6];
|
||||
|
||||
static {
|
||||
for (byte i = 0; i < 6; ++i) {
|
||||
final Vec3i offset = EnumFacing._VALUES[i].getDirectionVec();
|
||||
neighborShifts[i] = ((long) offset.getY() << S_Y) | ((long) offset.getX() << S_X) | ((long) offset.getZ() << S_Z);
|
||||
}
|
||||
}
|
||||
|
||||
private static final long M_CHUNK = ((M_X >> 4) << (4 + S_X)) | ((M_Z >> 4) << (4 + S_Z));
|
||||
|
||||
private final MutableBlockPos currentPos = new MutableBlockPos();
|
||||
private Chunk currentChunk;
|
||||
private long currentChunkIdentifier;
|
||||
private long currentData;
|
||||
|
||||
private boolean isNeighborDataValid = false;
|
||||
|
||||
private final NeighborInfo[] neighborInfos = new NeighborInfo[6];
|
||||
private DeduplicatedLongQueue currentQueue;
|
||||
|
||||
private ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
public LightingEngine(final World world) {
|
||||
this.world = world;
|
||||
profiler = world.theProfiler;
|
||||
|
||||
initialBrightenings = new DeduplicatedLongQueue(16384);
|
||||
initialDarkenings = new DeduplicatedLongQueue(16384);
|
||||
|
||||
for (int i = 0; i < EnumSkyBlock.values().length; ++i)
|
||||
lightUpdateQueues[i] = new DeduplicatedLongQueue(16384);
|
||||
|
||||
for (int i = 0; i < darkeningQueues.length; ++i)
|
||||
darkeningQueues[i] = new DeduplicatedLongQueue(16384);
|
||||
|
||||
for (int i = 0; i < brighteningQueues.length; ++i)
|
||||
brighteningQueues[i] = new DeduplicatedLongQueue(16384);
|
||||
|
||||
for (int i = 0; i < neighborInfos.length; ++i)
|
||||
neighborInfos[i] = new NeighborInfo();
|
||||
}
|
||||
|
||||
public void scheduleLightUpdate(final EnumSkyBlock lightType, final BlockPos pos) {
|
||||
lock();
|
||||
|
||||
try {
|
||||
scheduleLightUpdate(lightType, encodeWorldCoord(pos));
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleLightUpdate(final EnumSkyBlock lightType, final long blockPos) {
|
||||
lightUpdateQueues[lightType.ordinal()].enqueue(blockPos);
|
||||
}
|
||||
|
||||
public void processLightUpdatesForType(final EnumSkyBlock lightType) {
|
||||
// We only want to perform updates if we're being called from a tick event on 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())
|
||||
return;
|
||||
|
||||
final DeduplicatedLongQueue queue = lightUpdateQueues[lightType.ordinal()];
|
||||
|
||||
// Quickly check if the queue is empty before we acquire a more expensive lock.
|
||||
if (queue.isEmpty())
|
||||
return;
|
||||
|
||||
profiler.startSection("process");
|
||||
|
||||
lock();
|
||||
|
||||
try {
|
||||
processLightUpdatesForTypeInner(lightType, queue);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
profiler.endSection();
|
||||
}
|
||||
|
||||
private boolean isCallingFromMainThread() {
|
||||
return Minecraft.getMinecraft().isCallingFromMinecraftThread();
|
||||
}
|
||||
|
||||
public void processLightUpdates() {
|
||||
profiler.startSection("processSky");
|
||||
|
||||
processLightUpdatesForType(EnumSkyBlock.SKY);
|
||||
|
||||
profiler.endStartSection("processBlock");
|
||||
|
||||
processLightUpdatesForType(EnumSkyBlock.BLOCK);
|
||||
|
||||
profiler.endSection();
|
||||
}
|
||||
|
||||
private void lock() {
|
||||
if (lock.tryLock())
|
||||
return;
|
||||
|
||||
// If we cannot lock, something has gone wrong... Only one thread should ever acquire the lock.
|
||||
// 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();
|
||||
|
||||
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()));
|
||||
|
||||
System.out.println(
|
||||
"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" +
|
||||
"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" +
|
||||
"You should report this issue to our issue tracker with the following stacktrace information.");
|
||||
|
||||
illegalAccessException.printStackTrace();
|
||||
|
||||
}
|
||||
|
||||
// Wait for the lock to be released. This will likely introduce unwanted stalls, but will mitigate the issue.
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
private void processLightUpdatesForTypeInner(final EnumSkyBlock lightType, final DeduplicatedLongQueue queue) {
|
||||
// Avoid nested calls
|
||||
if (updating)
|
||||
throw new IllegalStateException("Already processing updates!");
|
||||
|
||||
updating = true;
|
||||
|
||||
currentChunkIdentifier = -1; // Reset chunk cache
|
||||
|
||||
currentQueue = queue;
|
||||
|
||||
if (currentQueue != null)
|
||||
currentQueue.clearSet();
|
||||
|
||||
profiler.startSection("prepare");
|
||||
|
||||
// Process the queued updates and enqueue them for further processing
|
||||
while (nextItem()) {
|
||||
if (currentChunk == null)
|
||||
continue;
|
||||
|
||||
final byte oldLight = getCursorCachedLight(lightType);
|
||||
final byte newLight = calculateNewLightFromCursor(lightType);
|
||||
|
||||
if (oldLight < newLight)
|
||||
initialBrightenings.enqueue(((long) newLight << S_L) | currentData); // Don't enqueue directly for brightening to avoid duplicate scheduling
|
||||
else if (oldLight > newLight)
|
||||
initialDarkenings.enqueue(currentData); // Don't enqueue directly for darkening to avoid duplicate scheduling
|
||||
}
|
||||
|
||||
profiler.endStartSection("enqueueBrightening");
|
||||
|
||||
currentQueue = initialBrightenings;
|
||||
|
||||
if (currentQueue != null)
|
||||
currentQueue.clearSet();
|
||||
|
||||
while (nextItem()) {
|
||||
final byte newLight = (byte) (currentData >> S_L & M_L);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
profiler.endStartSection("enqueueDarkening");
|
||||
|
||||
currentQueue = initialDarkenings;
|
||||
|
||||
if (currentQueue != null)
|
||||
currentQueue.clearSet();
|
||||
|
||||
while (nextItem()) {
|
||||
final byte oldLight = getCursorCachedLight(lightType);
|
||||
|
||||
if (oldLight != 0)
|
||||
enqueueDarkening(currentPos, currentData, oldLight, currentChunk, lightType); // Sets the light to zero to only schedule once
|
||||
}
|
||||
|
||||
profiler.endStartSection("process");
|
||||
|
||||
// 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) {
|
||||
currentQueue = darkeningQueues[currentLight];
|
||||
|
||||
if (currentQueue != null)
|
||||
currentQueue.clearSet();
|
||||
|
||||
while (nextItem()) {
|
||||
// Don't darken if we got brighter due to some other change
|
||||
if (getCursorCachedLight(lightType) >= currentLight)
|
||||
continue;
|
||||
|
||||
final IBlockState blockState = currentChunk.getBlockState(currentPos);
|
||||
final byte luminosity = getCursorLuminosity(blockState, lightType);
|
||||
final byte opacity; // If luminosity is high enough, opacity is irrelevant
|
||||
|
||||
if (luminosity >= MAX_LIGHT_LEVEL - 1)
|
||||
opacity = 1;
|
||||
else
|
||||
opacity = getPosOpacity(currentPos, blockState);
|
||||
|
||||
// Only darken neighbors if we indeed became darker
|
||||
if (calculateNewLightFromCursor(luminosity, opacity, lightType) < currentLight) {
|
||||
// Need to calculate new light value from neighbors IGNORING neighbors which are scheduled for darkening
|
||||
byte newLight = luminosity;
|
||||
|
||||
fetchNeighborDataFromCursor(lightType);
|
||||
|
||||
for (final NeighborInfo neighborInfo : neighborInfos) {
|
||||
final Chunk neighborChunk = neighborInfo.chunk;
|
||||
|
||||
if (neighborChunk == null)
|
||||
continue;
|
||||
|
||||
final byte neighborLight = neighborInfo.light;
|
||||
|
||||
if (neighborLight == 0)
|
||||
continue;
|
||||
|
||||
final MutableBlockPos neighborPos = neighborInfo.mutableBlockPos;
|
||||
|
||||
if (currentLight - getPosOpacity(neighborPos, neighborChunk.getBlockState(neighborPos)) >= neighborLight) /*Schedule neighbor for darkening if we possibly light it*/ {
|
||||
enqueueDarkening(neighborPos, neighborInfo.key, neighborLight, neighborChunk, lightType);
|
||||
} 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
|
||||
newLight = (byte) Math.max(newLight, neighborLight - opacity);
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule brightening since light level was set to 0
|
||||
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*/ {
|
||||
enqueueBrighteningFromCursor(currentLight, lightType); // Do not spread to neighbors immediately to avoid scheduling multiple times
|
||||
}
|
||||
}
|
||||
|
||||
currentQueue = brighteningQueues[currentLight];
|
||||
|
||||
if (currentQueue != null)
|
||||
currentQueue.clearSet();
|
||||
|
||||
while (nextItem()) {
|
||||
final byte oldLight = getCursorCachedLight(lightType);
|
||||
|
||||
// Only process this if nothing else has happened at this position since scheduling
|
||||
if (oldLight == currentLight) {
|
||||
world.notifyLightSet(currentPos);
|
||||
|
||||
if (currentLight > 1)
|
||||
spreadLightFromCursor(currentLight, lightType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
profiler.endSection();
|
||||
|
||||
updating = false;
|
||||
}
|
||||
|
||||
private void fetchNeighborDataFromCursor(final EnumSkyBlock lightType) {
|
||||
// Only update if curPos was changed
|
||||
if (isNeighborDataValid)
|
||||
return;
|
||||
|
||||
isNeighborDataValid = true;
|
||||
|
||||
for (int i = 0; i < neighborInfos.length; ++i) {
|
||||
final NeighborInfo neighborInfo = neighborInfos[i];
|
||||
final long neighborLongPos = neighborInfo.key = currentData + neighborShifts[i];
|
||||
|
||||
if ((neighborLongPos & Y_CHECK) != 0) {
|
||||
neighborInfo.chunk = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
final MutableBlockPos neighborPos = decodeWorldCoord(neighborInfo.mutableBlockPos, neighborLongPos);
|
||||
|
||||
final Chunk neighborChunk;
|
||||
|
||||
if ((neighborLongPos & M_CHUNK) == currentChunkIdentifier)
|
||||
neighborChunk = neighborInfo.chunk = currentChunk;
|
||||
else
|
||||
neighborChunk = neighborInfo.chunk = getChunk(neighborPos);
|
||||
|
||||
if (neighborChunk != null) {
|
||||
final ExtendedBlockStorage neighborSection = neighborChunk.getBlockStorageArray()[neighborPos.getY() >> 4];
|
||||
|
||||
neighborInfo.light = getCachedLightFor(neighborChunk, neighborSection, neighborPos, lightType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte getCachedLightFor(final Chunk chunk, final ExtendedBlockStorage storage, final BlockPos blockPos, final EnumSkyBlock type) {
|
||||
final int x = blockPos.getX() & 15;
|
||||
final int y = blockPos.getY();
|
||||
final int z = blockPos.getZ() & 15;
|
||||
|
||||
if (storage == Chunk.NULL_BLOCK_STORAGE)
|
||||
return type == EnumSkyBlock.SKY && chunk.canSeeSky(blockPos) ? (byte) type.defaultLightValue : 0;
|
||||
else if (type == EnumSkyBlock.SKY)
|
||||
return !chunk.getWorld().provider.getHasNoSky() ? (byte) storage.getExtSkylightValue(x, y & 15, z) : 0;
|
||||
else
|
||||
return type == EnumSkyBlock.BLOCK ? (byte) storage.getExtBlocklightValue(x, y & 15, z) : (byte) type.defaultLightValue;
|
||||
}
|
||||
|
||||
private byte calculateNewLightFromCursor(final EnumSkyBlock lightType) {
|
||||
final IBlockState blockState = currentChunk.getBlockState(currentPos);
|
||||
|
||||
final byte luminosity = getCursorLuminosity(blockState, lightType);
|
||||
final byte opacity;
|
||||
|
||||
if (luminosity >= MAX_LIGHT_LEVEL - 1)
|
||||
opacity = 1;
|
||||
else
|
||||
opacity = getPosOpacity(currentPos, blockState);
|
||||
|
||||
return calculateNewLightFromCursor(luminosity, opacity, lightType);
|
||||
}
|
||||
|
||||
private byte calculateNewLightFromCursor(final byte luminosity, final byte opacity, final EnumSkyBlock lightType) {
|
||||
if (luminosity >= MAX_LIGHT_LEVEL - opacity)
|
||||
return luminosity;
|
||||
|
||||
byte newLight = luminosity;
|
||||
|
||||
fetchNeighborDataFromCursor(lightType);
|
||||
|
||||
for (final NeighborInfo neighborInfo : neighborInfos) {
|
||||
if (neighborInfo.chunk == null)
|
||||
continue;
|
||||
|
||||
newLight = (byte) Math.max(neighborInfo.light - opacity, newLight);
|
||||
}
|
||||
|
||||
return newLight;
|
||||
}
|
||||
|
||||
private void spreadLightFromCursor(final byte currentLight, final EnumSkyBlock lightType) {
|
||||
fetchNeighborDataFromCursor(lightType);
|
||||
|
||||
for (final NeighborInfo neighborInfo : neighborInfos) {
|
||||
final Chunk neighborChunk = neighborInfo.chunk;
|
||||
|
||||
if (neighborChunk == null || currentLight < neighborInfo.light)
|
||||
continue;
|
||||
|
||||
final BlockPos neighborBlockPos = neighborInfo.mutableBlockPos;
|
||||
|
||||
final byte newLight = (byte) (currentLight - getPosOpacity(neighborBlockPos, neighborChunk.getBlockState(neighborBlockPos)));
|
||||
|
||||
if (newLight > neighborInfo.light)
|
||||
enqueueBrightening(neighborBlockPos, neighborInfo.key, newLight, neighborChunk, lightType);
|
||||
}
|
||||
}
|
||||
|
||||
private void enqueueBrighteningFromCursor(final byte newLight, final EnumSkyBlock 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) {
|
||||
brighteningQueues[newLight].enqueue(longPos);
|
||||
|
||||
chunk.setLightFor(lightType, blockPos, newLight);
|
||||
}
|
||||
|
||||
private void enqueueDarkening(final BlockPos blockPos, final long longPos, final byte oldLight, final Chunk chunk, final EnumSkyBlock lightType) {
|
||||
darkeningQueues[oldLight].enqueue(longPos);
|
||||
|
||||
chunk.setLightFor(lightType, blockPos, 0);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private boolean nextItem() {
|
||||
if (currentQueue.isEmpty()) {
|
||||
currentQueue = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
currentData = currentQueue.dequeue();
|
||||
isNeighborDataValid = false;
|
||||
|
||||
decodeWorldCoord(currentPos, currentData);
|
||||
|
||||
final long chunkIdentifier = currentData & M_CHUNK;
|
||||
|
||||
if (currentChunkIdentifier != chunkIdentifier) {
|
||||
currentChunk = getChunk(currentPos);
|
||||
currentChunkIdentifier = chunkIdentifier;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private byte getCursorCachedLight(final EnumSkyBlock lightType) {
|
||||
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
|
||||
}
|
||||
|
||||
private byte getCursorLuminosity(final IBlockState state, final EnumSkyBlock lightType) {
|
||||
if (lightType == EnumSkyBlock.SKY) {
|
||||
if (currentChunk.canSeeSky(currentPos))
|
||||
return (byte) EnumSkyBlock.SKY.defaultLightValue;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (byte) ClampUtil.clampMinFirst(LightUtil.getLightValueForState(state, world, currentPos), 0, MAX_LIGHT_LEVEL);
|
||||
}
|
||||
|
||||
private byte getPosOpacity(final BlockPos blockPos, final IBlockState blockState) {
|
||||
return (byte) ClampUtil.clampMinFirst(blockState.getBlock().getLightOpacity(), 1, MAX_LIGHT_LEVEL);
|
||||
}
|
||||
|
||||
private Chunk getChunk(final BlockPos blockPos) {
|
||||
return world.getChunkProvider().getLoadedChunk(blockPos.getX() >> 4, blockPos.getZ() >> 4);
|
||||
}
|
||||
|
||||
|
||||
private static final class NeighborInfo {
|
||||
|
||||
public final MutableBlockPos mutableBlockPos = new MutableBlockPos();
|
||||
|
||||
public Chunk chunk;
|
||||
|
||||
public byte light;
|
||||
|
||||
public long key;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,343 @@
|
|||
package net.hoosiertransfer.Alfheim.util;
|
||||
|
||||
/**
|
||||
* A utility class that offers efficient clamping methods.
|
||||
* <p>
|
||||
* These functions are optimized for speed and provided for every primitive datatype.
|
||||
*
|
||||
* @author Luna Lage (Desoroxxx)
|
||||
* @since 0.5
|
||||
*/
|
||||
@SuppressWarnings({"unused", "ManualMinMaxCalculation", "DuplicatedCode"})
|
||||
public final class ClampUtil {
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
* <p>
|
||||
* This will log the result to check if clampMinFirst or clampMaxFirst should be used.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static byte clampTest(final byte input, final byte min, final byte max) {
|
||||
if (input < min) {
|
||||
return min;
|
||||
} else if (input > max) {
|
||||
return max;
|
||||
} else {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
* <p>
|
||||
* This will log the result to check if clampMinFirst or clampMaxFirst should be used.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static short clampTest(final short input, final short min, final short max) {
|
||||
if (input < min) {
|
||||
return min;
|
||||
} else if (input > max) {
|
||||
return max;
|
||||
} else {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
* <p>
|
||||
* This will log the result to check if clampMinFirst or clampMaxFirst should be used.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static int clampTest(final int input, final int min, final int max) {
|
||||
if (input < min) {
|
||||
return min;
|
||||
} else if (input > max) {
|
||||
return max;
|
||||
} else {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
* <p>
|
||||
* This will log the result to check if clampMinFirst or clampMaxFirst should be used.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static long clampTest(final long input, final long min, final long max) {
|
||||
if (input < min) {
|
||||
return min;
|
||||
} else if (input > max) {
|
||||
return max;
|
||||
} else {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
* <p>
|
||||
* This will log the result to check if clampMinFirst or clampMaxFirst should be used.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static float clampTest(final float input, final float min, final float max) {
|
||||
if (input < min) {
|
||||
return min;
|
||||
} else if (input > max) {
|
||||
return max;
|
||||
} else {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
* <p>
|
||||
* This will log the result to check if clampMinFirst or clampMaxFirst should be used.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static double clampTest(final double input, final double min, final double max) {
|
||||
if (input < min) {
|
||||
return min;
|
||||
} else if (input > max) {
|
||||
return max;
|
||||
} else {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the minimum value first.
|
||||
* <p>
|
||||
* If the input is less than min, it returns min. If the input is greater than max, it returns max.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static byte clampMinFirst(final byte input, final byte min, final byte max) {
|
||||
return input < min ? min : input > max ? max : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the minimum value first.
|
||||
* <p>
|
||||
* If the input is less than min, it returns min. If the input is greater than max, it returns max.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static short clampMinFirst(final short input, final short min, final short max) {
|
||||
return input < min ? min : input > max ? max : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the minimum value first.
|
||||
* <p>
|
||||
* If the input is less than min, it returns min. If the input is greater than max, it returns max.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static int clampMinFirst(final int input, final int min, final int max) {
|
||||
return input < min ? min : input > max ? max : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the minimum value first.
|
||||
* <p>
|
||||
* If the input is less than min, it returns min. If the input is greater than max, it returns max.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static long clampMinFirst(final long input, final long min, final long max) {
|
||||
return input < min ? min : input > max ? max : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the minimum value first.
|
||||
* <p>
|
||||
* If the input is less than min, it returns min. If the input is greater than max, it returns max.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static float clampMinFirst(final float input, final float min, final float max) {
|
||||
return input < min ? min : input > max ? max : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the minimum value first.
|
||||
* <p>
|
||||
* If the input is less than min, it returns min. If the input is greater than max, it returns max.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static double clampMinFirst(final double input, final double min, final double max) {
|
||||
return input < min ? min : input > max ? max : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static byte clampMaxFirst(final byte input, final byte min, final byte max) {
|
||||
return input > max ? max : input < min ? min : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static short clampMaxFirst(final short input, final short min, final short max) {
|
||||
return input > max ? max : input < min ? min : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static int clampMaxFirst(final int input, final int min, final int max) {
|
||||
return input > max ? max : input < min ? min : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static long clampMaxFirst(final long input, final long min, final long max) {
|
||||
return input > max ? max : input < min ? min : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static float clampMaxFirst(final float input, final float min, final float max) {
|
||||
return input > max ? max : input < min ? min : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps a value within a specified range [min, max], checking for the maximum value first.
|
||||
* <p>
|
||||
* If the input is greater than max, it returns max. If the input is less than min, it returns min.
|
||||
* Otherwise, it returns the input.
|
||||
*
|
||||
* @param input The input value to clamp
|
||||
* @param min The minimum value to clamp to
|
||||
* @param max The maximum value to clamp to
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static double clampMaxFirst(final double input, final double min, final double max) {
|
||||
return input > max ? max : input < min ? min : input;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package net.hoosiertransfer.Alfheim.util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* A queue implementation for long values that are deduplicated on addition.
|
||||
* <p>
|
||||
* This is achieved by storing the values in a HashSet and a LinkedList.
|
||||
*/
|
||||
public final class DeduplicatedLongQueue {
|
||||
|
||||
private final HashSet<Long> set;
|
||||
private final LinkedList<Long> queue;
|
||||
|
||||
/**
|
||||
* Creates a new deduplicated queue with the given capacity.
|
||||
*
|
||||
* @param capacity The capacity of the deduplicated queue
|
||||
*/
|
||||
public DeduplicatedLongQueue(final int capacity) {
|
||||
set = new HashSet<>(capacity);
|
||||
queue = new LinkedList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the queue.
|
||||
*
|
||||
* @param value The value to add to the queue
|
||||
*/
|
||||
public void enqueue(final long value) {
|
||||
if (set.add(value))
|
||||
queue.addLast(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the first value in the queue.
|
||||
*
|
||||
* @return The first value in the queue
|
||||
*/
|
||||
public long dequeue() {
|
||||
Long value = queue.removeFirst();
|
||||
return value != null ? value : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the queue is empty.
|
||||
*
|
||||
* @return {@code true} if the queue is empty, {@code false} otherwise
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return queue.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the deduplication set.
|
||||
*/
|
||||
public void clearSet() {
|
||||
set.clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package net.hoosiertransfer.Alfheim.util;
|
||||
|
||||
public enum EnumBoundaryFacing {
|
||||
IN,
|
||||
OUT
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package net.hoosiertransfer.Alfheim.util;
|
||||
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
|
||||
/**
|
||||
* Represents a slice of a world containing a collection of chunks.
|
||||
*
|
||||
* @author Luna Lage (Desoroxxx)
|
||||
* @author Angeline (@jellysquid)
|
||||
* @since 1.0
|
||||
*/
|
||||
public class WorldChunkSlice {
|
||||
|
||||
private static final int DIAMETER = 5;
|
||||
private static final int RADIUS = DIAMETER / 2;
|
||||
|
||||
private final int x, z;
|
||||
|
||||
private final Chunk[] chunks;
|
||||
|
||||
/**
|
||||
* Initializes a {@link WorldChunkSlice} object using a given chunk provider and coordinates.
|
||||
*
|
||||
* @param chunkProvider The chunk provider to get chunks from
|
||||
* @param x The X-coordinate of the center chunk
|
||||
* @param z The Z-coordinate of the center chunk
|
||||
*/
|
||||
public WorldChunkSlice(final IChunkProvider chunkProvider, final int x, final int z) {
|
||||
chunks = new Chunk[DIAMETER * DIAMETER];
|
||||
|
||||
for (int xDiff = -RADIUS; xDiff <= RADIUS; xDiff++)
|
||||
for (int zDiff = -RADIUS; zDiff <= RADIUS; zDiff++)
|
||||
chunks[((xDiff + RADIUS) * DIAMETER) + (zDiff + RADIUS)] = chunkProvider.getLoadedChunk(x + xDiff, z + zDiff);
|
||||
|
||||
this.x = x - RADIUS;
|
||||
this.z = z - RADIUS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all chunks within a radius around a coordinate are loaded.
|
||||
*
|
||||
* @param x The X-coordinate to check around
|
||||
* @param z The Z-coordinate to check around
|
||||
* @param radius The radius around the coordinates to check
|
||||
* @return true if all chunks are loaded, false otherwise
|
||||
*/
|
||||
public boolean isLoaded(final int x, final int z, final int radius) {
|
||||
final int xStart = ((x - radius) >> 4) - this.x;
|
||||
final int zStart = ((z - radius) >> 4) - this.z;
|
||||
final int xEnd = ((x + radius) >> 4) - this.x;
|
||||
final int zEnd = ((z + radius) >> 4) - this.z;
|
||||
|
||||
for (int currentX = xStart; currentX <= xEnd; ++currentX)
|
||||
for (int currentZ = zStart; currentZ <= zEnd; ++currentZ)
|
||||
if (getChunk(currentX, currentZ) == null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the chunk that includes the provided world coordinates.
|
||||
*
|
||||
* @param x The X-coordinate in the world
|
||||
* @param z The Z-coordinate in the world
|
||||
* @return The Chunk object that includes these coordinates
|
||||
*/
|
||||
public Chunk getChunkFromWorldCoords(final int x, final int z) {
|
||||
return getChunk((x >> 4) - this.x, (z >> 4) - this.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the chunk located at the given coordinates within this chunk slice.
|
||||
*
|
||||
* @param x The X-coordinate within the slice
|
||||
* @param z The Z-coordinate within the slice
|
||||
* @return The Chunk object at these coordinates
|
||||
*/
|
||||
private Chunk getChunk(final int x, final int z) {
|
||||
return chunks[(x * DIAMETER) + z];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package net.hoosiertransfer.teavm;
|
||||
|
||||
public class ReentrantLock {
|
||||
private Thread owner = null;
|
||||
private int lockCount = 0;
|
||||
|
||||
public synchronized void lock() {
|
||||
Thread callingThread = Thread.currentThread();
|
||||
while (lockCount > 0 && owner != callingThread) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
// Handle exception
|
||||
}
|
||||
}
|
||||
owner = callingThread;
|
||||
lockCount++;
|
||||
}
|
||||
|
||||
public synchronized void unlock() {
|
||||
if (Thread.currentThread() == owner) {
|
||||
lockCount--;
|
||||
if (lockCount == 0) {
|
||||
owner = null;
|
||||
notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean isHeldByCurrentThread() {
|
||||
return owner == Thread.currentThread();
|
||||
}
|
||||
|
||||
public synchronized boolean tryLock() {
|
||||
Thread callingThread = Thread.currentThread();
|
||||
if (lockCount == 0 || owner == callingThread) {
|
||||
owner = callingThread;
|
||||
lockCount++;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.ILightingEngineProvider;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
@ -89,6 +90,7 @@ public class EaglerChunkLoader extends AnvilChunkLoader {
|
|||
|
||||
@Override
|
||||
public void saveChunk(World var1, Chunk var2) throws IOException, MinecraftException {
|
||||
var1.alfheim$getLightingEngine().processLightUpdates();
|
||||
NBTTagCompound chunkData = new NBTTagCompound();
|
||||
this.writeChunkToNBT(var2, var1, chunkData);
|
||||
NBTTagCompound fileData = new NBTTagCompound();
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package net.minecraft.block;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.ILightInfoProvider;
|
||||
import net.hoosiertransfer.Alfheim.ILightLevelProvider;
|
||||
import net.hoosiertransfer.Alfheim.ILitBlock;
|
||||
import net.hoosiertransfer.Alfheim.util.ClampUtil;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
|
||||
|
||||
import net.minecraft.block.material.MapColor;
|
||||
|
@ -30,6 +35,7 @@ import net.minecraft.util.RegistryNamespacedDefaultedByKey;
|
|||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.StatCollector;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
import net.minecraft.world.Explosion;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -54,7 +60,7 @@ import net.minecraft.world.World;
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class Block {
|
||||
public class Block implements ILitBlock {
|
||||
/**+
|
||||
* ResourceLocation for the Air block
|
||||
*/
|
||||
|
@ -978,7 +984,13 @@ public class Block {
|
|||
* opacity
|
||||
*/
|
||||
public float getAmbientOcclusionLightValue() {
|
||||
return this.isBlockNormalCube() ? 0.2F : 1.0F;
|
||||
final byte lightValue = (byte) ClampUtil.clampMinFirst(this.getLightValue() - 1, 0, 15);
|
||||
|
||||
if (lightValue == 0) {
|
||||
return this.isBlockNormalCube() ? 0.2F : 1.0F;
|
||||
} else {
|
||||
return 1.0F;
|
||||
}
|
||||
}
|
||||
|
||||
/**+
|
||||
|
@ -1660,4 +1672,40 @@ public class Block {
|
|||
public boolean eaglerShadersShouldRenderGlassHighlights() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int alfheim$getLightFor(final IBlockState blockState, final IBlockAccess blockAccess, final EnumSkyBlock lightType, final BlockPos blockPos) {
|
||||
int lightLevel = ((ILightLevelProvider) blockAccess).alfheim$getLight(lightType, blockPos);
|
||||
|
||||
if (lightLevel == 15)
|
||||
return lightLevel;
|
||||
|
||||
if (!blockState.getBlock().getUseNeighborBrightness())
|
||||
return lightLevel;
|
||||
|
||||
for (EnumFacing facing : EnumFacing._VALUES) {
|
||||
if (((ILightInfoProvider) blockState).alfheim$useNeighborBrightness(facing, blockAccess, blockPos)) {
|
||||
int opacity = ((ILightInfoProvider) blockState).alfheim$getLightOpacity(facing, blockAccess, blockPos);
|
||||
final int neighborLightLevel = ((ILightLevelProvider) blockAccess).alfheim$getLight(lightType, blockPos.offset(facing));
|
||||
|
||||
if (opacity == 0 && (lightType != EnumSkyBlock.SKY || neighborLightLevel != EnumSkyBlock.SKY.defaultLightValue))
|
||||
opacity = 1;
|
||||
|
||||
lightLevel = Math.max(lightLevel, neighborLightLevel - opacity);
|
||||
|
||||
if (lightLevel == 15)
|
||||
return lightLevel;
|
||||
}
|
||||
}
|
||||
|
||||
return lightLevel;
|
||||
}
|
||||
|
||||
public boolean alfheim$useNeighborBrightness(final IBlockState blockState, final EnumFacing facing, final IBlockAccess blockAccess, final BlockPos blockPos) {
|
||||
return facing == EnumFacing.UP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int alfheim$getLightOpacity(final IBlockState blockState, final EnumFacing facing, final IBlockAccess blockAccess, final BlockPos blockPos) {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package net.minecraft.block;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.ILitBlock;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
|
||||
|
||||
import net.minecraft.block.material.Material;
|
||||
|
@ -21,6 +23,9 @@ import net.minecraft.util.IStringSerializable;
|
|||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import static net.minecraft.block.BlockSlab.EnumBlockHalf.TOP;
|
||||
|
||||
|
||||
/**+
|
||||
* This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code.
|
||||
*
|
||||
|
@ -41,7 +46,7 @@ import net.minecraft.world.World;
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public abstract class BlockSlab extends Block {
|
||||
public abstract class BlockSlab extends Block {
|
||||
public static PropertyEnum<BlockSlab.EnumBlockHalf> HALF;
|
||||
|
||||
public BlockSlab(Material materialIn) {
|
||||
|
@ -204,4 +209,14 @@ public abstract class BlockSlab extends Block {
|
|||
}
|
||||
return super.onBlockActivated(world, blockpos, var3, entityplayer, var5, var6, var7, var8);
|
||||
}
|
||||
|
||||
public boolean alfheim$useNeighborBrightness(final IBlockState blockState, final EnumFacing facing, final IBlockAccess blockAccess, final BlockPos blockPos) {
|
||||
if (facing.getAxis() != EnumFacing.Axis.Y)
|
||||
return false;
|
||||
|
||||
if (((BlockSlab) (Object) blockState.getBlock()).isFullCube())
|
||||
return false;
|
||||
|
||||
return facing == (blockState.getValue(HALF) == TOP ? EnumFacing.DOWN : EnumFacing.UP);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,8 @@ import net.minecraft.world.Explosion;
|
|||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import static net.minecraft.block.BlockStairs.EnumHalf.TOP;
|
||||
|
||||
/**+
|
||||
* This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code.
|
||||
*
|
||||
|
@ -704,4 +706,11 @@ public class BlockStairs extends Block {
|
|||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean alfheim$useNeighborBrightness(final IBlockState blockState, final EnumFacing facing, final IBlockAccess blockAccess, final BlockPos blockPos) {
|
||||
if (facing.getAxis() != EnumFacing.Axis.Y)
|
||||
return false;
|
||||
|
||||
return facing == (blockState.getValue(HALF) == TOP ? EnumFacing.DOWN : EnumFacing.UP);
|
||||
}
|
||||
}
|
|
@ -21,10 +21,16 @@ import com.google.common.collect.Iterables;
|
|||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.ILightInfoProvider;
|
||||
import net.hoosiertransfer.Alfheim.ILitBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.properties.IProperty;
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.util.Cartesian;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.MapPopulator;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
/**+
|
||||
* This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code.
|
||||
|
@ -46,7 +52,7 @@ import net.minecraft.util.MapPopulator;
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class BlockState {
|
||||
public class BlockState implements ILightInfoProvider {
|
||||
private static final Joiner COMMA_JOINER = Joiner.on(", ");
|
||||
private static final Function<IProperty, String> GET_NAME_FUNC = new Function<IProperty, String>() {
|
||||
public String apply(IProperty iproperty) {
|
||||
|
@ -114,7 +120,20 @@ public class BlockState {
|
|||
.add("properties", Iterables.transform(this.properties, GET_NAME_FUNC)).toString();
|
||||
}
|
||||
|
||||
static class StateImplementation extends BlockStateBase {
|
||||
public int alfheim$getLightFor(IBlockAccess iBlockAccess, EnumSkyBlock lightType, BlockPos blockPos) {
|
||||
return ((ILitBlock) block).alfheim$getLightFor(((IBlockState) this), iBlockAccess, lightType, blockPos); // i probably need to cast the StateImplementation to IBlockState instead of this
|
||||
}
|
||||
|
||||
|
||||
public boolean alfheim$useNeighborBrightness(EnumFacing facing, IBlockAccess blockAccess, BlockPos blockPos) {
|
||||
return ((ILitBlock) block).alfheim$useNeighborBrightness(((IBlockState) this), facing, blockAccess, blockPos); // i probably need to cast the StateImplementation to IBlockState instead of this
|
||||
}
|
||||
|
||||
public int alfheim$getLightOpacity(EnumFacing facing, IBlockAccess blockAccess, BlockPos blockPos) {
|
||||
return ((ILitBlock) block).alfheim$getLightOpacity(((IBlockState) this), facing, blockAccess, blockPos); // i probably need to cast the StateImplementation to IBlockState instead of this
|
||||
}
|
||||
|
||||
static class StateImplementation extends BlockStateBase implements ILightInfoProvider {
|
||||
private final Block block;
|
||||
private final ImmutableMap<IProperty, Comparable> properties;
|
||||
private ImmutableTable<IProperty, Comparable, IBlockState> propertyValueTable;
|
||||
|
@ -186,10 +205,26 @@ public class BlockState {
|
|||
}
|
||||
}
|
||||
|
||||
public int getLightValue(IBlockAccess blockAccess, BlockPos pos) {
|
||||
return this.block.getLightValue();
|
||||
}
|
||||
|
||||
private Map<IProperty, Comparable> getPropertiesWithValue(IProperty property, Comparable value) {
|
||||
HashMap hashmap = Maps.newHashMap(this.properties);
|
||||
hashmap.put(property, value);
|
||||
return hashmap;
|
||||
}
|
||||
|
||||
public int alfheim$getLightFor(IBlockAccess iBlockAccess, EnumSkyBlock lightType, BlockPos blockPos) {
|
||||
return ((ILitBlock) block).alfheim$getLightFor(((IBlockState) this), iBlockAccess, lightType, blockPos);
|
||||
}
|
||||
|
||||
public boolean alfheim$useNeighborBrightness(EnumFacing facing, IBlockAccess blockAccess, BlockPos blockPos) {
|
||||
return ((ILitBlock) block).alfheim$useNeighborBrightness(((IBlockState) this), facing, blockAccess, blockPos);
|
||||
}
|
||||
|
||||
public int alfheim$getLightOpacity(EnumFacing facing, IBlockAccess blockAccess, BlockPos blockPos) {
|
||||
return ((ILitBlock) block).alfheim$getLightOpacity(((IBlockState) this), facing, blockAccess, blockPos);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,8 @@ import com.google.common.collect.ImmutableMap;
|
|||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.properties.IProperty;
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
/**+
|
||||
* This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code.
|
||||
|
@ -42,4 +44,6 @@ public interface IBlockState {
|
|||
ImmutableMap<IProperty, Comparable> getProperties();
|
||||
|
||||
Block getBlock();
|
||||
|
||||
int getLightValue(IBlockAccess blockAccess, BlockPos pos);
|
||||
}
|
|
@ -20,6 +20,7 @@ import org.apache.commons.lang3.Validate;
|
|||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.hoosiertransfer.CullingMod;
|
||||
import net.hoosiertransfer.Alfheim.ILightUpdatesProcessor;
|
||||
import net.lax1dude.eaglercraft.v1_8.Display;
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglerXBungeeVersion;
|
||||
|
@ -328,6 +329,10 @@ public class Minecraft implements IThreadListener {
|
|||
Bootstrap.register();
|
||||
}
|
||||
|
||||
public boolean isCallingFromMinecraftThread() {
|
||||
return Thread.currentThread() == this.mcThread;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
CullingMod.intialize();
|
||||
this.running = true;
|
||||
|
@ -1616,6 +1621,9 @@ public class Minecraft implements IThreadListener {
|
|||
if (!this.isGamePaused) {
|
||||
this.renderGlobal.updateClouds();
|
||||
}
|
||||
this.mcProfiler.endStartSection("processRenderGlobalLightUpdates");
|
||||
if (!isGamePaused)
|
||||
((ILightUpdatesProcessor) renderGlobal).alfheim$processLightUpdates();
|
||||
|
||||
this.mcProfiler.endStartSection("level");
|
||||
if (!this.isGamePaused) {
|
||||
|
|
|
@ -102,6 +102,10 @@ public class ChunkProviderClient implements IChunkProvider {
|
|||
return chunk == null ? this.blankChunk : chunk;
|
||||
}
|
||||
|
||||
public Chunk getLoadedChunk(int var1, int var2) {
|
||||
return (Chunk) this.chunkMapping.getValueByKey(ChunkCoordIntPair.chunkXZ2Int(var1, var2));
|
||||
}
|
||||
|
||||
/**+
|
||||
* Two modes of operation: if passed true, save all Chunks in
|
||||
* one go. If passed false, save up to two chunks. Return true
|
||||
|
|
|
@ -3,6 +3,7 @@ package net.minecraft.client.renderer;
|
|||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.util.ClampUtil;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer;
|
||||
import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.DeferredStateManager;
|
||||
|
@ -53,7 +54,7 @@ public class BlockModelRenderer {
|
|||
|
||||
public boolean renderModel(IBlockAccess blockAccessIn, IBakedModel modelIn, IBlockState blockStateIn,
|
||||
BlockPos blockPosIn, WorldRenderer worldRendererIn, boolean checkSides) {
|
||||
boolean flag = Minecraft.isAmbientOcclusionEnabled() && blockStateIn.getBlock().getLightValue() == 0
|
||||
boolean flag = Minecraft.isAmbientOcclusionEnabled() && ClampUtil.clampMinFirst(blockStateIn.getLightValue(blockAccessIn, blockPosIn) -1, 0, 15) == 0
|
||||
&& modelIn.isAmbientOcclusion();
|
||||
|
||||
try {
|
||||
|
|
|
@ -8,6 +8,8 @@ import java.util.Iterator;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.ILightUpdatesProcessor;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
|
||||
import net.lax1dude.eaglercraft.v1_8.HString;
|
||||
import net.lax1dude.eaglercraft.v1_8.Keyboard;
|
||||
|
@ -115,7 +117,7 @@ import net.minecraft.world.chunk.Chunk;
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class RenderGlobal implements IWorldAccess, IResourceManagerReloadListener {
|
||||
public class RenderGlobal implements IWorldAccess, IResourceManagerReloadListener, ILightUpdatesProcessor {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
private static final ResourceLocation locationMoonPhasesPng = new ResourceLocation(
|
||||
"textures/environment/moon_phases.png");
|
||||
|
@ -182,6 +184,8 @@ public class RenderGlobal implements IWorldAccess, IResourceManagerReloadListene
|
|||
private double prevRenderSortZ;
|
||||
private boolean displayListEntitiesDirty = true;
|
||||
|
||||
private final Set<BlockPos> setLightUpdates = Sets.<BlockPos>newHashSet();
|
||||
|
||||
public RenderGlobal(Minecraft mcIn) {
|
||||
this.mc = mcIn;
|
||||
this.renderManager = mcIn.getRenderManager();
|
||||
|
@ -2108,6 +2112,7 @@ public class RenderGlobal implements IWorldAccess, IResourceManagerReloadListene
|
|||
}
|
||||
|
||||
public void notifyLightSet(BlockPos blockpos) {
|
||||
this.setLightUpdates.add(blockpos.toImmutable());
|
||||
int i = blockpos.getX();
|
||||
int j = blockpos.getY();
|
||||
int k = blockpos.getZ();
|
||||
|
@ -2514,4 +2519,33 @@ public class RenderGlobal implements IWorldAccess, IResourceManagerReloadListene
|
|||
return "" + Minecraft.getDebugFPS() + "fps | C: " + j + "/" + i + ", E: " + this.countEntitiesRendered + "+" + k
|
||||
+ ", " + renderDispatcher.getDebugInfo();
|
||||
}
|
||||
|
||||
public void alfheim$processLightUpdates() {
|
||||
if (setLightUpdates.isEmpty())
|
||||
return;
|
||||
|
||||
final Iterator<BlockPos> iterator = setLightUpdates.iterator();
|
||||
final float lightUpdateLimit = 2048 + ((float) setLightUpdates.size() / 4); // Todo: Rework this once again, this is currently pretty dumb.
|
||||
// It fixed the issue where the FPS on lower end hardware would plummet for a few seconds.
|
||||
// But it also reduced how smooth the frame rate was on higher end hardware.
|
||||
// Updating blocks is costly and will take a long time, this is why lower end hardware plummets for a few seconds.
|
||||
// Higher end hardware instead has somewhat of a FPS "buffer" which can handle it fine over multiple frames thus reducing frame-time spikes.
|
||||
// The technically the best way to do this (that I hadn't though of before) was to add current "FPS" to the equation.
|
||||
// If the FPS is low more updates would be done in one frame if it is high we can afford spreading light updates over multiple frames.
|
||||
|
||||
short lightUpdatesProcessed = 0;
|
||||
while (iterator.hasNext() && lightUpdatesProcessed < lightUpdateLimit) {
|
||||
final BlockPos blockpos = iterator.next();
|
||||
|
||||
iterator.remove();
|
||||
|
||||
final int x = blockpos.getX();
|
||||
final int y = blockpos.getY();
|
||||
final int z = blockpos.getZ();
|
||||
|
||||
markBlocksForUpdate(x, y, z, x, y, z);
|
||||
|
||||
lightUpdatesProcessed++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -207,7 +207,7 @@ public class GameSettings {
|
|||
|
||||
public boolean enableSound = true;
|
||||
|
||||
public boolean disableAlpha = true;
|
||||
public boolean disableAlpha = false;
|
||||
|
||||
public boolean skipHandRender = false;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.ArrayList;
|
|||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.ILightingEngineProvider;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.network.play.INetHandlerPlayClient;
|
||||
|
@ -44,6 +45,7 @@ public class S21PacketChunkData implements Packet<INetHandlerPlayClient> {
|
|||
this.chunkX = chunkIn.xPosition;
|
||||
this.chunkZ = chunkIn.zPosition;
|
||||
this.field_149279_g = parFlag;
|
||||
chunkIn.alfheim$getLightingEngine().processLightUpdates();
|
||||
this.extractedData = func_179756_a(chunkIn, parFlag, !chunkIn.getWorld().provider.getHasNoSky(), parInt1);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package net.minecraft.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
|
||||
|
@ -317,6 +319,11 @@ public class BlockPos extends Vec3i {
|
|||
return new BlockPos(i, j, k);
|
||||
}
|
||||
|
||||
public BlockPos toImmutable()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/**+
|
||||
* Create an Iterable that returns all positions in the box
|
||||
* specified by the given corners
|
||||
|
@ -409,7 +416,7 @@ public class BlockPos extends Vec3i {
|
|||
};
|
||||
}
|
||||
|
||||
public static final class MutableBlockPos extends BlockPos {
|
||||
public static class MutableBlockPos extends BlockPos {
|
||||
|
||||
public MutableBlockPos() {
|
||||
this(0, 0, 0);
|
||||
|
@ -431,6 +438,36 @@ public class BlockPos extends Vec3i {
|
|||
return this.z;
|
||||
}
|
||||
|
||||
public BlockPos.MutableBlockPos setPos(Entity entityIn)
|
||||
{
|
||||
return this.setPos(entityIn.posX, entityIn.posY, entityIn.posZ);
|
||||
}
|
||||
|
||||
public BlockPos.MutableBlockPos setPos(double xIn, double yIn, double zIn)
|
||||
{
|
||||
return this.setPos(MathHelper.floor_double(xIn), MathHelper.floor_double(yIn), MathHelper.floor_double(zIn));
|
||||
}
|
||||
|
||||
public BlockPos.MutableBlockPos setPos(Vec3i vec)
|
||||
{
|
||||
return this.setPos(vec.getX(), vec.getY(), vec.getZ());
|
||||
}
|
||||
|
||||
public BlockPos.MutableBlockPos move(EnumFacing facing)
|
||||
{
|
||||
return this.move(facing, 1);
|
||||
}
|
||||
|
||||
public BlockPos.MutableBlockPos move(EnumFacing facing, int p_189534_2_)
|
||||
{
|
||||
return this.setPos(this.x + facing.getFrontOffsetX() * p_189534_2_, this.y + facing.getFrontOffsetY() * p_189534_2_, this.z + facing.getFrontOffsetZ() * p_189534_2_);
|
||||
}
|
||||
|
||||
public void setY(int yIn)
|
||||
{
|
||||
this.y = yIn;
|
||||
}
|
||||
|
||||
public BlockPos.MutableBlockPos setPos(int x_, int y_, int z_) {
|
||||
this.x = x_;
|
||||
this.y = y_;
|
||||
|
@ -444,5 +481,104 @@ public class BlockPos extends Vec3i {
|
|||
this.z = parInt3;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockPos toImmutable()
|
||||
{
|
||||
return new BlockPos(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class PooledMutableBlockPos extends BlockPos.MutableBlockPos
|
||||
{
|
||||
private boolean released;
|
||||
private static final List<BlockPos.PooledMutableBlockPos> POOL = Lists.<BlockPos.PooledMutableBlockPos>newArrayList();
|
||||
|
||||
private PooledMutableBlockPos(int xIn, int yIn, int zIn)
|
||||
{
|
||||
super(xIn, yIn, zIn);
|
||||
}
|
||||
|
||||
public static BlockPos.PooledMutableBlockPos retain()
|
||||
{
|
||||
return retain(0, 0, 0);
|
||||
}
|
||||
|
||||
public static BlockPos.PooledMutableBlockPos retain(double xIn, double yIn, double zIn)
|
||||
{
|
||||
return retain(MathHelper.floor_double(xIn), MathHelper.floor_double(yIn), MathHelper.floor_double(zIn));
|
||||
}
|
||||
|
||||
public static BlockPos.PooledMutableBlockPos retain(Vec3i vec)
|
||||
{
|
||||
return retain(vec.getX(), vec.getY(), vec.getZ());
|
||||
}
|
||||
|
||||
public static BlockPos.PooledMutableBlockPos retain(int xIn, int yIn, int zIn)
|
||||
{
|
||||
synchronized (POOL)
|
||||
{
|
||||
if (!POOL.isEmpty())
|
||||
{
|
||||
BlockPos.PooledMutableBlockPos blockpos$pooledmutableblockpos = (BlockPos.PooledMutableBlockPos)POOL.remove(POOL.size() - 1);
|
||||
|
||||
if (blockpos$pooledmutableblockpos != null && blockpos$pooledmutableblockpos.released)
|
||||
{
|
||||
blockpos$pooledmutableblockpos.released = false;
|
||||
blockpos$pooledmutableblockpos.setPos(xIn, yIn, zIn);
|
||||
return blockpos$pooledmutableblockpos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new BlockPos.PooledMutableBlockPos(xIn, yIn, zIn);
|
||||
}
|
||||
|
||||
public void release()
|
||||
{
|
||||
synchronized (POOL)
|
||||
{
|
||||
if (POOL.size() < 100)
|
||||
{
|
||||
POOL.add(this);
|
||||
}
|
||||
|
||||
this.released = true;
|
||||
}
|
||||
}
|
||||
|
||||
public BlockPos.PooledMutableBlockPos setPos(int xIn, int yIn, int zIn)
|
||||
{
|
||||
if (this.released)
|
||||
{
|
||||
this.released = false;
|
||||
}
|
||||
|
||||
return (BlockPos.PooledMutableBlockPos)super.setPos(xIn, yIn, zIn);
|
||||
}
|
||||
|
||||
public BlockPos.PooledMutableBlockPos setPos(Entity entityIn)
|
||||
{
|
||||
return (BlockPos.PooledMutableBlockPos)super.setPos(entityIn);
|
||||
}
|
||||
|
||||
public BlockPos.PooledMutableBlockPos setPos(double xIn, double yIn, double zIn)
|
||||
{
|
||||
return (BlockPos.PooledMutableBlockPos)super.setPos(xIn, yIn, zIn);
|
||||
}
|
||||
|
||||
public BlockPos.PooledMutableBlockPos setPos(Vec3i vec)
|
||||
{
|
||||
return (BlockPos.PooledMutableBlockPos)super.setPos(vec);
|
||||
}
|
||||
|
||||
public BlockPos.PooledMutableBlockPos move(EnumFacing facing)
|
||||
{
|
||||
return (BlockPos.PooledMutableBlockPos)super.move(facing);
|
||||
}
|
||||
|
||||
public BlockPos.PooledMutableBlockPos move(EnumFacing facing, int p_189534_2_)
|
||||
{
|
||||
return (BlockPos.PooledMutableBlockPos)super.move(facing, p_189534_2_);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,7 +52,7 @@ public enum EnumFacing implements IStringSerializable {
|
|||
/**+
|
||||
* All Facings with horizontal axis in order S-W-N-E
|
||||
*/
|
||||
private static final EnumFacing[] HORIZONTALS = new EnumFacing[4];
|
||||
public static final EnumFacing[] HORIZONTALS = new EnumFacing[4];
|
||||
private static final Map<String, EnumFacing> NAME_LOOKUP = Maps.newHashMap();
|
||||
|
||||
private EnumFacing(int indexIn, int oppositeIn, int horizontalIndexIn, String nameIn,
|
||||
|
@ -208,6 +208,18 @@ public enum EnumFacing implements IStringSerializable {
|
|||
}
|
||||
}
|
||||
|
||||
public int getXOffset() {
|
||||
return this.directionVec.getX();
|
||||
}
|
||||
|
||||
public int getYOffset() {
|
||||
return this.directionVec.getY();
|
||||
}
|
||||
|
||||
public int getZOffset() {
|
||||
return this.directionVec.getZ();
|
||||
}
|
||||
|
||||
/**+
|
||||
* Returns a offset that addresses the block in front of this
|
||||
* facing.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package net.minecraft.world;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.ILightInfoProvider;
|
||||
import net.hoosiertransfer.Alfheim.ILightLevelProvider;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
|
@ -29,7 +31,7 @@ import net.minecraft.world.chunk.Chunk;
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public class ChunkCache implements IBlockAccess {
|
||||
public class ChunkCache implements IBlockAccess, ILightLevelProvider {
|
||||
protected int chunkX;
|
||||
protected int chunkZ;
|
||||
protected Chunk[][] chunkArray;
|
||||
|
@ -105,34 +107,35 @@ public class ChunkCache implements IBlockAccess {
|
|||
}
|
||||
|
||||
private int getLightForExt(EnumSkyBlock pos, BlockPos parBlockPos) {
|
||||
if (pos == EnumSkyBlock.SKY && this.worldObj.provider.getHasNoSky()) {
|
||||
return Chunk.getNoSkyLightValue();
|
||||
} else if (parBlockPos.getY() >= 0 && parBlockPos.getY() < 256) {
|
||||
if (this.getBlockState(parBlockPos).getBlock().getUseNeighborBrightness()) {
|
||||
int l = 0;
|
||||
return ((ILightInfoProvider) getBlockState(parBlockPos)).alfheim$getLightFor(((ChunkCache) (Object) this), pos, parBlockPos);
|
||||
// if (pos == EnumSkyBlock.SKY && this.worldObj.provider.getHasNoSky()) {
|
||||
// return Chunk.getNoSkyLightValue();
|
||||
// } else if (parBlockPos.getY() >= 0 && parBlockPos.getY() < 256) {
|
||||
// if (this.getBlockState(parBlockPos).getBlock().getUseNeighborBrightness()) {
|
||||
// int l = 0;
|
||||
|
||||
EnumFacing[] facings = EnumFacing._VALUES;
|
||||
BlockPos tmp = new BlockPos(0, 0, 0);
|
||||
for (int i = 0; i < facings.length; ++i) {
|
||||
int k = this.getLightFor(pos, parBlockPos.offsetEvenFaster(facings[i], tmp));
|
||||
if (k > l) {
|
||||
l = k;
|
||||
}
|
||||
// EnumFacing[] facings = EnumFacing._VALUES;
|
||||
// BlockPos tmp = new BlockPos(0, 0, 0);
|
||||
// for (int i = 0; i < facings.length; ++i) {
|
||||
// int k = this.getLightFor(pos, parBlockPos.offsetEvenFaster(facings[i], tmp));
|
||||
// if (k > l) {
|
||||
// l = k;
|
||||
// }
|
||||
|
||||
if (l >= 15) {
|
||||
return l;
|
||||
}
|
||||
}
|
||||
// if (l >= 15) {
|
||||
// return l;
|
||||
// }
|
||||
// }
|
||||
|
||||
return l;
|
||||
} else {
|
||||
int i = (parBlockPos.getX() >> 4) - this.chunkX;
|
||||
int j = (parBlockPos.getZ() >> 4) - this.chunkZ;
|
||||
return this.chunkArray[i][j].getLightFor(pos, parBlockPos);
|
||||
}
|
||||
} else {
|
||||
return pos.defaultLightValue;
|
||||
}
|
||||
// return l;
|
||||
// } else {
|
||||
// int i = (parBlockPos.getX() >> 4) - this.chunkX;
|
||||
// int j = (parBlockPos.getZ() >> 4) - this.chunkZ;
|
||||
// return this.chunkArray[i][j].getLightFor(pos, parBlockPos);
|
||||
// }
|
||||
// } else {
|
||||
// return pos.defaultLightValue;
|
||||
// }
|
||||
}
|
||||
|
||||
/**+
|
||||
|
@ -163,4 +166,8 @@ public class ChunkCache implements IBlockAccess {
|
|||
public WorldType getWorldType() {
|
||||
return this.worldObj.getWorldType();
|
||||
}
|
||||
|
||||
public int alfheim$getLight(final EnumSkyBlock lightType, final BlockPos blockPos) {
|
||||
return getLightFor(lightType, blockPos);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,10 @@ import java.util.Collection;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.ILightInfoProvider;
|
||||
import net.hoosiertransfer.Alfheim.ILightLevelProvider;
|
||||
import net.hoosiertransfer.Alfheim.ILightingEngineProvider;
|
||||
import net.hoosiertransfer.Alfheim.lighting.LightingEngine;
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
|
||||
import java.util.Set;
|
||||
|
@ -80,7 +84,7 @@ import net.minecraft.world.storage.WorldInfo;
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
public abstract class World implements IBlockAccess {
|
||||
public abstract class World implements IBlockAccess, ILightingEngineProvider, ILightLevelProvider {
|
||||
private int field_181546_a = 63;
|
||||
protected boolean scheduledUpdatesAreImmediate;
|
||||
/**+
|
||||
|
@ -150,6 +154,8 @@ public abstract class World implements IBlockAccess {
|
|||
int[] lightUpdateBlockList;
|
||||
public final boolean isRemote;
|
||||
|
||||
private LightingEngine alfheim$lightingEngine;
|
||||
|
||||
protected World(ISaveHandler saveHandlerIn, WorldInfo info, WorldProvider providerIn, Profiler profilerIn,
|
||||
boolean client) {
|
||||
this.ambientTickCountdown = this.rand.nextInt(12000);
|
||||
|
@ -162,6 +168,8 @@ public abstract class World implements IBlockAccess {
|
|||
this.provider = providerIn;
|
||||
this.worldBorder = providerIn.getWorldBorder();
|
||||
this.isRemote = client;
|
||||
|
||||
alfheim$lightingEngine = new LightingEngine((World) (Object) this);
|
||||
}
|
||||
|
||||
public World init() {
|
||||
|
@ -529,43 +537,12 @@ public abstract class World implements IBlockAccess {
|
|||
}
|
||||
|
||||
public int getLight(BlockPos pos, boolean checkNeighbors) {
|
||||
if (pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000) {
|
||||
if (checkNeighbors && this.getBlockState(pos).getBlock().getUseNeighborBrightness()) {
|
||||
int i1 = this.getLight(pos.up(), false);
|
||||
int i = this.getLight(pos.east(), false);
|
||||
int j = this.getLight(pos.west(), false);
|
||||
int k = this.getLight(pos.south(), false);
|
||||
int l = this.getLight(pos.north(), false);
|
||||
if (i > i1) {
|
||||
i1 = i;
|
||||
}
|
||||
if (!checkNeighbors)
|
||||
return getLight(pos);
|
||||
|
||||
if (j > i1) {
|
||||
i1 = j;
|
||||
}
|
||||
final IBlockState blockState = getBlockState(pos);
|
||||
|
||||
if (k > i1) {
|
||||
i1 = k;
|
||||
}
|
||||
|
||||
if (l > i1) {
|
||||
i1 = l;
|
||||
}
|
||||
|
||||
return i1;
|
||||
} else if (pos.getY() < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
if (pos.getY() >= 256) {
|
||||
pos = new BlockPos(pos.getX(), 255, pos.getZ());
|
||||
}
|
||||
|
||||
Chunk chunk = this.getChunkFromBlockCoords(pos);
|
||||
return chunk.getLightSubtracted(pos, this.skylightSubtracted);
|
||||
}
|
||||
} else {
|
||||
return 15;
|
||||
}
|
||||
return Math.max(((ILightInfoProvider) blockState).alfheim$getLightFor(((World) (Object) this), EnumSkyBlock.BLOCK, pos), ((ILightInfoProvider) blockState).alfheim$getLightFor(((World) (Object) this), EnumSkyBlock.SKY, pos) - skylightSubtracted);
|
||||
}
|
||||
|
||||
/**+
|
||||
|
@ -605,45 +582,7 @@ public abstract class World implements IBlockAccess {
|
|||
}
|
||||
|
||||
public int getLightFromNeighborsFor(EnumSkyBlock type, BlockPos pos) {
|
||||
if (this.provider.getHasNoSky() && type == EnumSkyBlock.SKY) {
|
||||
return Chunk.getNoSkyLightValue();
|
||||
} else {
|
||||
if (pos.getY() < 0) {
|
||||
pos = new BlockPos(pos.getX(), 0, pos.getZ());
|
||||
}
|
||||
|
||||
if (!this.isValid(pos)) {
|
||||
return type.defaultLightValue;
|
||||
} else if (!this.isBlockLoaded(pos)) {
|
||||
return type.defaultLightValue;
|
||||
} else if (this.getBlockState(pos).getBlock().getUseNeighborBrightness()) {
|
||||
int i1 = this.getLightFor(type, pos.up());
|
||||
int i = this.getLightFor(type, pos.east());
|
||||
int j = this.getLightFor(type, pos.west());
|
||||
int k = this.getLightFor(type, pos.south());
|
||||
int l = this.getLightFor(type, pos.north());
|
||||
if (i > i1) {
|
||||
i1 = i;
|
||||
}
|
||||
|
||||
if (j > i1) {
|
||||
i1 = j;
|
||||
}
|
||||
|
||||
if (k > i1) {
|
||||
i1 = k;
|
||||
}
|
||||
|
||||
if (l > i1) {
|
||||
i1 = l;
|
||||
}
|
||||
|
||||
return i1;
|
||||
} else {
|
||||
Chunk chunk = this.getChunkFromBlockCoords(pos);
|
||||
return chunk.getLightFor(type, pos);
|
||||
}
|
||||
}
|
||||
return ((ILightInfoProvider) getBlockState(pos)).alfheim$getLightFor(((World) (Object) this), type, pos);
|
||||
}
|
||||
|
||||
public int getLightFor(EnumSkyBlock type, BlockPos pos) {
|
||||
|
@ -2325,118 +2264,9 @@ public abstract class World implements IBlockAccess {
|
|||
}
|
||||
|
||||
public boolean checkLightFor(EnumSkyBlock lightType, BlockPos pos) {
|
||||
if (!this.isAreaLoaded(pos, 17, false)) {
|
||||
return false;
|
||||
} else {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
this.theProfiler.startSection("getBrightness");
|
||||
int k = this.getLightFor(lightType, pos);
|
||||
int l = this.getRawLight(pos, lightType);
|
||||
int i1 = pos.getX();
|
||||
int j1 = pos.getY();
|
||||
int k1 = pos.getZ();
|
||||
if (l > k) {
|
||||
this.lightUpdateBlockList[j++] = 133152;
|
||||
} else if (l < k) {
|
||||
this.lightUpdateBlockList[j++] = 133152 | k << 18;
|
||||
alfheim$lightingEngine.scheduleLightUpdate(lightType, pos);
|
||||
|
||||
while (i < j) {
|
||||
int l1 = this.lightUpdateBlockList[i++];
|
||||
int i2 = (l1 & 63) - 32 + i1;
|
||||
int j2 = (l1 >> 6 & 63) - 32 + j1;
|
||||
int k2 = (l1 >> 12 & 63) - 32 + k1;
|
||||
int l2 = l1 >> 18 & 15;
|
||||
BlockPos blockpos = new BlockPos(i2, j2, k2);
|
||||
int i3 = this.getLightFor(lightType, blockpos);
|
||||
if (i3 == l2) {
|
||||
this.setLightFor(lightType, blockpos, 0);
|
||||
if (l2 > 0) {
|
||||
int j3 = MathHelper.abs_int(i2 - i1);
|
||||
int k3 = MathHelper.abs_int(j2 - j1);
|
||||
int l3 = MathHelper.abs_int(k2 - k1);
|
||||
if (j3 + k3 + l3 < 17) {
|
||||
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
|
||||
|
||||
EnumFacing[] facings = EnumFacing._VALUES;
|
||||
for (int m = 0; m < facings.length; ++m) {
|
||||
EnumFacing enumfacing = facings[m];
|
||||
int i4 = i2 + enumfacing.getFrontOffsetX();
|
||||
int j4 = j2 + enumfacing.getFrontOffsetY();
|
||||
int k4 = k2 + enumfacing.getFrontOffsetZ();
|
||||
blockpos$mutableblockpos.func_181079_c(i4, j4, k4);
|
||||
int l4 = Math.max(1,
|
||||
this.getBlockState(blockpos$mutableblockpos).getBlock().getLightOpacity());
|
||||
i3 = this.getLightFor(lightType, blockpos$mutableblockpos);
|
||||
if (i3 == l2 - l4 && j < this.lightUpdateBlockList.length) {
|
||||
this.lightUpdateBlockList[j++] = i4 - i1 + 32 | j4 - j1 + 32 << 6
|
||||
| k4 - k1 + 32 << 12 | l2 - l4 << 18;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
}
|
||||
|
||||
this.theProfiler.endSection();
|
||||
this.theProfiler.startSection("checkedPosition < toCheckCount");
|
||||
|
||||
while (i < j) {
|
||||
int i5 = this.lightUpdateBlockList[i++];
|
||||
int j5 = (i5 & 63) - 32 + i1;
|
||||
int k5 = (i5 >> 6 & 63) - 32 + j1;
|
||||
int l5 = (i5 >> 12 & 63) - 32 + k1;
|
||||
BlockPos blockpos1 = new BlockPos(j5, k5, l5);
|
||||
int i6 = this.getLightFor(lightType, blockpos1);
|
||||
int j6 = this.getRawLight(blockpos1, lightType);
|
||||
if (j6 != i6) {
|
||||
this.setLightFor(lightType, blockpos1, j6);
|
||||
if (j6 > i6) {
|
||||
int k6 = Math.abs(j5 - i1);
|
||||
int l6 = Math.abs(k5 - j1);
|
||||
int i7 = Math.abs(l5 - k1);
|
||||
boolean flag = j < this.lightUpdateBlockList.length - 6;
|
||||
if (k6 + l6 + i7 < 17 && flag) {
|
||||
if (this.getLightFor(lightType, blockpos1.west()) < j6) {
|
||||
this.lightUpdateBlockList[j++] = j5 - 1 - i1 + 32 + (k5 - j1 + 32 << 6)
|
||||
+ (l5 - k1 + 32 << 12);
|
||||
}
|
||||
|
||||
if (this.getLightFor(lightType, blockpos1.east()) < j6) {
|
||||
this.lightUpdateBlockList[j++] = j5 + 1 - i1 + 32 + (k5 - j1 + 32 << 6)
|
||||
+ (l5 - k1 + 32 << 12);
|
||||
}
|
||||
|
||||
if (this.getLightFor(lightType, blockpos1.down()) < j6) {
|
||||
this.lightUpdateBlockList[j++] = j5 - i1 + 32 + (k5 - 1 - j1 + 32 << 6)
|
||||
+ (l5 - k1 + 32 << 12);
|
||||
}
|
||||
|
||||
if (this.getLightFor(lightType, blockpos1.up()) < j6) {
|
||||
this.lightUpdateBlockList[j++] = j5 - i1 + 32 + (k5 + 1 - j1 + 32 << 6)
|
||||
+ (l5 - k1 + 32 << 12);
|
||||
}
|
||||
|
||||
if (this.getLightFor(lightType, blockpos1.north()) < j6) {
|
||||
this.lightUpdateBlockList[j++] = j5 - i1 + 32 + (k5 - j1 + 32 << 6)
|
||||
+ (l5 - 1 - k1 + 32 << 12);
|
||||
}
|
||||
|
||||
if (this.getLightFor(lightType, blockpos1.south()) < j6) {
|
||||
this.lightUpdateBlockList[j++] = j5 - i1 + 32 + (k5 - j1 + 32 << 6)
|
||||
+ (l5 + 1 - k1 + 32 << 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.theProfiler.endSection();
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**+
|
||||
|
@ -3210,4 +3040,12 @@ public abstract class World implements IBlockAccess {
|
|||
short short1 = 128;
|
||||
return i >= -short1 && i <= short1 && j >= -short1 && j <= short1;
|
||||
}
|
||||
|
||||
public LightingEngine alfheim$getLightingEngine() {
|
||||
return alfheim$lightingEngine;
|
||||
}
|
||||
|
||||
public int alfheim$getLight(final EnumSkyBlock lightType, final BlockPos blockPos) {
|
||||
return getLightFor(lightType, blockPos);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,13 @@ import java.util.Arrays;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.hoosiertransfer.Alfheim.IChunkLightingData;
|
||||
import net.hoosiertransfer.Alfheim.ILightingEngineProvider;
|
||||
import net.hoosiertransfer.Alfheim.lighting.LightUtil;
|
||||
import net.hoosiertransfer.Alfheim.lighting.LightingEngine;
|
||||
import net.hoosiertransfer.Alfheim.util.EnumBoundaryFacing;
|
||||
import net.hoosiertransfer.Alfheim.util.WorldChunkSlice;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
@ -81,6 +88,15 @@ public class Chunk {
|
|||
private int queuedLightChecks;
|
||||
private List<BlockPos> tileEntityPosQueue;
|
||||
|
||||
public static final ExtendedBlockStorage NULL_BLOCK_STORAGE = null;
|
||||
|
||||
private LightingEngine alfheim$lightingEngine;
|
||||
private boolean alfheim$isLightInitialized;
|
||||
private short[] alfheim$neighborLightChecks;
|
||||
private static final EnumSkyBlock[] ENUM_SKY_BLOCK_VALUES = EnumSkyBlock.values();
|
||||
private static final EnumFacing[] ENUM_FACING_HORIZONTAL = EnumFacing.Plane.HORIZONTAL.facings();
|
||||
private static final EnumFacing.AxisDirection[] ENUM_AXIS_DIRECTION_VALUES = EnumFacing.AxisDirection.values();
|
||||
|
||||
public Chunk(World worldIn, int x, int z) {
|
||||
this.storageArrays = new ExtendedBlockStorage[16];
|
||||
this.blockBiomeArray = new byte[256];
|
||||
|
@ -101,6 +117,8 @@ public class Chunk {
|
|||
|
||||
Arrays.fill(this.precipitationHeightMap, -999);
|
||||
Arrays.fill(this.blockBiomeArray, (byte) -1);
|
||||
|
||||
alfheim$lightingEngine = worldIn.alfheim$getLightingEngine();
|
||||
}
|
||||
|
||||
public Chunk(World worldIn, ChunkPrimer primer, int x, int z) {
|
||||
|
@ -231,8 +249,10 @@ public class Chunk {
|
|||
ExtendedBlockStorage extendedblockstorage = this.storageArrays[i1 >> 4];
|
||||
if (extendedblockstorage != null) {
|
||||
extendedblockstorage.setExtSkylightValue(j, i1 & 15, k, k1);
|
||||
this.worldObj.notifyLightSet(
|
||||
new BlockPos((this.xPosition << 4) + j, i1, (this.zPosition << 4) + k));
|
||||
alfheim$initSkylightForSection(storageArrays[i1 >> 4]);
|
||||
// do i comment this out?
|
||||
// this.worldObj.notifyLightSet(
|
||||
// new BlockPos((this.xPosition << 4) + j, i1, (this.zPosition << 4) + k));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,44 +281,22 @@ public class Chunk {
|
|||
}
|
||||
|
||||
private void recheckGaps(boolean parFlag) {
|
||||
this.worldObj.theProfiler.startSection("recheckGaps");
|
||||
if (this.worldObj.isAreaLoaded(new BlockPos(this.xPosition * 16 + 8, 0, this.zPosition * 16 + 8), 16)) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
for (int j = 0; j < 16; ++j) {
|
||||
if (this.updateSkylightColumns[i + j * 16]) {
|
||||
this.updateSkylightColumns[i + j * 16] = false;
|
||||
int k = this.getHeightValue(i, j);
|
||||
int l = this.xPosition * 16 + i;
|
||||
int i1 = this.zPosition * 16 + j;
|
||||
int j1 = Integer.MAX_VALUE;
|
||||
if (!worldObj.isAreaLoaded(new BlockPos((xPosition << 4) + 8, 0, (zPosition << 4) + 8), 16))
|
||||
return;
|
||||
|
||||
EnumFacing[] facings = EnumFacing.Plane.HORIZONTAL.facingsArray;
|
||||
for (int m = 0; m < facings.length; ++m) {
|
||||
EnumFacing enumfacing = facings[m];
|
||||
j1 = Math.min(j1, this.worldObj.getChunksLowestHorizon(l + enumfacing.getFrontOffsetX(),
|
||||
i1 + enumfacing.getFrontOffsetZ()));
|
||||
}
|
||||
final WorldChunkSlice slice = new WorldChunkSlice(worldObj.getChunkProvider(), xPosition, zPosition);
|
||||
|
||||
this.checkSkylightNeighborHeight(l, i1, j1);
|
||||
for (int x = 0; x < 16; ++x) {
|
||||
for (int z = 0; z < 16; ++z) {
|
||||
if (!alfheim$recheckGapsForColumn(slice, x, z))
|
||||
continue;
|
||||
|
||||
for (int m = 0; m < facings.length; ++m) {
|
||||
EnumFacing enumfacing1 = facings[m];
|
||||
this.checkSkylightNeighborHeight(l + enumfacing1.getFrontOffsetX(),
|
||||
i1 + enumfacing1.getFrontOffsetZ(), k);
|
||||
}
|
||||
if (parFlag)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (parFlag) {
|
||||
this.worldObj.theProfiler.endSection();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.isGapLightingUpdated = false;
|
||||
}
|
||||
|
||||
this.worldObj.theProfiler.endSection();
|
||||
isGapLightingUpdated = false;
|
||||
}
|
||||
|
||||
/**+
|
||||
|
@ -331,91 +329,24 @@ public class Chunk {
|
|||
* sky-light for a given block inside a chunk.
|
||||
*/
|
||||
private void relightBlock(int x, int y, int z) {
|
||||
int i = this.heightMap[z << 4 | x] & 255;
|
||||
int j = i;
|
||||
if (y > i) {
|
||||
j = y;
|
||||
}
|
||||
int heightMapY = heightMap[z << 4 | x] & 255;
|
||||
int newHeightMapY = Math.max(y, heightMapY);
|
||||
|
||||
while (j > 0 && this.getBlockLightOpacity(x, j - 1, z) == 0) {
|
||||
--j;
|
||||
}
|
||||
while (newHeightMapY > 0 && getBlockLightOpacity(x, newHeightMapY - 1, z) == 0)
|
||||
--newHeightMapY;
|
||||
|
||||
if (j != i) {
|
||||
this.worldObj.markBlocksDirtyVertical(x + this.xPosition * 16, z + this.zPosition * 16, j, i);
|
||||
this.heightMap[z << 4 | x] = j;
|
||||
int k = this.xPosition * 16 + x;
|
||||
int l = this.zPosition * 16 + z;
|
||||
if (!this.worldObj.provider.getHasNoSky()) {
|
||||
if (j < i) {
|
||||
for (int j1 = j; j1 < i; ++j1) {
|
||||
ExtendedBlockStorage extendedblockstorage2 = this.storageArrays[j1 >> 4];
|
||||
if (extendedblockstorage2 != null) {
|
||||
extendedblockstorage2.setExtSkylightValue(x, j1 & 15, z, 15);
|
||||
this.worldObj.notifyLightSet(
|
||||
new BlockPos((this.xPosition << 4) + x, j1, (this.zPosition << 4) + z));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i1 = i; i1 < j; ++i1) {
|
||||
ExtendedBlockStorage extendedblockstorage = this.storageArrays[i1 >> 4];
|
||||
if (extendedblockstorage != null) {
|
||||
extendedblockstorage.setExtSkylightValue(x, i1 & 15, z, 0);
|
||||
this.worldObj.notifyLightSet(
|
||||
new BlockPos((this.xPosition << 4) + x, i1, (this.zPosition << 4) + z));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newHeightMapY == heightMapY)
|
||||
return;
|
||||
|
||||
int k1 = 15;
|
||||
heightMap[z << 4 | x] = newHeightMapY;
|
||||
|
||||
while (j > 0 && k1 > 0) {
|
||||
--j;
|
||||
int i2 = this.getBlockLightOpacity(x, j, z);
|
||||
if (i2 == 0) {
|
||||
i2 = 1;
|
||||
}
|
||||
if (!worldObj.provider.getHasNoSky())
|
||||
alfheim$relightSkylightColumn(x, z, heightMapY, newHeightMapY);
|
||||
|
||||
k1 -= i2;
|
||||
if (k1 < 0) {
|
||||
k1 = 0;
|
||||
}
|
||||
final int heightMapY1 = heightMap[z << 4 | x];
|
||||
|
||||
ExtendedBlockStorage extendedblockstorage1 = this.storageArrays[j >> 4];
|
||||
if (extendedblockstorage1 != null) {
|
||||
extendedblockstorage1.setExtSkylightValue(x, j & 15, z, k1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int l1 = this.heightMap[z << 4 | x];
|
||||
int j2 = i;
|
||||
int k2 = l1;
|
||||
if (l1 < i) {
|
||||
j2 = l1;
|
||||
k2 = i;
|
||||
}
|
||||
|
||||
if (l1 < this.heightMapMinimum) {
|
||||
this.heightMapMinimum = l1;
|
||||
}
|
||||
|
||||
if (!this.worldObj.provider.getHasNoSky()) {
|
||||
EnumFacing[] facings = EnumFacing.Plane.HORIZONTAL.facingsArray;
|
||||
for (int m = 0; m < facings.length; ++m) {
|
||||
EnumFacing enumfacing = facings[m];
|
||||
this.updateSkylightNeighborHeight(k + enumfacing.getFrontOffsetX(),
|
||||
l + enumfacing.getFrontOffsetZ(), j2, k2);
|
||||
}
|
||||
|
||||
this.updateSkylightNeighborHeight(k, l, j2, k2);
|
||||
}
|
||||
|
||||
if (!this.worldObj.isRemote) {
|
||||
++EaglerMinecraftServer.counterLightUpdate;
|
||||
}
|
||||
this.isModified = true;
|
||||
}
|
||||
if (heightMapY1 < heightMapMinimum)
|
||||
heightMapMinimum = heightMapY1;
|
||||
}
|
||||
|
||||
public int getBlockLightOpacity(BlockPos blockpos) {
|
||||
|
@ -577,7 +508,9 @@ public class Chunk {
|
|||
|
||||
extendedblockstorage = this.storageArrays[j >> 4] = new ExtendedBlockStorage(j >> 4 << 4,
|
||||
!this.worldObj.provider.getHasNoSky());
|
||||
flag = j >= i1;
|
||||
|
||||
alfheim$initSkylightForSection(extendedblockstorage);
|
||||
// flag = j >= i1;
|
||||
}
|
||||
|
||||
extendedblockstorage.set(i, j & 15, k, state);
|
||||
|
@ -605,10 +538,10 @@ public class Chunk {
|
|||
this.relightBlock(i, j, k);
|
||||
}
|
||||
|
||||
if (j1 != k1 && (j1 < k1 || this.getLightFor(EnumSkyBlock.SKY, pos) > 0
|
||||
|| this.getLightFor(EnumSkyBlock.BLOCK, pos) > 0)) {
|
||||
this.propagateSkylightOcclusion(i, k);
|
||||
}
|
||||
// if (j1 != k1 && (j1 < k1 || this.getLightFor(EnumSkyBlock.SKY, pos) > 0
|
||||
// || this.getLightFor(EnumSkyBlock.BLOCK, pos) > 0)) {
|
||||
// this.propagateSkylightOcclusion(i, k);
|
||||
// }
|
||||
}
|
||||
|
||||
if (block1 instanceof ITileEntityProvider) {
|
||||
|
@ -642,17 +575,9 @@ public class Chunk {
|
|||
}
|
||||
|
||||
public int getLightFor(EnumSkyBlock enumskyblock, BlockPos blockpos) {
|
||||
int i = blockpos.getX() & 15;
|
||||
int j = blockpos.getY();
|
||||
int k = blockpos.getZ() & 15;
|
||||
ExtendedBlockStorage extendedblockstorage = this.storageArrays[j >> 4];
|
||||
return extendedblockstorage == null
|
||||
? (this.canSeeSky(blockpos) ? enumskyblock.defaultLightValue : getNoSkyLightValue())
|
||||
: (enumskyblock == EnumSkyBlock.SKY
|
||||
? (this.worldObj.provider.getHasNoSky() ? getNoSkyLightValue()
|
||||
: extendedblockstorage.getExtSkylightValue(i, j & 15, k))
|
||||
: (enumskyblock == EnumSkyBlock.BLOCK ? extendedblockstorage.getExtBlocklightValue(i, j & 15, k)
|
||||
: enumskyblock.defaultLightValue));
|
||||
alfheim$lightingEngine.processLightUpdatesForType(enumskyblock);
|
||||
|
||||
return alfheim$getCachedLightFor(enumskyblock, blockpos);
|
||||
}
|
||||
|
||||
public void setLightFor(EnumSkyBlock enumskyblock, BlockPos blockpos, int i) {
|
||||
|
@ -678,6 +603,7 @@ public class Chunk {
|
|||
}
|
||||
|
||||
public int getLightSubtracted(BlockPos blockpos, int i) {
|
||||
alfheim$lightingEngine.processLightUpdates();
|
||||
int j = blockpos.getX() & 15;
|
||||
int k = blockpos.getY();
|
||||
int l = blockpos.getZ() & 15;
|
||||
|
@ -830,6 +756,33 @@ public class Chunk {
|
|||
this.worldObj.loadEntities(this.entityLists[i]);
|
||||
}
|
||||
|
||||
final Chunk chunk = (Chunk) (Object) this;
|
||||
|
||||
for (final EnumFacing facing : EnumFacing.HORIZONTALS) {
|
||||
final int xOffset = facing.getXOffset();
|
||||
final int zOffset = facing.getZOffset();
|
||||
|
||||
final Chunk nChunk = worldObj.getChunkProvider().getLoadedChunk(chunk.xPosition + xOffset, chunk.zPosition + zOffset);
|
||||
|
||||
if (nChunk == null)
|
||||
continue;
|
||||
|
||||
for (final EnumSkyBlock lightType : ENUM_SKY_BLOCK_VALUES) {
|
||||
for (final EnumFacing.AxisDirection axisDir : ENUM_AXIS_DIRECTION_VALUES) {
|
||||
// Merge flags upon loading of a chunk. This ensures that all flags are always already on the IN boundary below
|
||||
alfheim$mergeFlags(lightType, chunk, nChunk, facing, axisDir);
|
||||
alfheim$mergeFlags(lightType, nChunk, chunk, facing.getOpposite(), axisDir);
|
||||
|
||||
// Check everything that might have been canceled due to this chunk not being loaded.
|
||||
// Also, pass in chunks if already known
|
||||
// The boundary to the neighbor chunk (both ways)
|
||||
alfheim$scheduleRelightChecksForBoundary(chunk, nChunk, null, lightType, xOffset, zOffset, axisDir);
|
||||
alfheim$scheduleRelightChecksForBoundary(nChunk, chunk, null, lightType, -xOffset, -zOffset, axisDir);
|
||||
// The boundary to the diagonal neighbor (since the checks in that chunk were aborted if this chunk wasn't loaded, see alfheim$scheduleRelightChecksForBoundary)
|
||||
alfheim$scheduleRelightChecksForBoundary(nChunk, null, chunk, lightType, (zOffset != 0 ? axisDir.getOffset() : 0), (xOffset != 0 ? axisDir.getOffset() : 0), facing.getAxisDirection() == EnumFacing.AxisDirection.POSITIVE ? EnumFacing.AxisDirection.NEGATIVE : EnumFacing.AxisDirection.POSITIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**+
|
||||
|
@ -1014,7 +967,7 @@ public class Chunk {
|
|||
|
||||
this.field_150815_m = true;
|
||||
if (!this.isLightPopulated && this.isTerrainPopulated) {
|
||||
this.func_150809_p();
|
||||
this.checkLight();
|
||||
}
|
||||
|
||||
while (!this.tileEntityPosQueue.isEmpty()) {
|
||||
|
@ -1225,38 +1178,27 @@ public class Chunk {
|
|||
|
||||
}
|
||||
|
||||
public void func_150809_p() {
|
||||
public void checkLight() {
|
||||
this.isTerrainPopulated = true;
|
||||
this.isLightPopulated = true;
|
||||
BlockPos blockpos = new BlockPos(this.xPosition << 4, 0, this.zPosition << 4);
|
||||
if (!this.worldObj.provider.getHasNoSky()) {
|
||||
if (this.worldObj.isAreaLoaded(blockpos.add(-1, 0, -1),
|
||||
blockpos.add(16, this.worldObj.func_181545_F(), 16))) {
|
||||
label92: for (int i = 0; i < 16; ++i) {
|
||||
for (int j = 0; j < 16; ++j) {
|
||||
if (!this.func_150811_f(i, j)) {
|
||||
this.isLightPopulated = false;
|
||||
break label92;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isLightPopulated) {
|
||||
EnumFacing[] facings = EnumFacing.Plane.HORIZONTAL.facingsArray;
|
||||
for (int i = 0; i < facings.length; ++i) {
|
||||
EnumFacing enumfacing = facings[i];
|
||||
int k = enumfacing.getAxisDirection() == EnumFacing.AxisDirection.POSITIVE ? 16 : 1;
|
||||
this.worldObj.getChunkFromBlockCoords(blockpos.offset(enumfacing, k))
|
||||
.func_180700_a(enumfacing.getOpposite());
|
||||
}
|
||||
final Chunk chunk = (Chunk) (Object) this;
|
||||
|
||||
if (!chunk.alfheim$isLightInitialized())
|
||||
alfheim$initChunkLighting(chunk, worldObj);
|
||||
|
||||
this.func_177441_y();
|
||||
}
|
||||
} else {
|
||||
this.isLightPopulated = false;
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int z = -1; z <= 1; z++) {
|
||||
if (x == 0 && z == 0)
|
||||
continue;
|
||||
|
||||
final Chunk nChunk = worldObj.getChunkProvider().getLoadedChunk(chunk.xPosition + x, chunk.zPosition + z);
|
||||
|
||||
if (nChunk == null || !nChunk.alfheim$isLightInitialized())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
chunk.setLightPopulated(true);
|
||||
}
|
||||
|
||||
private void func_177441_y() {
|
||||
|
@ -1400,4 +1342,309 @@ public class Chunk {
|
|||
public static enum EnumCreateEntityType {
|
||||
IMMEDIATE, QUEUED, CHECK;
|
||||
}
|
||||
|
||||
private boolean alfheim$recheckGapsForColumn(final WorldChunkSlice slice, final int x, final int z) {
|
||||
final int i = x + z * 16;
|
||||
|
||||
if (updateSkylightColumns[i]) {
|
||||
updateSkylightColumns[i] = false;
|
||||
|
||||
final int x1 = this.xPosition * 16 + x;
|
||||
final int z1 = this.zPosition * 16 + z;
|
||||
|
||||
alfheim$recheckGapsSkylightNeighborHeight(slice, x1, z1, getHeightValue(x, z), alfheim$recheckGapsGetLowestHeight(slice, x1, z1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int alfheim$recheckGapsGetLowestHeight(final WorldChunkSlice slice, final int x, final int z) {
|
||||
int max = Integer.MAX_VALUE;
|
||||
|
||||
for (final EnumFacing facing : ENUM_FACING_HORIZONTAL) {
|
||||
final Chunk chunk = slice.getChunkFromWorldCoords(x + facing.getXOffset(), z + facing.getZOffset());
|
||||
|
||||
if (chunk != null)
|
||||
max = Math.min(max, chunk.getLowestHeight());
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
private void alfheim$recheckGapsSkylightNeighborHeight(final WorldChunkSlice slice, final int x, final int z, final int height, final int max) {
|
||||
alfheim$checkSkylightNeighborHeight(slice, x, z, max);
|
||||
|
||||
for (final EnumFacing facing : ENUM_FACING_HORIZONTAL)
|
||||
alfheim$checkSkylightNeighborHeight(slice, x + facing.getXOffset(), z + facing.getFrontOffsetZ(), height);
|
||||
}
|
||||
|
||||
private void alfheim$checkSkylightNeighborHeight(final WorldChunkSlice slice, final int x, final int z, final int maxValue) {
|
||||
if (slice.getChunkFromWorldCoords(x, z) == null)
|
||||
return;
|
||||
|
||||
final int y = slice.getChunkFromWorldCoords(x, z).getHeightValue(x & 15, z & 15);
|
||||
|
||||
if (y > maxValue)
|
||||
alfheim$updateSkylightNeighborHeight(slice, x, z, maxValue, y + 1);
|
||||
else if (y < maxValue)
|
||||
alfheim$updateSkylightNeighborHeight(slice, x, z, y, maxValue + 1);
|
||||
}
|
||||
|
||||
private void alfheim$updateSkylightNeighborHeight(final WorldChunkSlice slice, final int x, final int z, final int startY, final int endY) {
|
||||
if (endY < startY)
|
||||
return;
|
||||
|
||||
if (!slice.isLoaded(x, z, 16))
|
||||
return;
|
||||
|
||||
for (int y = startY; y < endY; ++y)
|
||||
worldObj.checkLightFor(EnumSkyBlock.SKY, new BlockPos(x, y, z));
|
||||
|
||||
isModified = true;
|
||||
}
|
||||
|
||||
private static void alfheim$mergeFlags(final EnumSkyBlock lightType, final Chunk inChunk, final Chunk outChunk, final EnumFacing dir, final EnumFacing.AxisDirection axisDirection) {
|
||||
// final IChunkLightingData outChunkLightingData = (IChunkLightingData) outChunk; // I REALLY NEED TO SUBMIT A BUG REPORT FOR THIS WEIRD PROBLEM WHERE FUNCTIONS GET DELETED IF YOU DO THIS IN TEAVM
|
||||
|
||||
if (outChunk.alfheim$getNeighborLightChecks() == null)
|
||||
return;
|
||||
|
||||
inChunk.alfheim$initNeighborLightChecks();
|
||||
|
||||
final int inIndex = alfheim$getFlagIndex(lightType, dir, axisDirection, EnumBoundaryFacing.IN);
|
||||
final int outIndex = alfheim$getFlagIndex(lightType, dir.getOpposite(), axisDirection, EnumBoundaryFacing.OUT);
|
||||
|
||||
inChunk.alfheim$getNeighborLightChecks()[inIndex] |= outChunk.alfheim$getNeighborLightChecks()[outIndex];
|
||||
// No need to call Chunk.setModified() since checks are not deleted from outChunk
|
||||
}
|
||||
|
||||
private void alfheim$scheduleRelightChecksForBoundary(final Chunk chunk, Chunk nChunk, Chunk sChunk, final EnumSkyBlock lightType, final int xOffset, final int zOffset, final EnumFacing.AxisDirection axisDirection) {
|
||||
if (chunk.alfheim$getNeighborLightChecks() == null)
|
||||
return;
|
||||
|
||||
final int flagIndex = alfheim$getFlagIndex(lightType, xOffset, zOffset, axisDirection, EnumBoundaryFacing.IN); // OUT checks from neighbor are already merged
|
||||
|
||||
final int flags = chunk.alfheim$getNeighborLightChecks()[flagIndex];
|
||||
|
||||
if (flags == 0)
|
||||
return;
|
||||
|
||||
if (nChunk == null) {
|
||||
nChunk = worldObj.getChunkProvider().getLoadedChunk(chunk.xPosition + xOffset, chunk.zPosition + zOffset);
|
||||
|
||||
if (nChunk == null)
|
||||
return;
|
||||
}
|
||||
|
||||
if (sChunk == null) {
|
||||
sChunk = worldObj.getChunkProvider()
|
||||
.getLoadedChunk(chunk.xPosition + (zOffset != 0 ? axisDirection.getOffset() : 0), chunk.zPosition + (xOffset != 0 ? axisDirection.getOffset() : 0));
|
||||
|
||||
if (sChunk == null)
|
||||
return; // Cancel, since the checks in the corner columns require the corner column of sChunk
|
||||
}
|
||||
|
||||
final int reverseIndex = alfheim$getFlagIndex(lightType, -xOffset, -zOffset, axisDirection, EnumBoundaryFacing.OUT);
|
||||
|
||||
chunk.alfheim$getNeighborLightChecks()[flagIndex] = 0;
|
||||
|
||||
if (nChunk.alfheim$getNeighborLightChecks() != null)
|
||||
nChunk.alfheim$getNeighborLightChecks()[reverseIndex] = 0; // Clear only now that it's clear that the checks are processed
|
||||
|
||||
chunk.setChunkModified();
|
||||
nChunk.setChunkModified();
|
||||
|
||||
// Get the area to check
|
||||
// Start in the corner...
|
||||
int xMin = chunk.xPosition << 4;
|
||||
int zMin = chunk.zPosition << 4;
|
||||
|
||||
// Move to other side of chunk if the direction is positive
|
||||
if ((xOffset | zOffset) > 0) {
|
||||
xMin += 15 * xOffset;
|
||||
zMin += 15 * zOffset;
|
||||
}
|
||||
|
||||
// Shift to other half if necessary (shift perpendicular to dir)
|
||||
if (axisDirection == EnumFacing.AxisDirection.POSITIVE) {
|
||||
xMin += 8 * (zOffset & 1); //x & 1 is same as abs(x) for x=-1,0,1
|
||||
zMin += 8 * (xOffset & 1);
|
||||
}
|
||||
|
||||
// Get maximal values (shift perpendicular to dir)
|
||||
final int xMax = xMin + 7 * (zOffset & 1);
|
||||
final int zMax = zMin + 7 * (xOffset & 1);
|
||||
|
||||
for (int y = 0; y < 16; ++y)
|
||||
if ((flags & (1 << y)) != 0)
|
||||
for (int x = xMin; x <= xMax; ++x)
|
||||
for (int z = zMin; z <= zMax; ++z)
|
||||
alfheim$scheduleRelightChecksForColumn(lightType, x, z, y << 4, (y << 4) + 15);
|
||||
}
|
||||
|
||||
private void alfheim$initSkylightForSection(final ExtendedBlockStorage extendedBlockStorage) {
|
||||
if (worldObj.provider.getHasNoSky())
|
||||
return;
|
||||
|
||||
for (int x = 0; x < 16; ++x) {
|
||||
for (int z = 0; z < 16; ++z) {
|
||||
if (((Chunk) (Object) this).getHeightValue(x, z) > extendedBlockStorage.getYLocation())
|
||||
continue;
|
||||
|
||||
for (int y = 0; y < 16; ++y)
|
||||
extendedBlockStorage.setExtSkylightValue(x, y, z, EnumSkyBlock.SKY.defaultLightValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void alfheim$scheduleRelightChecksForColumn(final EnumSkyBlock lightType, final int x, final int z, final int yMin, final int yMax) {
|
||||
final BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||
|
||||
for (int y = yMin; y <= yMax; ++y)
|
||||
worldObj.checkLightFor(lightType, mutableBlockPos.setPos(x, y, z));
|
||||
}
|
||||
|
||||
private static int alfheim$getFlagIndex(final EnumSkyBlock lightType, final int xOffset, final int zOffset, final EnumFacing.AxisDirection axisDirection, final EnumBoundaryFacing boundaryFacing) {
|
||||
return (lightType == EnumSkyBlock.BLOCK ? 0 : 16) | ((xOffset + 1) << 2) | ((zOffset + 1) << 1) | (axisDirection.getOffset() + 1) | boundaryFacing.ordinal();
|
||||
}
|
||||
|
||||
private static int alfheim$getFlagIndex(final EnumSkyBlock lightType, final EnumFacing facing, final EnumFacing.AxisDirection axisDirection, final EnumBoundaryFacing boundaryFacing) {
|
||||
return alfheim$getFlagIndex(lightType, facing.getXOffset(), facing.getZOffset(), axisDirection, boundaryFacing);
|
||||
}
|
||||
|
||||
private static void alfheim$initChunkLighting(final Chunk chunk, final World world) {
|
||||
final int xBase = chunk.xPosition << 4;
|
||||
final int zBase = chunk.zPosition << 4;
|
||||
|
||||
final BlockPos.PooledMutableBlockPos mutableBlockPos = BlockPos.PooledMutableBlockPos.retain(xBase, 0, zBase);
|
||||
|
||||
if (world.isAreaLoaded(mutableBlockPos.add(-16, 0, -16), mutableBlockPos.add(31, 255, 31), false)) {
|
||||
final ExtendedBlockStorage[] extendedBlockStorage = chunk.getBlockStorageArray();
|
||||
|
||||
for (int i = 0; i < extendedBlockStorage.length; ++i) {
|
||||
final ExtendedBlockStorage storage = extendedBlockStorage[i];
|
||||
|
||||
if (storage == Chunk.NULL_BLOCK_STORAGE)
|
||||
continue;
|
||||
|
||||
int yBase = i * 16;
|
||||
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
mutableBlockPos.setPos(xBase + x, yBase + y, zBase + z);
|
||||
|
||||
if (LightUtil.getLightValueForState(storage.get(x, y, z), world, mutableBlockPos) > 0)
|
||||
world.checkLightFor(EnumSkyBlock.BLOCK, mutableBlockPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!world.provider.getHasNoSky())
|
||||
chunk.alfheim$setSkylightUpdatedPublic();
|
||||
|
||||
chunk.alfheim$setLightInitialized(true);
|
||||
}
|
||||
|
||||
mutableBlockPos.release();
|
||||
}
|
||||
|
||||
private void alfheim$relightSkylightColumn(final int x, final int z, final int height1, final int height2) {
|
||||
final int yMin = Math.min(height1, height2);
|
||||
final int yMax = Math.max(height1, height2) - 1;
|
||||
|
||||
final Chunk chunk = ((Chunk) (Object) this);
|
||||
|
||||
final ExtendedBlockStorage[] sections = chunk.getBlockStorageArray();
|
||||
|
||||
final int xBase = (chunk.xPosition << 4) + x;
|
||||
final int zBase = (chunk.zPosition << 4) + z;
|
||||
|
||||
alfheim$scheduleRelightChecksForColumn(EnumSkyBlock.SKY, xBase, zBase, yMin, yMax);
|
||||
|
||||
if (sections[yMin >> 4] == Chunk.NULL_BLOCK_STORAGE && yMin > 0) {
|
||||
worldObj.checkLightFor(EnumSkyBlock.SKY, new BlockPos(xBase, yMin - 1, zBase));
|
||||
}
|
||||
|
||||
short emptySections = 0;
|
||||
|
||||
for (int sec = yMax >> 4; sec >= yMin >> 4; --sec) {
|
||||
if (sections[sec] == Chunk.NULL_BLOCK_STORAGE) {
|
||||
emptySections |= (short) (1 << sec);
|
||||
}
|
||||
}
|
||||
|
||||
if (emptySections != 0) {
|
||||
for (final EnumFacing facing : EnumFacing.HORIZONTALS) {
|
||||
final int xOffset = facing.getXOffset();
|
||||
final int zOffset = facing.getZOffset();
|
||||
|
||||
final boolean neighborColumnExists =
|
||||
(((x + xOffset) | (z + zOffset)) & 16) == 0
|
||||
//Checks whether the position is at the specified border (the 16 bit is set for both 15+1 and 0-1)
|
||||
|| worldObj.getChunkProvider().getLoadedChunk(chunk.xPosition + xOffset, chunk.zPosition + zOffset) != null;
|
||||
|
||||
if (neighborColumnExists) {
|
||||
for (int sec = yMax >> 4; sec >= yMin >> 4; --sec) {
|
||||
if ((emptySections & (1 << sec)) != 0)
|
||||
alfheim$scheduleRelightChecksForColumn(EnumSkyBlock.SKY, xBase + xOffset, zBase + zOffset, sec << 4, (sec << 4) + 15);
|
||||
}
|
||||
} else {
|
||||
chunk.alfheim$initNeighborLightChecks();
|
||||
|
||||
final EnumFacing.AxisDirection axisDirection = ((facing.getAxis() == EnumFacing.Axis.X ? z : x) & 15) < 8 ? EnumFacing.AxisDirection.NEGATIVE : EnumFacing.AxisDirection.POSITIVE;
|
||||
chunk.alfheim$getNeighborLightChecks()[alfheim$getFlagIndex(EnumSkyBlock.SKY, facing, axisDirection, EnumBoundaryFacing.OUT)] |= emptySections;
|
||||
|
||||
chunk.setChunkModified();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public short[] alfheim$getNeighborLightChecks() {
|
||||
return alfheim$neighborLightChecks;
|
||||
}
|
||||
|
||||
public void alfheim$setNeighborLightChecks(final short[] data) {
|
||||
alfheim$neighborLightChecks = data;
|
||||
}
|
||||
|
||||
public LightingEngine alfheim$getLightingEngine() {
|
||||
return alfheim$lightingEngine;
|
||||
}
|
||||
|
||||
public boolean alfheim$isLightInitialized() {
|
||||
return alfheim$isLightInitialized;
|
||||
}
|
||||
|
||||
public void alfheim$setLightInitialized(final boolean lightInitialized) {
|
||||
alfheim$isLightInitialized = lightInitialized;
|
||||
}
|
||||
|
||||
public void alfheim$setSkylightUpdatedPublic() {
|
||||
func_177441_y();
|
||||
}
|
||||
|
||||
public void alfheim$initNeighborLightChecks() {
|
||||
if (alfheim$getNeighborLightChecks() == null)
|
||||
alfheim$setNeighborLightChecks(new short[32]);
|
||||
}
|
||||
|
||||
public byte alfheim$getCachedLightFor(final EnumSkyBlock lightType, final BlockPos blockPos) {
|
||||
final int x = blockPos.getX() & 15;
|
||||
final int y = blockPos.getY();
|
||||
final int z = blockPos.getZ() & 15;
|
||||
|
||||
final ExtendedBlockStorage extendedblockstorage = storageArrays[y >> 4];
|
||||
|
||||
if (extendedblockstorage == Chunk.NULL_BLOCK_STORAGE)
|
||||
return canSeeSky(blockPos) ? (byte) lightType.defaultLightValue : 0;
|
||||
else if (lightType == EnumSkyBlock.SKY)
|
||||
return !worldObj.provider.getHasNoSky() ? (byte) extendedblockstorage.getExtSkylightValue(x, y & 15, z) : 0;
|
||||
else
|
||||
return lightType == EnumSkyBlock.BLOCK ? (byte) extendedblockstorage.getExtBlocklightValue(x, y & 15, z) : (byte) lightType.defaultLightValue;
|
||||
}
|
||||
}
|
|
@ -41,6 +41,8 @@ public interface IChunkProvider {
|
|||
*/
|
||||
Chunk provideChunk(int var1, int var2);
|
||||
|
||||
Chunk getLoadedChunk(int var1, int var2);
|
||||
|
||||
/**+
|
||||
* Will return back a chunk, if it doesn't exist and its not a
|
||||
* MP client it will generates all the blocks for the specified
|
||||
|
|
|
@ -6,6 +6,7 @@ import net.minecraft.entity.Entity;
|
|||
import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.nbt.NBTTagShort;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
@ -13,6 +14,7 @@ import net.minecraft.world.NextTickListEntry;
|
|||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.NibbleArray;
|
||||
import net.hoosiertransfer.Alfheim.IChunkLightingData;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
||||
|
@ -38,6 +40,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
|||
*/
|
||||
public abstract class AnvilChunkLoader implements IChunkLoader {
|
||||
private static final Logger logger = LogManager.getLogger("AnvilChunkLoader");
|
||||
private static final String NEIGHBOR_LIGHT_CHECKS_KEY = "NeighborLightChecks";
|
||||
|
||||
/**+
|
||||
* Wraps readChunkFromNBT. Checks the coordinates and several
|
||||
|
@ -73,6 +76,9 @@ public abstract class AnvilChunkLoader implements IChunkLoader {
|
|||
* last update time.
|
||||
*/
|
||||
protected void writeChunkToNBT(Chunk chunkIn, World worldIn, NBTTagCompound parNBTTagCompound) {
|
||||
alfheim$writeNeighborLightChecksToNBT(chunkIn, parNBTTagCompound);
|
||||
parNBTTagCompound.setBoolean("LightPopulated", chunkIn.alfheim$isLightInitialized());
|
||||
|
||||
parNBTTagCompound.setByte("V", (byte) 1);
|
||||
parNBTTagCompound.setInteger("xPos", chunkIn.xPosition);
|
||||
parNBTTagCompound.setInteger("zPos", chunkIn.zPosition);
|
||||
|
@ -285,6 +291,48 @@ public abstract class AnvilChunkLoader implements IChunkLoader {
|
|||
}
|
||||
}
|
||||
|
||||
alfheim$readNeighborLightChecksFromNBT(chunk, parNBTTagCompound);
|
||||
|
||||
chunk.alfheim$setLightInitialized(parNBTTagCompound.getBoolean("LightPopulated"));
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private static void alfheim$readNeighborLightChecksFromNBT(final Chunk chunk, final NBTTagCompound compound) {
|
||||
if (!compound.hasKey(NEIGHBOR_LIGHT_CHECKS_KEY, 9))
|
||||
return;
|
||||
|
||||
final NBTTagList tagList = compound.getTagList(NEIGHBOR_LIGHT_CHECKS_KEY, 2);
|
||||
|
||||
if (tagList.tagCount() != 32) {
|
||||
return;
|
||||
}
|
||||
|
||||
chunk.alfheim$initNeighborLightChecks();
|
||||
|
||||
final short[] neighborLightChecks = chunk.alfheim$getNeighborLightChecks();
|
||||
|
||||
for (int i = 0; i < 32; ++i)
|
||||
neighborLightChecks[i] = ((NBTTagShort) tagList.get(i)).getShort();
|
||||
}
|
||||
|
||||
private static void alfheim$writeNeighborLightChecksToNBT(final Chunk chunk, final NBTTagCompound compound) {
|
||||
final short[] neighborLightChecks = chunk.alfheim$getNeighborLightChecks();
|
||||
|
||||
if (neighborLightChecks == null)
|
||||
return;
|
||||
|
||||
boolean empty = true;
|
||||
|
||||
final NBTTagList list = new NBTTagList();
|
||||
|
||||
for (final short flags : neighborLightChecks) {
|
||||
list.appendTag(new NBTTagShort(flags));
|
||||
|
||||
if (flags != 0)
|
||||
empty = false;
|
||||
}
|
||||
|
||||
if (!empty)
|
||||
compound.setTag(NEIGHBOR_LIGHT_CHECKS_KEY, list);
|
||||
}
|
||||
}
|
|
@ -45,6 +45,8 @@ public class ChunkProviderDebug implements IChunkProvider {
|
|||
this.world = worldIn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**+
|
||||
* Will return back a chunk, if it doesn't exist and its not a
|
||||
* MP client it will generates all the blocks for the specified
|
||||
|
@ -79,6 +81,10 @@ public class ChunkProviderDebug implements IChunkProvider {
|
|||
return chunk;
|
||||
}
|
||||
|
||||
public Chunk getLoadedChunk(int parInt1, int parInt2) {
|
||||
return this.provideChunk(parInt1, parInt2);
|
||||
}
|
||||
|
||||
public static IBlockState func_177461_b(int parInt1, int parInt2) {
|
||||
IBlockState iblockstate = null;
|
||||
if (parInt1 > 0 && parInt2 > 0 && parInt1 % 2 != 0 && parInt2 % 2 != 0) {
|
||||
|
|
|
@ -181,6 +181,10 @@ public class ChunkProviderEnd implements IChunkProvider {
|
|||
return chunk;
|
||||
}
|
||||
|
||||
public Chunk getLoadedChunk(int parInt1, int parInt2) {
|
||||
return this.provideChunk(parInt1, parInt2);
|
||||
}
|
||||
|
||||
/**+
|
||||
* generates a subset of the level's terrain data. Takes 7
|
||||
* arguments: the [empty] noise array, the position, and the
|
||||
|
|
|
@ -157,6 +157,10 @@ public class ChunkProviderFlat implements IChunkProvider {
|
|||
return chunk;
|
||||
}
|
||||
|
||||
public Chunk getLoadedChunk(int var1, int var2) {
|
||||
return this.provideChunk(var1, var2);
|
||||
}
|
||||
|
||||
/**+
|
||||
* Checks to see if a chunk exists at x, z
|
||||
*/
|
||||
|
|
|
@ -247,6 +247,10 @@ public class ChunkProviderGenerate implements IChunkProvider {
|
|||
return chunk;
|
||||
}
|
||||
|
||||
public Chunk getLoadedChunk(int var1, int var2) {
|
||||
return this.provideChunk(var1, var2);
|
||||
}
|
||||
|
||||
private void func_147423_a(int parInt1, int parInt2, int parInt3) {
|
||||
this.field_147426_g = this.noiseGen6.generateNoiseOctaves(this.field_147426_g, parInt1, parInt3, 5, 5,
|
||||
(double) this.settings.depthNoiseScaleX, (double) this.settings.depthNoiseScaleZ,
|
||||
|
|
|
@ -264,6 +264,10 @@ public class ChunkProviderHell implements IChunkProvider {
|
|||
return chunk;
|
||||
}
|
||||
|
||||
public Chunk getLoadedChunk(int i, int j) {
|
||||
return this.provideChunk(i, j);
|
||||
}
|
||||
|
||||
/**+
|
||||
* generates a subset of the level's terrain data. Takes 7
|
||||
* arguments: the [empty] noise array, the position, and the
|
||||
|
|
|
@ -24,6 +24,7 @@ import net.minecraft.world.chunk.Chunk;
|
|||
import net.minecraft.world.chunk.EmptyChunk;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
import net.minecraft.world.chunk.storage.IChunkLoader;
|
||||
import net.hoosiertransfer.Alfheim.ILightingEngineProvider;
|
||||
import net.lax1dude.eaglercraft.v1_8.HString;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
|
@ -157,6 +158,10 @@ public class ChunkProviderServer implements IChunkProvider {
|
|||
: this.loadChunk(i, j)) : chunk;
|
||||
}
|
||||
|
||||
public Chunk getLoadedChunk(int i, int j) {
|
||||
return (Chunk) this.id2ChunkMap.getValueByKey(ChunkCoordIntPair.chunkXZ2Int(i, j));
|
||||
}
|
||||
|
||||
private Chunk loadChunkFromFile(int x, int z) {
|
||||
if (this.chunkLoader == null) {
|
||||
return null;
|
||||
|
@ -211,7 +216,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
|||
public void populate(IChunkProvider ichunkprovider, int i, int j) {
|
||||
Chunk chunk = this.provideChunk(i, j);
|
||||
if (!chunk.isTerrainPopulated()) {
|
||||
chunk.func_150809_p();
|
||||
chunk.checkLight();
|
||||
if (this.serverChunkGenerator != null) {
|
||||
this.serverChunkGenerator.populate(ichunkprovider, i, j);
|
||||
chunk.setChunkModified();
|
||||
|
@ -236,6 +241,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
|||
* if all chunks have been saved.
|
||||
*/
|
||||
public boolean saveChunks(boolean flag, IProgressUpdate var2) {
|
||||
worldObj.alfheim$getLightingEngine().processLightUpdates();
|
||||
int i = 0;
|
||||
ArrayList arraylist = Lists.newArrayList(this.loadedChunks);
|
||||
|
||||
|
@ -278,6 +284,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
|||
if (!this.worldObj.disableLevelSaving) {
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
if (!this.droppedChunksSet.isEmpty()) {
|
||||
//!!! i probably should do a ((ILightingEngineProvider) world).alfheim$getLightingEngine().processLightUpdates(); here
|
||||
Long olong = (Long) this.droppedChunksSet.iterator().next();
|
||||
Chunk chunk = (Chunk) this.id2ChunkMap.getValueByKey(olong.longValue());
|
||||
if (chunk != null) {
|
||||
|
|
Loading…
Reference in New Issue