PeriodicNotificationManager.java

net.minecraft.client.PeriodicNotificationManager

信息

  • 全限定名:net.minecraft.client.PeriodicNotificationManager
  • 类型:public class
  • 包:net.minecraft.client
  • 源码路径:src/main/java/net/minecraft/client/PeriodicNotificationManager.java
  • 起始行号:L34
  • 继承:SimplePreparableReloadListener<Map<String,List<PeriodicNotificationManager.Notification>>>
  • 实现:AutoCloseable
  • 职责:

    TODO

字段/常量

  • CODEC

    • 类型: Codec<Map<String,List<PeriodicNotificationManager.Notification>>>
    • 修饰符: private static final
    • 源码定位: L37
    • 说明:

      TODO

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L50
    • 说明:

      TODO

  • notifications

    • 类型: Identifier
    • 修饰符: private final
    • 源码定位: L51
    • 说明:

      TODO

  • selector

    • 类型: Object2BooleanFunction<String>
    • 修饰符: private final
    • 源码定位: L52
    • 说明:

      TODO

  • timer

    • 类型: Timer
    • 修饰符: private
    • 源码定位: L53
    • 说明:

      TODO

  • notificationTask

    • 类型: PeriodicNotificationManager.NotificationTask
    • 修饰符: private
    • 源码定位: L54
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.PeriodicNotificationManager.Notification

    • 类型: record
    • 修饰符: public
    • 源码定位: L127
    • 说明:

      TODO

  • net.minecraft.client.PeriodicNotificationManager.NotificationTask

    • 类型: class
    • 修饰符: private static
    • 源码定位: L137
    • 说明:

      TODO

构造器

public PeriodicNotificationManager(Identifier notifications, Object2BooleanFunction<String> selector) @ L56

  • 构造器名:PeriodicNotificationManager
  • 源码定位:L56
  • 修饰符:public

参数:

  • notifications: Identifier
  • selector: Object2BooleanFunction

说明:

TODO

方法

下面的方法块按源码顺序生成。

protected Map<String,List<PeriodicNotificationManager.Notification>> prepare(ResourceManager manager, ProfilerFiller profiler) @ L61

  • 方法名:prepare
  • 源码定位:L61
  • 返回类型:Map<String,List<PeriodicNotificationManager.Notification>>
  • 修饰符:protected

参数:

  • manager: ResourceManager
  • profiler: ProfilerFiller

说明:

TODO

protected void apply(Map<String,List<PeriodicNotificationManager.Notification>> preparations, ResourceManager manager, ProfilerFiller profiler) @ L75

  • 方法名:apply
  • 源码定位:L75
  • 返回类型:void
  • 修饰符:protected

参数:

  • preparations: Map<String,List<PeriodicNotificationManager.Notification>>
  • manager: ResourceManager
  • profiler: ProfilerFiller

说明:

TODO

public void close() @ L104

  • 方法名:close
  • 源码定位:L104
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

private void stopTimer() @ L109

  • 方法名:stopTimer
  • 源码定位:L109
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

private long calculateOptimalPeriod(List<PeriodicNotificationManager.Notification> notifications, long initialDelay) @ L115

  • 方法名:calculateOptimalPeriod
  • 源码定位:L115
  • 返回类型:long
  • 修饰符:private

参数:

  • notifications: List<PeriodicNotificationManager.Notification>
  • initialDelay: long

说明:

TODO

private long calculateInitialDelay(List<PeriodicNotificationManager.Notification> notifications) @ L122

  • 方法名:calculateInitialDelay
  • 源码定位:L122
  • 返回类型:long
  • 修饰符:private

