fabric-api-base-1.0.0+14b92d896f.jar

Download file
    package net.fabricmc.fabric.impl.base.event;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.impl.base.toposort.NodeSorting;
import net.minecraft.class_2960;

class ArrayBackedEvent<T> extends Event<T> {
   private final Function<T[], T> invokerFactory;
   private final Object lock = new Object();
   private T[] handlers;
   private final Map<class_2960, EventPhaseData<T>> phases = new LinkedHashMap();
   private final List<EventPhaseData<T>> sortedPhases = new ArrayList();

   ArrayBackedEvent(Class<? super T> type, Function<T[], T> invokerFactory) {
      this.invokerFactory = invokerFactory;
      this.handlers = (T[])((Object[])Array.newInstance(type, 0));
      this.update();
   }

   void update() {
      this.invoker = (T)this.invokerFactory.apply(this.handlers);
   }

   public void register(T listener) {
      this.register(DEFAULT_PHASE, listener);
   }

   public void register(class_2960 phaseIdentifier, T listener) {
      Objects.requireNonNull(phaseIdentifier, "Tried to register a listener for a null phase!");
      Objects.requireNonNull(listener, "Tried to register a null listener!");
      synchronized(this.lock) {
         this.getOrCreatePhase(phaseIdentifier, true).addListener(listener);
         this.rebuildInvoker(this.handlers.length + 1);
      }
   }

   private EventPhaseData<T> getOrCreatePhase(class_2960 id, boolean sortIfCreate) {
      EventPhaseData<T> phase = (EventPhaseData)this.phases.get(id);
      if (phase == null) {
         phase = new EventPhaseData<T>(id, this.handlers.getClass().getComponentType());
         this.phases.put(id, phase);
         this.sortedPhases.add(phase);
         if (sortIfCreate) {
            NodeSorting.sort(this.sortedPhases, "event phases", Comparator.comparing((data) -> data.id));
         }
      }

      return phase;
   }

   private void rebuildInvoker(int newLength) {
      if (this.sortedPhases.size() == 1) {
         this.handlers = ((EventPhaseData)this.sortedPhases.get(0)).listeners;
      } else {
         T[] newHandlers = (T[])((Object[])Array.newInstance(this.handlers.getClass().getComponentType(), newLength));
         int newHandlersIndex = 0;

         for(EventPhaseData<T> existingPhase : this.sortedPhases) {
            int length = existingPhase.listeners.length;
            System.arraycopy(existingPhase.listeners, 0, newHandlers, newHandlersIndex, length);
            newHandlersIndex += length;
         }

         this.handlers = newHandlers;
      }

      this.update();
   }

   public void addPhaseOrdering(class_2960 firstPhase, class_2960 secondPhase) {
      Objects.requireNonNull(firstPhase, "Tried to add an ordering for a null phase.");
      Objects.requireNonNull(secondPhase, "Tried to add an ordering for a null phase.");
      if (firstPhase.equals(secondPhase)) {
         throw new IllegalArgumentException("Tried to add a phase that depends on itself.");
      } else {
         synchronized(this.lock) {
            EventPhaseData<T> first = this.getOrCreatePhase(firstPhase, false);
            EventPhaseData<T> second = this.getOrCreatePhase(secondPhase, false);
            EventPhaseData.link(first, second);
            NodeSorting.sort(this.sortedPhases, "event phases", Comparator.comparing((data) -> data.id));
            this.rebuildInvoker(this.handlers.length);
         }
      }
   }
}
    
Download file