cleanup
This commit is contained in:
parent
c126bdd8b0
commit
318a8885ba
53 changed files with 990 additions and 5887 deletions
|
@ -23,10 +23,6 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
@ -120,10 +116,6 @@ import common.entity.npc.EntityNPC;
|
|||
import common.entity.npc.EntityWaterNPC;
|
||||
import common.entity.npc.PlayerCharacter;
|
||||
import common.entity.types.EntityLiving;
|
||||
import common.future.Futures;
|
||||
import common.future.ListenableFuture;
|
||||
import common.future.ListenableFutureTask;
|
||||
import common.future.ThreadFactoryBuilder;
|
||||
import common.init.BlockRegistry;
|
||||
import common.init.Blocks;
|
||||
import common.init.EntityRegistry;
|
||||
|
@ -171,7 +163,6 @@ import common.util.CharValidator;
|
|||
import common.util.ExtMath;
|
||||
import common.util.Facing;
|
||||
import common.util.HitPosition;
|
||||
import common.util.LazyLoader;
|
||||
import common.util.Util;
|
||||
import common.util.Var;
|
||||
import common.util.HitPosition.ObjectType;
|
||||
|
@ -281,15 +272,11 @@ public class Client implements IThreadListener {
|
|||
public static final int LOG_BUFFER = 32768;
|
||||
public static final int MIN_WIDTH = 800;
|
||||
public static final int MIN_HEIGHT = 450;
|
||||
private static final LazyLoader<NioEventLoopGroup> CLIENT_NIO_EVENTLOOP = new LazyLoader<NioEventLoopGroup>() {
|
||||
protected NioEventLoopGroup load() {
|
||||
return new NioEventLoopGroup(0, new ThreadFactoryBuilder().setNameFormat("Netty Client IO #%d").setDaemon(true).build());
|
||||
}
|
||||
};
|
||||
|
||||
private final Queue<FutureTask<?>> tasks = new ArrayDeque<FutureTask<?>>();
|
||||
|
||||
private final Thread thread = Thread.currentThread();
|
||||
private final NioEventLoopGroup eventGroup = new NioEventLoopGroup(0, Util.getThreadFactory("Netty Client IO"));
|
||||
private final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
|
||||
private final Map<Integer, Long> bars = Maps.newTreeMap();
|
||||
private final Thread clThread = Thread.currentThread();
|
||||
private final Map<String, CVar> cvars = Maps.newTreeMap();
|
||||
private final Map<String, Field> synced = Maps.newTreeMap();
|
||||
private final Map<Keysym, DebugFunction> debug = Maps.newTreeMap();
|
||||
|
@ -537,7 +524,7 @@ public class Client implements IThreadListener {
|
|||
|
||||
private NetConnection connect(InetAddress address, int port) {
|
||||
final NetConnection connection = new NetConnection();
|
||||
new Bootstrap().group(CLIENT_NIO_EVENTLOOP.getValue()).handler(new ChannelInitializer<Channel>() {
|
||||
new Bootstrap().group(this.eventGroup).handler(new ChannelInitializer<Channel>() {
|
||||
protected void initChannel(Channel channel) throws Exception {
|
||||
try {
|
||||
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
|
||||
|
@ -708,17 +695,13 @@ public class Client implements IThreadListener {
|
|||
{
|
||||
while (!this.tasks.isEmpty())
|
||||
{
|
||||
FutureTask<?> task = this.tasks.poll();
|
||||
Runnable task = this.tasks.poll();
|
||||
try {
|
||||
task.run();
|
||||
task.get();
|
||||
}
|
||||
catch(ExecutionException e1) {
|
||||
if(!(e1.getCause() instanceof ThreadQuickExitException))
|
||||
Log.SYSTEM.error(e1, "Fehler beim Ausführen von Render-Task " + task);
|
||||
}
|
||||
catch(InterruptedException e2) {
|
||||
Log.SYSTEM.error(e2, "Fehler beim Ausführen von Render-Task " + task);
|
||||
catch(Throwable e) {
|
||||
if(!(e instanceof ThreadQuickExitException))
|
||||
Log.SYSTEM.error(e, "Fehler beim Ausführen von Render-Task " + task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1605,40 +1588,25 @@ public class Client implements IThreadListener {
|
|||
this.viewEntity = viewingEntity;
|
||||
}
|
||||
|
||||
private <V> ListenableFuture<V> addScheduledTask(Callable<V> callableToSchedule)
|
||||
{
|
||||
if (!this.isMainThread())
|
||||
{
|
||||
ListenableFutureTask<V> listenablefuturetask = ListenableFutureTask.<V>create(callableToSchedule);
|
||||
|
||||
synchronized (this.tasks)
|
||||
{
|
||||
this.tasks.add(listenablefuturetask);
|
||||
return listenablefuturetask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
return Futures.<V>immediateFuture(callableToSchedule.call());
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.SYSTEM.error(exception, "Fehler beim sofortigen Ausführen von Render-Task " + callableToSchedule);
|
||||
return Futures.immediateFailedFuture(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ListenableFuture<Object> schedule(Runnable runnableToSchedule)
|
||||
{
|
||||
return this.<Object>addScheduledTask(Executors.callable(runnableToSchedule));
|
||||
}
|
||||
public void schedule(Runnable task) {
|
||||
if(!this.isMainThread()) {
|
||||
synchronized(this.tasks) {
|
||||
this.tasks.add(task);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
task.run();
|
||||
}
|
||||
catch(Throwable e) {
|
||||
Log.SYSTEM.error(e, "Fehler beim sofortigen Ausführen von Render-Task " + task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMainThread()
|
||||
{
|
||||
return Thread.currentThread() == this.clThread;
|
||||
return Thread.currentThread() == this.thread;
|
||||
}
|
||||
|
||||
public BlockRenderer getBlockRendererDispatcher()
|
||||
|
|
|
@ -27,7 +27,7 @@ public class GuiInfo extends Gui {
|
|||
"Albert Pham - WorldEdit (Snippets)",
|
||||
"Joonas Vali - NameGenerator",
|
||||
"LWJGL 2.9.4-nightly-20150209 - Project, Vector*, Matrix*",
|
||||
"Guava 17.0 - collect, future, Predicates",
|
||||
"Guava 17.0 - collect, Predicates",
|
||||
"Netty 4.0.23-Final - net.*",
|
||||
"JOrbis 20101023 (JCraft) - jogg, jorbis, CodecJOrbis"
|
||||
};
|
||||
|
|
595
client/src/main/java/client/renderer/chunk/ChunkBuilder.java
Normal file
595
client/src/main/java/client/renderer/chunk/ChunkBuilder.java
Normal file
|
@ -0,0 +1,595 @@
|
|||
package client.renderer.chunk;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.AbstractExecutorService;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import common.collect.ImmutableList;
|
||||
import common.collect.Sets;
|
||||
import common.log.Log;
|
||||
|
||||
public abstract class ChunkBuilder {
|
||||
public static interface ListenableFuture<V> extends Future<V> {
|
||||
void addListener(Runnable listener, Executor executor);
|
||||
}
|
||||
|
||||
public static class ImmediateFuture implements ListenableFuture<Object> {
|
||||
public void addListener(Runnable listener, Executor executor) {
|
||||
try {
|
||||
executor.execute(listener);
|
||||
}
|
||||
catch(RuntimeException e) {
|
||||
Log.SYSTEM.error(e, "Fehler beim Ausführen von " + listener + " mit " + executor);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object get() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object get(long timeout, TimeUnit unit) throws ExecutionException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SameThreadExecutorService extends AbstractExecutorService implements ExecutorService {
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Condition termination = lock.newCondition();
|
||||
|
||||
private int runningTasks = 0;
|
||||
private boolean shutdown = false;
|
||||
|
||||
public void execute(Runnable command) {
|
||||
startTask();
|
||||
try {
|
||||
command.run();
|
||||
}
|
||||
finally {
|
||||
endTask();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isShutdown() {
|
||||
lock.lock();
|
||||
try {
|
||||
return shutdown;
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
lock.lock();
|
||||
try {
|
||||
shutdown = true;
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Runnable> shutdownNow() {
|
||||
shutdown();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public boolean isTerminated() {
|
||||
lock.lock();
|
||||
try {
|
||||
return shutdown && runningTasks == 0;
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
|
||||
long nanos = unit.toNanos(timeout);
|
||||
lock.lock();
|
||||
try {
|
||||
for(;;) {
|
||||
if(isTerminated()) {
|
||||
return true;
|
||||
}
|
||||
else if(nanos <= 0) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
nanos = termination.awaitNanos(nanos);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void startTask() {
|
||||
lock.lock();
|
||||
try {
|
||||
if(isShutdown()) {
|
||||
throw new RejectedExecutionException("Executor already shutdown");
|
||||
}
|
||||
runningTasks++;
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void endTask() {
|
||||
lock.lock();
|
||||
try {
|
||||
runningTasks--;
|
||||
if(isTerminated()) {
|
||||
termination.signalAll();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected final <T> ListenableFutureTask<T> newTaskFor(Runnable runnable, T value) {
|
||||
return ListenableFutureTask.create(runnable, value);
|
||||
}
|
||||
|
||||
protected final <T> ListenableFutureTask<T> newTaskFor(Callable<T> callable) {
|
||||
return ListenableFutureTask.create(callable);
|
||||
}
|
||||
|
||||
public ListenableFuture<?> submit(Runnable task) {
|
||||
return (ListenableFuture<?>)super.submit(task);
|
||||
}
|
||||
|
||||
public <T> ListenableFuture<T> submit(Runnable task, T result) {
|
||||
return (ListenableFuture<T>)super.submit(task, result);
|
||||
}
|
||||
|
||||
public <T> ListenableFuture<T> submit(Callable<T> task) {
|
||||
return (ListenableFuture<T>)super.submit(task);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ExecutionList {
|
||||
private RunnableExecutorPair runnables;
|
||||
private boolean executed;
|
||||
|
||||
public void add(Runnable runnable, Executor executor) {
|
||||
synchronized(this) {
|
||||
if(!executed) {
|
||||
runnables = new RunnableExecutorPair(runnable, executor, runnables);
|
||||
return;
|
||||
}
|
||||
}
|
||||
executeListener(runnable, executor);
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
RunnableExecutorPair list;
|
||||
synchronized(this) {
|
||||
if(executed) {
|
||||
return;
|
||||
}
|
||||
executed = true;
|
||||
list = runnables;
|
||||
runnables = null;
|
||||
}
|
||||
RunnableExecutorPair reversedList = null;
|
||||
while(list != null) {
|
||||
RunnableExecutorPair tmp = list;
|
||||
list = list.next;
|
||||
tmp.next = reversedList;
|
||||
reversedList = tmp;
|
||||
}
|
||||
while(reversedList != null) {
|
||||
executeListener(reversedList.runnable, reversedList.executor);
|
||||
reversedList = reversedList.next;
|
||||
}
|
||||
}
|
||||
|
||||
private static void executeListener(Runnable runnable, Executor executor) {
|
||||
try {
|
||||
executor.execute(runnable);
|
||||
}
|
||||
catch(RuntimeException e) {
|
||||
Log.SYSTEM.error(e, "Fehler beim Ausführen von " + runnable + " mit " + executor);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class RunnableExecutorPair {
|
||||
final Runnable runnable;
|
||||
final Executor executor;
|
||||
RunnableExecutorPair next;
|
||||
|
||||
RunnableExecutorPair(Runnable runnable, Executor executor, RunnableExecutorPair next) {
|
||||
this.runnable = runnable;
|
||||
this.executor = executor;
|
||||
this.next = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ListenableFutureTask<V> extends FutureTask<V> implements ListenableFuture<V> {
|
||||
private final ExecutionList executionList = new ExecutionList();
|
||||
|
||||
public static <V> ListenableFutureTask<V> create(Callable<V> callable) {
|
||||
return new ListenableFutureTask<V>(callable);
|
||||
}
|
||||
|
||||
public static <V> ListenableFutureTask<V> create(Runnable runnable, V result) {
|
||||
return new ListenableFutureTask<V>(runnable, result);
|
||||
}
|
||||
|
||||
ListenableFutureTask(Callable<V> callable) {
|
||||
super(callable);
|
||||
}
|
||||
|
||||
ListenableFutureTask(Runnable runnable, V result) {
|
||||
super(runnable, result);
|
||||
}
|
||||
|
||||
public void addListener(Runnable listener, Executor exec) {
|
||||
executionList.add(listener, exec);
|
||||
}
|
||||
|
||||
protected void done() {
|
||||
executionList.execute();
|
||||
}
|
||||
}
|
||||
|
||||
public static void addCallback(List<ListenableFuture<Object>> futures, final ChunkCompileTaskGenerator generator, final CompiledChunk compiled, final ChunkRenderWorker worker) {
|
||||
final CombinedFuture future = new CombinedFuture(ImmutableList.copyOf(futures));
|
||||
generator.addFinishRunnable(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
future.cancel(false);
|
||||
}
|
||||
});
|
||||
Runnable listener = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
boolean interrupted = false;
|
||||
try {
|
||||
while(true) {
|
||||
try {
|
||||
future.get();
|
||||
break;
|
||||
}
|
||||
catch(InterruptedException e) {
|
||||
interrupted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if(interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(ExecutionException e) {
|
||||
if (!(e.getCause() instanceof CancellationException) && !(e.getCause() instanceof InterruptedException))
|
||||
Log.RENDER.error(e.getCause(), "Fehler beim Rendern des Chunks");
|
||||
worker.freeRenderBuilder(generator);
|
||||
return;
|
||||
}
|
||||
catch(RuntimeException e) {
|
||||
if (!(e instanceof CancellationException))
|
||||
Log.RENDER.error(e, "Fehler beim Rendern des Chunks");
|
||||
worker.freeRenderBuilder(generator);
|
||||
return;
|
||||
}
|
||||
catch(Error e) {
|
||||
Log.RENDER.error(e, "Fehler beim Rendern des Chunks");
|
||||
worker.freeRenderBuilder(generator);
|
||||
return;
|
||||
}
|
||||
worker.setRenderBuilderChunk(generator, compiled);
|
||||
}
|
||||
};
|
||||
future.addListener(listener, new SameThreadExecutorService());
|
||||
}
|
||||
|
||||
private static <V> V getUninterruptibly(Future<V> future) throws ExecutionException {
|
||||
boolean interrupted = false;
|
||||
try {
|
||||
while(true) {
|
||||
try {
|
||||
return future.get();
|
||||
}
|
||||
catch(InterruptedException e) {
|
||||
interrupted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if(interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CombinedFuture {
|
||||
private final Sync sync = new Sync();
|
||||
private final ExecutionList executionList = new ExecutionList();
|
||||
ImmutableList<? extends ListenableFuture<Object>> futures;
|
||||
final AtomicInteger remaining;
|
||||
final Object seenExceptionsLock = new Object();
|
||||
boolean active = true;
|
||||
Set<Throwable> seenExceptions;
|
||||
|
||||
CombinedFuture(ImmutableList<ListenableFuture<Object>> futures) {
|
||||
this.futures = futures;
|
||||
this.remaining = new AtomicInteger(futures.size());
|
||||
init();
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
addListener(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(CombinedFuture.this.isCancelled()) {
|
||||
for(ListenableFuture<?> future : CombinedFuture.this.futures) {
|
||||
future.cancel(CombinedFuture.this.wasInterrupted());
|
||||
}
|
||||
}
|
||||
|
||||
CombinedFuture.this.futures = null;
|
||||
CombinedFuture.this.active = false;
|
||||
}
|
||||
}, new SameThreadExecutorService());
|
||||
|
||||
if(futures.isEmpty()) {
|
||||
set();
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for(final ListenableFuture<Object> listenable : futures) {
|
||||
final int index = i++;
|
||||
listenable.addListener(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setOneValue(index, listenable);
|
||||
}
|
||||
}, new SameThreadExecutorService());
|
||||
}
|
||||
}
|
||||
|
||||
private void setExceptionAndMaybeLog(Throwable throwable) {
|
||||
boolean visibleFromOutputFuture = false;
|
||||
boolean firstTimeSeeingThisException = true;
|
||||
if(true) {
|
||||
visibleFromOutputFuture = this.setException(throwable);
|
||||
|
||||
synchronized(seenExceptionsLock) {
|
||||
if(seenExceptions == null) {
|
||||
seenExceptions = Sets.newHashSet();
|
||||
}
|
||||
firstTimeSeeingThisException = seenExceptions.add(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
if(throwable instanceof Error || (true && !visibleFromOutputFuture && firstTimeSeeingThisException)) {
|
||||
Log.SYSTEM.error(throwable, "Aufgabe fehlgeschlagen");
|
||||
}
|
||||
}
|
||||
|
||||
private void setOneValue(int index, Future<Object> future) {
|
||||
boolean wasActive = active;
|
||||
if(isDone() || !wasActive)
|
||||
checkState(true, "Future was done before all dependencies completed");
|
||||
|
||||
try {
|
||||
checkState(future.isDone(), "Tried to set value from future which is not done");
|
||||
Object returnValue = getUninterruptibly(future);
|
||||
}
|
||||
catch(CancellationException e) {
|
||||
if(true) {
|
||||
cancel(false);
|
||||
}
|
||||
}
|
||||
catch(ExecutionException e) {
|
||||
setExceptionAndMaybeLog(e.getCause());
|
||||
}
|
||||
catch(Throwable t) {
|
||||
setExceptionAndMaybeLog(t);
|
||||
}
|
||||
finally {
|
||||
int newRemaining = remaining.decrementAndGet();
|
||||
checkState(newRemaining >= 0, "Less than 0 remaining futures");
|
||||
if(newRemaining == 0) {
|
||||
if(wasActive) {
|
||||
set();
|
||||
}
|
||||
else {
|
||||
checkState(isDone(), "Future is not done");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void get() throws InterruptedException, ExecutionException {
|
||||
sync.get();
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return sync.isDone();
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return sync.isCancelled();
|
||||
}
|
||||
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
if(!sync.cancel(mayInterruptIfRunning)) {
|
||||
return false;
|
||||
}
|
||||
executionList.execute();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected final boolean wasInterrupted() {
|
||||
return sync.wasInterrupted();
|
||||
}
|
||||
|
||||
public void addListener(Runnable listener, Executor exec) {
|
||||
executionList.add(listener, exec);
|
||||
}
|
||||
|
||||
protected boolean set() {
|
||||
boolean result = sync.set();
|
||||
if(result) {
|
||||
executionList.execute();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean setException(Throwable throwable) {
|
||||
boolean result = sync.setException(throwable);
|
||||
if(result) {
|
||||
executionList.execute();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static final class Sync extends AbstractQueuedSynchronizer {
|
||||
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
static final int RUNNING = 0;
|
||||
static final int COMPLETING = 1;
|
||||
static final int COMPLETED = 2;
|
||||
static final int CANCELLED = 4;
|
||||
static final int INTERRUPTED = 8;
|
||||
|
||||
private Throwable exception;
|
||||
|
||||
protected int tryAcquireShared(int ignored) {
|
||||
if(isDone()) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected boolean tryReleaseShared(int finalState) {
|
||||
setState(finalState);
|
||||
return true;
|
||||
}
|
||||
|
||||
void get(long nanos) throws TimeoutException, CancellationException, ExecutionException, InterruptedException {
|
||||
|
||||
if(!tryAcquireSharedNanos(-1, nanos)) {
|
||||
throw new TimeoutException("Timeout waiting for task.");
|
||||
}
|
||||
|
||||
getValue();
|
||||
}
|
||||
|
||||
void get() throws CancellationException, ExecutionException, InterruptedException {
|
||||
|
||||
acquireSharedInterruptibly(-1);
|
||||
getValue();
|
||||
}
|
||||
|
||||
private void getValue() throws CancellationException, ExecutionException {
|
||||
int state = getState();
|
||||
switch(state) {
|
||||
case COMPLETED:
|
||||
if(exception != null) {
|
||||
throw new ExecutionException(exception);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
case CANCELLED:
|
||||
case INTERRUPTED:
|
||||
throw cancellationExceptionWithCause("Task was cancelled.", exception);
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Error, synchronizer in invalid state: " + state);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isDone() {
|
||||
return (getState() & (COMPLETED | CANCELLED | INTERRUPTED)) != 0;
|
||||
}
|
||||
|
||||
boolean isCancelled() {
|
||||
return (getState() & (CANCELLED | INTERRUPTED)) != 0;
|
||||
}
|
||||
|
||||
boolean wasInterrupted() {
|
||||
return getState() == INTERRUPTED;
|
||||
}
|
||||
|
||||
boolean set() {
|
||||
return complete(null, COMPLETED);
|
||||
}
|
||||
|
||||
boolean setException(Throwable t) {
|
||||
return complete(t, COMPLETED);
|
||||
}
|
||||
|
||||
boolean cancel(boolean interrupt) {
|
||||
return complete(null, interrupt ? INTERRUPTED : CANCELLED);
|
||||
}
|
||||
|
||||
private boolean complete(Throwable t, int finalState) {
|
||||
boolean doCompletion = compareAndSetState(RUNNING, COMPLETING);
|
||||
if(doCompletion) {
|
||||
this.exception = ((finalState & (CANCELLED | INTERRUPTED)) != 0) ? new CancellationException("Future.cancel() was called.") : t;
|
||||
releaseShared(finalState);
|
||||
}
|
||||
else if(getState() == COMPLETING) {
|
||||
acquireShared(-1);
|
||||
}
|
||||
return doCompletion;
|
||||
}
|
||||
}
|
||||
|
||||
static final CancellationException cancellationExceptionWithCause(String message, Throwable cause) {
|
||||
CancellationException exception = new CancellationException(message);
|
||||
exception.initCause(cause);
|
||||
return exception;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void checkState(boolean expression, String errorMessage) {
|
||||
if(!expression) {
|
||||
throw new IllegalStateException(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,22 +5,18 @@ import java.util.List;
|
|||
import java.util.Queue;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import client.Client;
|
||||
import client.renderer.RegionRenderCacheBuilder;
|
||||
import client.renderer.RenderBuffer;
|
||||
import client.renderer.VertexBuffer;
|
||||
import client.renderer.chunk.ChunkBuilder.ImmediateFuture;
|
||||
import client.renderer.chunk.ChunkBuilder.ListenableFuture;
|
||||
import client.renderer.chunk.ChunkBuilder.ListenableFutureTask;
|
||||
import common.collect.Lists;
|
||||
import common.future.Futures;
|
||||
import common.future.ListenableFuture;
|
||||
import common.future.ListenableFutureTask;
|
||||
import common.future.ThreadFactoryBuilder;
|
||||
import common.model.BlockLayer;
|
||||
|
||||
public class ChunkRenderDispatcher
|
||||
{
|
||||
private static final ThreadFactory threadFactory = (new ThreadFactoryBuilder()).setNameFormat("Chunk Batcher %d").setDaemon(true).build();
|
||||
private final List<ChunkRenderWorker> listThreadedWorkers = Lists.<ChunkRenderWorker>newArrayList();
|
||||
private final BlockingQueue<ChunkCompileTaskGenerator> queueChunkUpdates = new ArrayBlockingQueue<ChunkCompileTaskGenerator>(100);
|
||||
private final BlockingQueue<RegionRenderCacheBuilder> queueFreeRenderBuilders = new ArrayBlockingQueue<RegionRenderCacheBuilder>(5);
|
||||
|
@ -34,7 +30,8 @@ public class ChunkRenderDispatcher
|
|||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
ChunkRenderWorker chunkrenderworker = new ChunkRenderWorker(this);
|
||||
Thread thread = threadFactory.newThread(chunkrenderworker);
|
||||
Thread thread = new Thread(chunkrenderworker, "Chunk Batcher #" + (i + 1));
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
this.listThreadedWorkers.add(chunkrenderworker);
|
||||
}
|
||||
|
@ -225,15 +222,15 @@ public class ChunkRenderDispatcher
|
|||
return flag;
|
||||
}
|
||||
|
||||
public ListenableFuture<Object> uploadChunk(final BlockLayer player, final RenderBuffer p_178503_2_, final RenderChunk chunkRenderer, final CompiledChunk compiledChunkIn)
|
||||
public ListenableFuture<Object> uploadChunk(final BlockLayer layer, final RenderBuffer buf, final RenderChunk renderer, final CompiledChunk compiled)
|
||||
{
|
||||
if (Client.CLIENT.isMainThread())
|
||||
{
|
||||
p_178503_2_.reset();
|
||||
chunkRenderer.getVertexBufferByLayer(player.ordinal()).bufferData(p_178503_2_.getByteBuffer());
|
||||
buf.reset();
|
||||
renderer.getVertexBufferByLayer(layer.ordinal()).bufferData(buf.getByteBuffer());
|
||||
|
||||
p_178503_2_.setTranslation(0.0D, 0.0D, 0.0D);
|
||||
return Futures.<Object>immediateFuture((Object)null);
|
||||
buf.setTranslation(0.0D, 0.0D, 0.0D);
|
||||
return new ImmediateFuture();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -241,7 +238,7 @@ public class ChunkRenderDispatcher
|
|||
{
|
||||
public void run()
|
||||
{
|
||||
ChunkRenderDispatcher.this.uploadChunk(player, p_178503_2_, chunkRenderer, compiledChunkIn);
|
||||
ChunkRenderDispatcher.this.uploadChunk(layer, buf, renderer, compiled);
|
||||
}
|
||||
}, (Object)null);
|
||||
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
package client.renderer.chunk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
import client.Client;
|
||||
import client.renderer.RegionRenderCacheBuilder;
|
||||
import client.renderer.chunk.ChunkBuilder.ListenableFuture;
|
||||
import common.collect.Lists;
|
||||
import common.entity.Entity;
|
||||
import common.future.FutureCallback;
|
||||
import common.future.Futures;
|
||||
import common.future.ListenableFuture;
|
||||
import common.log.Log;
|
||||
import common.model.BlockLayer;
|
||||
|
||||
|
@ -120,72 +115,25 @@ public class ChunkRenderWorker implements Runnable
|
|||
generator.getLock().unlock();
|
||||
}
|
||||
|
||||
final CompiledChunk lvt_7_1_ = generator.getCompiledChunk();
|
||||
ArrayList lvt_8_1_ = Lists.newArrayList();
|
||||
final CompiledChunk compiled = generator.getCompiledChunk();
|
||||
List<ListenableFuture<Object>> list = Lists.newArrayList();
|
||||
|
||||
if (chunkcompiletaskgenerator$type == ChunkCompileTaskGenerator.Type.REBUILD_CHUNK)
|
||||
{
|
||||
for (BlockLayer enumworldblocklayer : BlockLayer.values())
|
||||
{
|
||||
if (lvt_7_1_.isLayerStarted(enumworldblocklayer))
|
||||
if (compiled.isLayerStarted(enumworldblocklayer))
|
||||
{
|
||||
lvt_8_1_.add(this.chunkRenderDispatcher.uploadChunk(enumworldblocklayer, generator.getRegionRenderCacheBuilder().getWorldRendererByLayer(enumworldblocklayer), generator.getRenderChunk(), lvt_7_1_));
|
||||
list.add(this.chunkRenderDispatcher.uploadChunk(enumworldblocklayer, generator.getRegionRenderCacheBuilder().getWorldRendererByLayer(enumworldblocklayer), generator.getRenderChunk(), compiled));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (chunkcompiletaskgenerator$type == ChunkCompileTaskGenerator.Type.RESORT_TRANSPARENCY)
|
||||
{
|
||||
lvt_8_1_.add(this.chunkRenderDispatcher.uploadChunk(BlockLayer.TRANSLUCENT, generator.getRegionRenderCacheBuilder().getWorldRendererByLayer(BlockLayer.TRANSLUCENT), generator.getRenderChunk(), lvt_7_1_));
|
||||
list.add(this.chunkRenderDispatcher.uploadChunk(BlockLayer.TRANSLUCENT, generator.getRegionRenderCacheBuilder().getWorldRendererByLayer(BlockLayer.TRANSLUCENT), generator.getRenderChunk(), compiled));
|
||||
}
|
||||
|
||||
final ListenableFuture<List<Object>> listenablefuture = Futures.allAsList(lvt_8_1_);
|
||||
generator.addFinishRunnable(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
listenablefuture.cancel(false);
|
||||
}
|
||||
});
|
||||
Futures.addCallback(listenablefuture, new FutureCallback<List<Object>>()
|
||||
{
|
||||
public void onSuccess(List<Object> p_onSuccess_1_)
|
||||
{
|
||||
ChunkRenderWorker.this.freeRenderBuilder(generator);
|
||||
generator.getLock().lock();
|
||||
label21:
|
||||
{
|
||||
try
|
||||
{
|
||||
if (generator.getStatus() == ChunkCompileTaskGenerator.Status.UPLOADING)
|
||||
{
|
||||
generator.setStatus(ChunkCompileTaskGenerator.Status.DONE);
|
||||
break label21;
|
||||
}
|
||||
|
||||
if (!generator.isFinished())
|
||||
{
|
||||
Log.RENDER.warn("Chunk-Rendering-Aufgabe war " + generator.getStatus() + " wenn UPLOADING erwartet war; breche Aufgabe ab");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
generator.getLock().unlock();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
generator.getRenderChunk().setCompiledChunk(lvt_7_1_);
|
||||
}
|
||||
public void onFailure(Throwable p_onFailure_1_)
|
||||
{
|
||||
ChunkRenderWorker.this.freeRenderBuilder(generator);
|
||||
|
||||
if (!(p_onFailure_1_ instanceof CancellationException) && !(p_onFailure_1_ instanceof InterruptedException))
|
||||
{
|
||||
Log.RENDER.error(p_onFailure_1_, "Fehler beim Rendern des Chunks");
|
||||
}
|
||||
}
|
||||
});
|
||||
ChunkBuilder.addCallback(list, generator, compiled, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,11 +142,40 @@ public class ChunkRenderWorker implements Runnable
|
|||
return this.regionRenderCacheBuilder != null ? this.regionRenderCacheBuilder : this.chunkRenderDispatcher.allocateRenderBuilder();
|
||||
}
|
||||
|
||||
private void freeRenderBuilder(ChunkCompileTaskGenerator taskGenerator)
|
||||
public void freeRenderBuilder(ChunkCompileTaskGenerator taskGenerator)
|
||||
{
|
||||
if (this.regionRenderCacheBuilder == null)
|
||||
{
|
||||
this.chunkRenderDispatcher.freeRenderBuilder(taskGenerator.getRegionRenderCacheBuilder());
|
||||
}
|
||||
}
|
||||
|
||||
public void setRenderBuilderChunk(ChunkCompileTaskGenerator generator, CompiledChunk compiled)
|
||||
{
|
||||
ChunkRenderWorker.this.freeRenderBuilder(generator);
|
||||
generator.getLock().lock();
|
||||
label21:
|
||||
{
|
||||
try
|
||||
{
|
||||
if (generator.getStatus() == ChunkCompileTaskGenerator.Status.UPLOADING)
|
||||
{
|
||||
generator.setStatus(ChunkCompileTaskGenerator.Status.DONE);
|
||||
break label21;
|
||||
}
|
||||
|
||||
if (!generator.isFinished())
|
||||
{
|
||||
Log.RENDER.warn("Chunk-Rendering-Aufgabe war " + generator.getStatus() + " wenn UPLOADING erwartet war; breche Aufgabe ab");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
generator.getLock().unlock();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
generator.getRenderChunk().setCompiledChunk(compiled);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue