/* * 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 Task createTask(String id, Callable 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(id, updater, periodInUnit, repeatStrategy); } public Subscription createSubscription() { return new Subscription(); } public class Task { private final String id; private final Callable updater; private final long period; private final RepeatedDelayStrategy repeatStrategy; private @Nullable CompletableFuture> pendingTask; private @Nullable SuccessfulComputationResult lastResult; private long nextUpdate = -1L; private Task(String id, Callable 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(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> subscriptions = new ArrayList(); public void subscribe(Task task, Consumer output) { SubscribedTask subscription = new SubscribedTask(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 { private final Task task; private final Consumer output; private long lastCheckTime = -1L; private SubscribedTask(DataFetcher dataFetcher, Task task, Consumer 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 value, long time) { } private record ComputationResult(Either value, long time) { } }