2025-11-24 22:52:51 +03:00

178 lines
6.5 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.mojang.datafixers.util.Either
* com.mojang.logging.LogUtils
* org.jspecify.annotations.Nullable
* org.slf4j.Logger
*/
package com.mojang.realmsclient.gui.task;
import com.mojang.datafixers.util.Either;
import com.mojang.logging.LogUtils;
import com.mojang.realmsclient.gui.task.RepeatedDelayStrategy;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import net.minecraft.util.TimeSource;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
public class DataFetcher {
private static final Logger LOGGER = LogUtils.getLogger();
private final Executor executor;
private final TimeUnit resolution;
private final TimeSource timeSource;
public DataFetcher(Executor executor, TimeUnit resolution, TimeSource timeSource) {
this.executor = executor;
this.resolution = resolution;
this.timeSource = timeSource;
}
public <T> Task<T> createTask(String id, Callable<T> updater, Duration period, RepeatedDelayStrategy repeatStrategy) {
long periodInUnit = this.resolution.convert(period);
if (periodInUnit == 0L) {
throw new IllegalArgumentException("Period of " + String.valueOf(period) + " too short for selected resolution of " + String.valueOf((Object)this.resolution));
}
return new Task<T>(id, updater, periodInUnit, repeatStrategy);
}
public Subscription createSubscription() {
return new Subscription();
}
public class Task<T> {
private final String id;
private final Callable<T> updater;
private final long period;
private final RepeatedDelayStrategy repeatStrategy;
private @Nullable CompletableFuture<ComputationResult<T>> pendingTask;
private @Nullable SuccessfulComputationResult<T> lastResult;
private long nextUpdate = -1L;
private Task(String id, Callable<T> updater, long period, RepeatedDelayStrategy repeatStrategy) {
this.id = id;
this.updater = updater;
this.period = period;
this.repeatStrategy = repeatStrategy;
}
private void updateIfNeeded(long currentTime) {
if (this.pendingTask != null) {
ComputationResult result = this.pendingTask.getNow(null);
if (result == null) {
return;
}
this.pendingTask = null;
long completionTime = result.time;
result.value().ifLeft(value -> {
this.lastResult = new SuccessfulComputationResult<Object>(value, completionTime);
this.nextUpdate = completionTime + this.period * this.repeatStrategy.delayCyclesAfterSuccess();
}).ifRight(e -> {
long cycles = this.repeatStrategy.delayCyclesAfterFailure();
LOGGER.warn("Failed to process task {}, will repeat after {} cycles", new Object[]{this.id, cycles, e});
this.nextUpdate = completionTime + this.period * cycles;
});
}
if (this.nextUpdate <= currentTime) {
this.pendingTask = CompletableFuture.supplyAsync(() -> {
try {
T result = this.updater.call();
long completionTime = DataFetcher.this.timeSource.get(DataFetcher.this.resolution);
return new ComputationResult(Either.left(result), completionTime);
}
catch (Exception e) {
long completionTime = DataFetcher.this.timeSource.get(DataFetcher.this.resolution);
return new ComputationResult(Either.right((Object)e), completionTime);
}
}, DataFetcher.this.executor);
}
}
public void reset() {
this.pendingTask = null;
this.lastResult = null;
this.nextUpdate = -1L;
}
}
public class Subscription {
private final List<SubscribedTask<?>> subscriptions = new ArrayList();
public <T> void subscribe(Task<T> task, Consumer<T> output) {
SubscribedTask<T> subscription = new SubscribedTask<T>(DataFetcher.this, task, output);
this.subscriptions.add(subscription);
subscription.runCallbackIfNeeded();
}
public void forceUpdate() {
for (SubscribedTask<?> subscription : this.subscriptions) {
subscription.runCallback();
}
}
public void tick() {
for (SubscribedTask<?> subscription : this.subscriptions) {
subscription.update(DataFetcher.this.timeSource.get(DataFetcher.this.resolution));
}
}
public void reset() {
for (SubscribedTask<?> subscription : this.subscriptions) {
subscription.reset();
}
}
}
private class SubscribedTask<T> {
private final Task<T> task;
private final Consumer<T> output;
private long lastCheckTime = -1L;
private SubscribedTask(DataFetcher dataFetcher, Task<T> task, Consumer<T> output) {
this.task = task;
this.output = output;
}
private void update(long currentTime) {
this.task.updateIfNeeded(currentTime);
this.runCallbackIfNeeded();
}
private void runCallbackIfNeeded() {
SuccessfulComputationResult lastResult = this.task.lastResult;
if (lastResult != null && this.lastCheckTime < lastResult.time) {
this.output.accept(lastResult.value);
this.lastCheckTime = lastResult.time;
}
}
private void runCallback() {
SuccessfulComputationResult lastResult = this.task.lastResult;
if (lastResult != null) {
this.output.accept(lastResult.value);
this.lastCheckTime = lastResult.time;
}
}
private void reset() {
this.task.reset();
this.lastCheckTime = -1L;
}
}
private record SuccessfulComputationResult<T>(T value, long time) {
}
private record ComputationResult<T>(Either<T, Exception> value, long time) {
}
}