参数:

  • notifications: List<PeriodicNotificationManager.Notification>

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class PeriodicNotificationManager
    extends SimplePreparableReloadListener<Map<String, List<PeriodicNotificationManager.Notification>>>
    implements AutoCloseable {
    private static final Codec<Map<String, List<PeriodicNotificationManager.Notification>>> CODEC = Codec.unboundedMap(
        Codec.STRING,
        RecordCodecBuilder.<PeriodicNotificationManager.Notification>create(
                i -> i.group(
                        Codec.LONG.optionalFieldOf("delay", 0L).forGetter(PeriodicNotificationManager.Notification::delay),
                        Codec.LONG.fieldOf("period").forGetter(PeriodicNotificationManager.Notification::period),
                        Codec.STRING.fieldOf("title").forGetter(PeriodicNotificationManager.Notification::title),
                        Codec.STRING.fieldOf("message").forGetter(PeriodicNotificationManager.Notification::message)
                    )
                    .apply(i, PeriodicNotificationManager.Notification::new)
            )
            .listOf()
    );
    private static final Logger LOGGER = LogUtils.getLogger();
    private final Identifier notifications;
    private final Object2BooleanFunction<String> selector;
    private @Nullable Timer timer;
    private PeriodicNotificationManager.@Nullable NotificationTask notificationTask;
 
    public PeriodicNotificationManager(Identifier notifications, Object2BooleanFunction<String> selector) {
        this.notifications = notifications;
        this.selector = selector;
    }
 
    protected Map<String, List<PeriodicNotificationManager.Notification>> prepare(ResourceManager manager, ProfilerFiller profiler) {
        try {
            Map var4;
            try (Reader reader = manager.openAsReader(this.notifications)) {
                var4 = CODEC.parse(JsonOps.INSTANCE, StrictJsonParser.parse(reader)).result().orElseThrow();
            }
 
            return var4;
        } catch (Exception var8) {
            LOGGER.warn("Failed to load {}", this.notifications, var8);
            return ImmutableMap.of();
        }
    }
 
    protected void apply(Map<String, List<PeriodicNotificationManager.Notification>> preparations, ResourceManager manager, ProfilerFiller profiler) {
        List<PeriodicNotificationManager.Notification> notifications = preparations.entrySet()
            .stream()
            .filter(e -> this.selector.apply(e.getKey()))
            .map(Entry::getValue)
            .flatMap(Collection::stream)
            .collect(Collectors.toList());
        if (notifications.isEmpty()) {
            this.stopTimer();
        } else if (notifications.stream().anyMatch(n -> n.period == 0L)) {
            Util.logAndPauseIfInIde("A periodic notification in " + this.notifications + " has a period of zero minutes");
            this.stopTimer();
        } else {
            long delay = this.calculateInitialDelay(notifications);
            long period = this.calculateOptimalPeriod(notifications, delay);
            if (this.timer == null) {
                this.timer = new Timer();
            }
 
            if (this.notificationTask == null) {
                this.notificationTask = new PeriodicNotificationManager.NotificationTask(notifications, delay, period);
            } else {
                this.notificationTask = this.notificationTask.reset(notifications, period);
            }
 
            this.timer.scheduleAtFixedRate(this.notificationTask, TimeUnit.MINUTES.toMillis(delay), TimeUnit.MINUTES.toMillis(period));
        }
    }
 
    @Override
    public void close() {
        this.stopTimer();
    }
 
    private void stopTimer() {
        if (this.timer != null) {
            this.timer.cancel();
        }
    }
 
    private long calculateOptimalPeriod(List<PeriodicNotificationManager.Notification> notifications, long initialDelay) {
        return notifications.stream().mapToLong(c -> {
            long delayPeriods = c.delay - initialDelay;
            return LongMath.gcd(delayPeriods, c.period);
        }).reduce(LongMath::gcd).orElseThrow(() -> new IllegalStateException("Empty notifications from: " + this.notifications));
    }
 
    private long calculateInitialDelay(List<PeriodicNotificationManager.Notification> notifications) {
        return notifications.stream().mapToLong(c -> c.delay).min().orElse(0L);
    }
 
    @OnlyIn(Dist.CLIENT)
    public record Notification(long delay, long period, String title, String message) {
        public Notification(long delay, long period, String title, String message) {
            this.delay = delay != 0L ? delay : period;
            this.period = period;
            this.title = title;
            this.message = message;
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    private static class NotificationTask extends TimerTask {
        private final Minecraft minecraft = Minecraft.getInstance();
        private final List<PeriodicNotificationManager.Notification> notifications;
        private final long period;
        private final AtomicLong elapsed;
 
        public NotificationTask(List<PeriodicNotificationManager.Notification> notifications, long elapsed, long period) {
            this.notifications = notifications;
            this.period = period;
            this.elapsed = new AtomicLong(elapsed);
        }
 
        public PeriodicNotificationManager.NotificationTask reset(List<PeriodicNotificationManager.Notification> notifications, long period) {
            this.cancel();
            return new PeriodicNotificationManager.NotificationTask(notifications, this.elapsed.get(), period);
        }
 
        @Override
        public void run() {
            long currentMinute = this.elapsed.getAndAdd(this.period);
            long nextMinute = this.elapsed.get();
 
            for (PeriodicNotificationManager.Notification notification : this.notifications) {
                if (currentMinute >= notification.delay) {
                    long elapsedPeriods = currentMinute / notification.period;
                    long currentPeriods = nextMinute / notification.period;
                    if (elapsedPeriods != currentPeriods) {
                        this.minecraft
                            .execute(
                                () -> SystemToast.add(
                                    Minecraft.getInstance().getToastManager(),
                                    SystemToast.SystemToastId.PERIODIC_NOTIFICATION,
                                    Component.translatable(notification.title, elapsedPeriods),
                                    Component.translatable(notification.message, elapsedPeriods)
                                )
                            );
                        return;
                    }
                }
            }
        }
    }
}

引用的其他类