--- a/net/minecraft/server/level/Ticket.java
+++ b/net/minecraft/server/level/Ticket.java
@@ -7,24 +_,85 @@
 import net.minecraft.core.registries.BuiltInRegistries;
 import net.minecraft.util.ExtraCodecs;
 
-public class Ticket {
+public class Ticket<T> implements Comparable<Ticket>, ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicket<T> { // Paper - rewrite chunk system
     public static final MapCodec<Ticket> CODEC = RecordCodecBuilder.mapCodec(
         instance -> instance.group(
                 BuiltInRegistries.TICKET_TYPE.byNameCodec().fieldOf("type").forGetter(Ticket::getType),
                 ExtraCodecs.NON_NEGATIVE_INT.fieldOf("level").forGetter(Ticket::getTicketLevel),
                 Codec.LONG.optionalFieldOf("ticks_left", 0L).forGetter(ticket -> ticket.ticksLeft)
             )
-            .apply(instance, Ticket::new)
+            .apply(instance, (type, level, ticks) -> new Ticket(type, level.intValue(), ticks.longValue())) // Paper - add identifier
     );
     private final TicketType type;
     private final int ticketLevel;
     private long ticksLeft;
+    // Paper start - add identifier
+    private T identifier; // Paper - rewrite chunk system
+
+    public Object getIdentifier() {
+        return this.identifier;
+    }
+    // Paper end - add identifier
+    // Paper start - rewrite chunk system
+    @Override
+    public final long moonrise$getRemoveDelay() {
+        return this.ticksLeft;
+    }
+
+    @Override
+    public final void moonrise$setRemoveDelay(final long removeDelay) {
+        this.ticksLeft = removeDelay;
+    }
+
+    @Override
+    public final T moonrise$getIdentifier() {
+        return this.identifier;
+    }
+
+    @Override
+    public final void moonrise$setIdentifier(final T identifier) {
+        if ((identifier == null) != (((ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType<T>)(Object)this.type).moonrise$getIdentifierComparator() == null)) {
+            throw new IllegalStateException("Nullability of identifier should match nullability of comparator");
+        }
+        this.identifier = identifier;
+    }
+
+    @Override
+    public final int compareTo(final Ticket ticket) {
+        final int levelCompare = Integer.compare(this.ticketLevel, ticket.ticketLevel);
+        if (levelCompare != 0) {
+            return levelCompare;
+        }
+
+        final int typeCompare = Long.compare(
+            ((ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType<T>)(Object)this.type).moonrise$getId(),
+            ((ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType<?>)(Object)ticket.type).moonrise$getId()
+        );
+        if (typeCompare != 0) {
+            return typeCompare;
+        }
+
+        final java.util.Comparator<T> comparator = ((ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType<T>)(Object)this.type).moonrise$getIdentifierComparator();
+        return comparator == null ? 0 : comparator.compare(this.identifier, (T)ticket.identifier);
+    }
+    // Paper end - rewrite chunk system
 
     public Ticket(TicketType type, int ticketLevel) {
-        this(type, ticketLevel, type.timeout());
+        // Paper start - add identifier
+        this(type, ticketLevel, null);
+    }
+    public Ticket(TicketType type, int ticketLevel, Object identifier) {
+        this(type, ticketLevel, type.timeout(), identifier);
+        // Paper end - add identifier
     }
 
-    private Ticket(TicketType type, int ticketLevel, long ticksLeft) {
+    public Ticket(TicketType type, int ticketLevel, long ticksLeft) { // Paper - rewrite chunk system - public
+        // Paper start - add identifier
+        this(type, ticketLevel, ticksLeft, null);
+    }
+    private Ticket(TicketType type, int ticketLevel, long ticksLeft, Object identifier) {
+        this.identifier = (T)identifier; // Paper - rewrite chunk system
+        // Paper end - add identifier
         this.type = type;
         this.ticketLevel = ticketLevel;
         this.ticksLeft = ticksLeft;
@@ -32,17 +_,7 @@
 
     @Override
     public String toString() {
-        return this.type.hasTimeout()
-            ? "Ticket["
-                + Util.getRegisteredName(BuiltInRegistries.TICKET_TYPE, this.type)
-                + " "
-                + this.ticketLevel
-                + "] with "
-                + this.ticksLeft
-                + " ticks left ( out of"
-                + this.type.timeout()
-                + ")"
-            : "Ticket[" + Util.getRegisteredName(BuiltInRegistries.TICKET_TYPE, this.type) + " " + this.ticketLevel + "] with no timeout";
+        return "Ticket[" + this.type + " " + this.ticketLevel + " (" + this.identifier + ")] to die in " + this.ticksLeft; // Paper - rewrite chunk system
     }
 
     public TicketType getType() {
