package com.hypixel.hytale.event; import com.hypixel.hytale.logger.HytaleLogger; import java.util.List; import java.util.function.Consumer; import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class SyncEventBusRegistry> extends EventBusRegistry> { public static final IEventDispatcher NO_OP = new IEventDispatcher() { @Override public boolean hasListener() { return false; } public IBaseEvent dispatch(IBaseEvent event) { return event; } }; private final IEventDispatcher globalDispatcher = event -> { if (!this.dispatchGlobal(event)) { this.dispatchUnhandled(event); } return event; }; public SyncEventBusRegistry(HytaleLogger logger, Class eventClass) { super(logger, eventClass, new SyncEventBusRegistry.SyncEventConsumerMap<>(null), new SyncEventBusRegistry.SyncEventConsumerMap<>(null)); this.global.registry = this.unhandled.registry = this; } @Nonnull @Override public EventRegistration register(short priority, @Nullable KeyType key, @Nonnull Consumer consumer) { if (this.shutdown) { throw new IllegalArgumentException("EventRegistry is shutdown!"); } else { KeyType k = (KeyType)(key != null ? key : NULL); SyncEventBusRegistry.SyncEventConsumerMap eventMap = this.map .computeIfAbsent(k, o -> new SyncEventBusRegistry.SyncEventConsumerMap<>(this)); SyncEventBusRegistry.SyncEventConsumer eventConsumer = new SyncEventBusRegistry.SyncEventConsumer<>(priority, consumer); eventMap.add(eventConsumer); return new EventRegistration<>(this.eventClass, this::isAlive, () -> this.unregister(key, eventConsumer)); } } private void unregister(@Nullable KeyType key, @Nonnull SyncEventBusRegistry.SyncEventConsumer consumer) { if (this.shutdown) { throw new IllegalArgumentException("EventRegistry is shutdown!"); } else { KeyType k = (KeyType)(key != null ? key : NULL); SyncEventBusRegistry.SyncEventConsumerMap eventMap = this.map.get(k); if (eventMap != null && !eventMap.remove(consumer)) { throw new IllegalArgumentException(String.valueOf(consumer)); } } } @Nonnull @Override public EventRegistration registerGlobal(short priority, @Nonnull Consumer consumer) { if (this.shutdown) { throw new IllegalArgumentException("EventRegistry is shutdown!"); } else { SyncEventBusRegistry.SyncEventConsumer eventConsumer = new SyncEventBusRegistry.SyncEventConsumer<>(priority, consumer); this.global.add(eventConsumer); return new EventRegistration<>(this.eventClass, this::isAlive, () -> this.unregisterGlobal(eventConsumer)); } } private void unregisterGlobal(@Nonnull SyncEventBusRegistry.SyncEventConsumer consumer) { if (this.shutdown) { throw new IllegalArgumentException("EventRegistry is shutdown!"); } else if (!this.global.remove(consumer)) { throw new IllegalArgumentException(String.valueOf(consumer)); } } @Nonnull @Override public EventRegistration registerUnhandled(short priority, @Nonnull Consumer consumer) { if (this.shutdown) { throw new IllegalArgumentException("EventRegistry is shutdown!"); } else { SyncEventBusRegistry.SyncEventConsumer eventConsumer = new SyncEventBusRegistry.SyncEventConsumer<>(priority, consumer); this.unhandled.add(eventConsumer); return new EventRegistration<>(this.eventClass, this::isAlive, () -> this.unregisterUnhandled(eventConsumer)); } } private void unregisterUnhandled(@Nonnull SyncEventBusRegistry.SyncEventConsumer consumer) { if (this.shutdown) { throw new IllegalArgumentException("EventRegistry is shutdown!"); } else if (!this.unhandled.remove(consumer)) { throw new IllegalArgumentException(String.valueOf(consumer)); } } @Nonnull @Override public IEventDispatcher dispatchFor(@Nullable KeyType key) { if (this.shutdown) { throw new IllegalArgumentException("EventRegistry is shutdown!"); } else { KeyType k = (KeyType)(key != null ? key : NULL); SyncEventBusRegistry.SyncEventConsumerMap eventMap = this.map.get(k); if (eventMap != null && !eventMap.isEmpty()) { return eventMap; } else { return this.global.isEmpty() && this.unhandled.isEmpty() ? NO_OP : this.globalDispatcher; } } } private boolean dispatchGlobal(EventType event) { return this.dispatchEventMap(event, this.global, "Failed to dispatch event (global)"); } private boolean dispatchUnhandled(EventType event) { return this.dispatchEventMap(event, this.unhandled, "Failed to dispatch event (unhandled)"); } private boolean dispatchEventMap(EventType event, @Nonnull SyncEventBusRegistry.SyncEventConsumerMap eventMap, String s) { boolean handled = false; for (short priority : eventMap.getPriorities()) { List> consumers = eventMap.get(priority); if (consumers != null) { for (SyncEventBusRegistry.SyncEventConsumer consumer : consumers) { try { Consumer theConsumer = this.timeEvents ? consumer.getTimedConsumer() : consumer.getConsumer(); theConsumer.accept(event); if (event instanceof IProcessedEvent processedEvent) { processedEvent.processEvent(consumer.getConsumerString()); } handled = true; } catch (Throwable var14) { ((HytaleLogger.Api)this.logger.at(Level.SEVERE).withCause(var14)).log("%s %s to %s", s, event, consumer); } } } } return handled; } protected static class SyncEventConsumer extends EventBusRegistry.EventConsumer { @Nonnull private final Consumer consumer; @Nonnull private final Consumer timedConsumer; public SyncEventConsumer(short priority, @Nonnull Consumer consumer) { super(priority, consumer.toString()); this.consumer = consumer; this.timedConsumer = t -> { long before = System.nanoTime(); consumer.accept(t); long after = System.nanoTime(); this.timer.add(after - before); }; } @Nonnull protected Consumer getConsumer() { return this.consumer; } @Nonnull public Consumer getTimedConsumer() { return this.timedConsumer; } @Nonnull @Override public String toString() { return "SyncEventConsumer{consumer=" + this.consumer + ", timedConsumer=" + this.timedConsumer + "} " + super.toString(); } } protected static class SyncEventConsumerMap extends EventBusRegistry.EventConsumerMap, EventType> { protected SyncEventBusRegistry registry; public SyncEventConsumerMap(SyncEventBusRegistry registry) { this.registry = registry; } public EventType dispatch(EventType event) { boolean handled = this.registry.dispatchEventMap(event, this, "Failed to dispatch event"); if (!this.registry.dispatchGlobal(event) && !handled) { this.registry.dispatchUnhandled(event); } return event; } } }