Switched to using the Presence API for Range detection, removed unused util structs, fixed cable implementation to be somewhat sane

This commit is contained in:
Tracker-Friendly 2025-02-27 17:41:29 +00:00
parent c28c6ccee0
commit d45e501c42
13 changed files with 111 additions and 342 deletions

View file

@ -44,10 +44,10 @@ energy.
To create a provider, implement the `EnergyProvider` interface. This interface has two methods:
- `void exists(EnergyReceiver receiver, ArrayList<Vec3i> pointsOfPresence);`
- `void exists(EnergyReceiver receiver);`
This method is called when the matchmaking service finds a receiver that can receive energy from this provider. The
provider should check if this receiver meets all of it's requirements, then call the Ready() method on the receiver to
provider should check if this receiver meets all of its requirements, then call the Ready() method on the receiver to
make a connection.
- `long extract(long amount, EnergyReceiver receiver);`

View file

@ -11,11 +11,10 @@ base {
}
repositories {
// Add repositories to retrieve artifacts from in here.
// You should only use this when depending on other mods because
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories.
maven {
name = "Arzumify's Maven"
url = "https://maven.ailur.dev"
}
}
loom {
@ -38,6 +37,9 @@ dependencies {
// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
// Presence API
implementation "arzumify:presence:${project.presence_version}"
// Testing
testImplementation(platform('org.junit:junit-bom:5.12.0'))
testImplementation('org.junit.jupiter:junit-jupiter')
@ -79,21 +81,3 @@ jar {
rename { "${it}_${inputs.properties.archivesName}" }
}
}
// configure the maven publication
publishing {
publications {
create("mavenJava", MavenPublication) {
artifactId = project.archives_base_name
from components.java
}
}
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
repositories {
// Add repositories to publish to here.
// Notice: This block does NOT have the same function as the block in the top level.
// The repositories here will be used for publishing your artifact, not for
// retrieving dependencies.
}
}

View file

@ -7,8 +7,9 @@ minecraft_version=1.21.4
yarn_mappings=1.21.4+build.8
loader_version=0.16.10
# Mod Properties
mod_version=1.2.1
mod_version=2.0.0
maven_group=arzumify.polyenergy
archives_base_name=polyenergy
# Dependencies
fabric_version=0.118.0+1.21.4
fabric_version=0.118.0+1.21.4
presence_version=1.1.1

View file

@ -0,0 +1,7 @@
package arzumify.polyenergy.api;
import arzumify.presence.presences.IntegerPresence;
import arzumify.presence.presences.PresenceProvider;
public interface EnergyPresence extends PresenceProvider<IntegerPresence> {
}

View file

@ -1,11 +1,7 @@
package arzumify.polyenergy.api;
import net.minecraft.util.math.Vec3i;
import java.util.ArrayList;
// Provides energy to EnergyReceivers. Can be implemented by anything able to tick and provide energy!
public interface EnergyProvider {
public interface EnergyProvider extends EnergyPresence {
/**
* When called by a receiver, attempts to remove energy from the provider.
* Do not attempt to extract energy until {@link EnergyReceiver#ready(EnergyProvider)} is called by the receiver.
@ -22,7 +18,6 @@ public interface EnergyProvider {
* This particular overload is for coordinate-based matchmaking.
*
* @param receiver The receiver that exists.
* @param pointsOfPresence The points of presence of the receiver (can be multiple, e.g. for a network of wires or a large entity).
*/
void exists(EnergyReceiver receiver, ArrayList<Vec3i> pointsOfPresence);
void exists(EnergyReceiver receiver);
}

View file

@ -1,7 +1,7 @@
package arzumify.polyenergy.api;
// Receives energy from EnergyProviders. Can be implemented by anything able to tick and receive energy!
public interface EnergyReceiver {
public interface EnergyReceiver extends EnergyPresence {
/**
* When called by a provider, indicates that the provider exists and is ready to have energy extracted from.
* Do not attempt to call {@link EnergyProvider#extract(long, EnergyReceiver)} on any provider until this method is called.

View file

@ -1,64 +1,67 @@
package arzumify.polyenergy.impl;
import arzumify.polyenergy.api.EnergyPresence;
import arzumify.polyenergy.api.EnergyProvider;
import arzumify.polyenergy.api.EnergyReceiver;
import arzumify.presence.matchmaker.Channel;
import arzumify.presence.matchmaker.MatchMaker;
import arzumify.presence.presences.IntegerPresence;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
// It's slightly more optimized now, as in it could realistically run in Minecraft.
// Reset: O(1) constant time, we're just deleting everything
// Add Provider: O(m * k^2) where m is the number of receivers and k is the number of points of presence
// Add Receiver: O(n * k^2) where n is the number of providers and k is the number of points of presence
// Remove Provider: O(n + m) where n is the number of providers and m is the number of matches for the provider
// Remove Receiver: O(m) where m is the number of receivers
// I think we stop the optimisations here, the bottleneck is no longer the matchmaker but Minecraft itself.
// If more optimisation is needed we can try to perform Vector math in a more efficient way, but I think this is good enough.
// CoordinateMatchMaker is now implemented using the Presence API
public class CoordinateMatchMaker {
private static final CopyOnWriteArrayList<ProviderDetails> providers = new CopyOnWriteArrayList<>();
private static final CopyOnWriteArrayList<ReceiverDetails> receivers = new CopyOnWriteArrayList<>();
private static final ConcurrentHashMap<ProviderDetails, Set<ReceiverDetails>> matches = new ConcurrentHashMap<>();
private static final Channel receivers = new Channel();
private static final Channel providers = new Channel();
private static final ConcurrentHashMap<EnergyProvider, Set<EnergyReceiver>> matches = new ConcurrentHashMap<>();
private static MatchMaker<IntegerPresence, EnergyPresence> matchMaker = new MatchMaker<>();
public static void reset() {
providers.clear();
receivers.clear();
matches.clear();
matchMaker = new MatchMaker<>();
}
public static void addProvider(ProviderDetails provider) {
providers.add(provider);
matches.put(provider, ConcurrentHashMap.newKeySet());
public static void addProvider(EnergyProvider provider) {
matchMaker.Add(provider, providers);
// Search for receivers within range of this provider
for (ReceiverDetails receiver : receivers) {
if (provider.isInRange(receiver.pointsOfPresence())) {
provider.provider().exists(receiver.receiver(), provider.pointsOfPresence());
matches.get(provider).add(receiver);
var receivers = matchMaker.Search(provider, CoordinateMatchMaker.receivers);
if (receivers != null) {
for (EnergyPresence receiver : receivers) {
if (receiver instanceof EnergyReceiver) {
provider.exists((EnergyReceiver) receiver);
}
}
}
}
public static void addReceiver(ReceiverDetails receiver) {
receivers.add(receiver);
public static void addReceiver(EnergyReceiver receiver) {
matchMaker.Add(receiver, receivers);
// Search for providers within range of this receiver
for (ProviderDetails provider : providers) {
if (provider.isInRange(receiver.pointsOfPresence())) {
provider.provider().exists(receiver.receiver(), provider.pointsOfPresence());
matches.get(provider).add(receiver);
var providers = matchMaker.Search(receiver, CoordinateMatchMaker.providers);
if (providers != null) {
for (EnergyPresence provider : providers) {
if (provider instanceof EnergyProvider) {
((EnergyProvider) provider).exists(receiver);
matches.putIfAbsent((EnergyProvider) provider, ConcurrentHashMap.newKeySet());
matches.get(provider).add(receiver);
}
}
}
}
public static void removeProvider(ProviderDetails provider) {
providers.remove(provider);
public static void removeProvider(EnergyProvider provider) {
matchMaker.Remove(provider, providers);
if (matches.get(provider) != null) {
for (ReceiverDetails receiver : matches.get(provider)) {
receiver.receiver().unready(provider.provider());
for (EnergyReceiver receiver : matches.get(provider)) {
receiver.unready(provider);
}
}
matches.remove(provider);
}
public static void removeReceiver(ReceiverDetails receiver) {
receivers.remove(receiver);
public static void removeReceiver(EnergyReceiver receiver) {
matchMaker.Remove(receiver, receivers);
}
}

View file

@ -1,28 +0,0 @@
package arzumify.polyenergy.impl;
import arzumify.polyenergy.api.EnergyProvider;
import net.minecraft.util.math.Vec3i;
import java.util.ArrayList;
public record ProviderDetails(ArrayList<Vec3i> pointsOfPresence, EnergyProvider provider, int range) {
public static ProviderDetails NewSimple(Vec3i position, EnergyProvider provider) {
var pointsOfPresence = new ArrayList<Vec3i>();
pointsOfPresence.add(position);
return new ProviderDetails(pointsOfPresence, provider, 1);
}
public boolean isInRange(ArrayList<Vec3i> pointsOfPresence) {
for (Vec3i point : pointsOfPresence) {
for (Vec3i myPoint : this.pointsOfPresence) {
var manhattanDistance = point.getManhattanDistance(myPoint);
if (manhattanDistance == 0) {
return false;
} else if (manhattanDistance <= range) {
return true;
}
}
}
return false;
}
}

View file

@ -1,14 +0,0 @@
package arzumify.polyenergy.impl;
import arzumify.polyenergy.api.EnergyReceiver;
import net.minecraft.util.math.Vec3i;
import java.util.ArrayList;
public record ReceiverDetails(ArrayList<Vec3i> pointsOfPresence, EnergyReceiver receiver) {
public static ReceiverDetails NewSimple(Vec3i position, EnergyReceiver receiver) {
var pointsOfPresence = new ArrayList<Vec3i>();
pointsOfPresence.add(position);
return new ReceiverDetails(pointsOfPresence, receiver);
}
}

View file

@ -1,105 +0,0 @@
package arzumify.polyenergy.util;
import arzumify.polyenergy.api.EnergyProvider;
import arzumify.polyenergy.api.EnergyReceiver;
import arzumify.polyenergy.impl.CoordinateMatchMaker;
import arzumify.polyenergy.impl.ProviderDetails;
import arzumify.polyenergy.impl.ReceiverDetails;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import java.util.ArrayList;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* A simple battery that can provide and receive energy. Has a range of 1 block in all directions (directly adjacent blocks).
*/
@SuppressWarnings("unused")
public class SimpleBattery extends BlockEntity implements EnergyProvider, EnergyReceiver, ServerBlockEntityEvents.Unload, ServerBlockEntityEvents.Load {
private final long capacity;
private final long inputRate;
private final long outputRate;
private final ProviderDetails providerDetails = ProviderDetails.NewSimple(pos, this);
private final ReceiverDetails receiverDetails = ReceiverDetails.NewSimple(pos, this);
private final Set<EnergyProvider> providers = ConcurrentHashMap.newKeySet();
private long energy = 0;
private boolean providing = false;
public SimpleBattery(BlockEntityType<?> type, BlockPos pos, BlockState state, long capacity, long inputRate, long outputRate) {
super(type, pos, state);
this.capacity = capacity;
this.inputRate = inputRate;
this.outputRate = outputRate;
CoordinateMatchMaker.addProvider(providerDetails);
CoordinateMatchMaker.addReceiver(receiverDetails);
}
public static void tick(World ignoredWorld, BlockPos ignoredPos, BlockState ignoredState, SimpleBattery battery) {
var leftToFill = Math.min(battery.inputRate, battery.capacity - battery.energy);
for (EnergyProvider provider : battery.providers) {
// Less than zero shouldn't be possible, but just in case...
if (leftToFill <= 0) {
break;
}
long extracted = provider.extract(leftToFill, battery);
battery.energy += extracted;
leftToFill -= extracted;
}
if (!battery.providing && battery.energy > 0) {
CoordinateMatchMaker.addProvider(battery.providerDetails);
battery.providing = true;
}
}
@Override
public long extract(long amount, EnergyReceiver receiver) {
if (providing) {
long extracted = Math.min(Math.min(outputRate, amount), energy);
energy -= extracted;
if (energy == 0) {
CoordinateMatchMaker.removeProvider(providerDetails);
}
return extracted;
} else {
return 0;
}
}
@Override
public void exists(EnergyReceiver receiver, ArrayList<Vec3i> pointsOfPresence) {
receiver.ready(this);
}
@Override
public void ready(EnergyProvider provider) {
providers.add(provider);
}
@Override
public void unready(EnergyProvider provider) {
providers.remove(provider);
}
@Override
public void onLoad(BlockEntity blockEntity, ServerWorld serverWorld) {
if (energy > 0) {
CoordinateMatchMaker.addProvider(providerDetails);
providing = true;
}
CoordinateMatchMaker.addReceiver(receiverDetails);
}
@Override
public void onUnload(BlockEntity blockEntity, ServerWorld serverWorld) {
CoordinateMatchMaker.removeProvider(providerDetails);
CoordinateMatchMaker.removeReceiver(receiverDetails);
providers.clear();
}
}

View file

@ -1,86 +0,0 @@
package arzumify.polyenergy.util;
import arzumify.polyenergy.api.EnergyProvider;
import arzumify.polyenergy.api.EnergyReceiver;
import arzumify.polyenergy.impl.CoordinateMatchMaker;
import arzumify.polyenergy.impl.ProviderDetails;
import arzumify.polyenergy.impl.ReceiverDetails;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import java.util.ArrayList;
// Cables can have ONE provider and MANY receivers.
@SuppressWarnings("unused")
public class SimpleCable extends BlockEntity implements EnergyProvider, EnergyReceiver, ServerBlockEntityEvents.Unload, ServerBlockEntityEvents.Load {
private final long capacity;
private final long inputRate;
private final long outputRate;
private final ProviderDetails providerDetails = ProviderDetails.NewSimple(pos, this);
private final ReceiverDetails receiverDetails = ReceiverDetails.NewSimple(pos, this);
private EnergyProvider currentProvider;
private long energy = 0;
public SimpleCable(BlockEntityType<?> type, BlockPos pos, BlockState state, long capacity, long inputRate, long outputRate) {
super(type, pos, state);
this.capacity = capacity;
this.inputRate = inputRate;
this.outputRate = outputRate;
CoordinateMatchMaker.addReceiver(receiverDetails);
}
public static void tick(World ignoredWorld, BlockPos ignoredPos, BlockState ignoredState, SimpleCable cable) {
if (cable.currentProvider != null && cable.energy < cable.capacity) {
cable.energy += cable.currentProvider.extract(Math.min(cable.capacity - cable.energy, cable.inputRate), cable);
}
}
@Override
public long extract(long amount, EnergyReceiver receiver) {
System.out.println("Extracting " + amount + " energy");
long extracted = Math.min(Math.min(outputRate, amount), energy);
energy -= extracted;
return extracted;
}
@Override
public void exists(EnergyReceiver receiver, ArrayList<Vec3i> pointsOfPresence) {
if (currentProvider != null) {
receiver.ready(this);
}
}
@Override
public void ready(EnergyProvider provider) {
if (currentProvider == null) {
currentProvider = provider;
CoordinateMatchMaker.addProvider(providerDetails);
}
}
@Override
public void unready(EnergyProvider provider) {
if (currentProvider == provider) {
currentProvider = null;
CoordinateMatchMaker.removeProvider(providerDetails);
}
}
@Override
public void onLoad(BlockEntity blockEntity, ServerWorld serverWorld) {
CoordinateMatchMaker.addReceiver(receiverDetails);
}
@Override
public void onUnload(BlockEntity blockEntity, ServerWorld serverWorld) {
CoordinateMatchMaker.removeProvider(providerDetails);
CoordinateMatchMaker.removeReceiver(receiverDetails);
currentProvider = null;
}
}

View file

@ -1,14 +1,13 @@
import arzumify.polyenergy.api.EnergyProvider;
import arzumify.polyenergy.api.EnergyReceiver;
import arzumify.polyenergy.impl.CoordinateMatchMaker;
import arzumify.polyenergy.impl.ProviderDetails;
import arzumify.polyenergy.impl.ReceiverDetails;
import arzumify.presence.presences.IntegerPresence;
import arzumify.presence.presences.Presence;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.Vec3i;
import java.util.ArrayList;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@ -20,9 +19,8 @@ public class SimpleCodeOnlyBattery implements EnergyProvider, EnergyReceiver, Se
public final long capacity;
public final long inputRate;
public final long outputRate;
public final IntegerPresence presence;
public final String name;
public final ProviderDetails providerDetails;
public final ReceiverDetails receiverDetails;
public final Set<EnergyProvider> providers = ConcurrentHashMap.newKeySet();
public long energy = 0;
public boolean providing = false;
@ -31,11 +29,10 @@ public class SimpleCodeOnlyBattery implements EnergyProvider, EnergyReceiver, Se
this.capacity = capacity;
this.inputRate = inputRate;
this.outputRate = outputRate;
this.providerDetails = ProviderDetails.NewSimple(pos, this);
this.receiverDetails = ReceiverDetails.NewSimple(pos, this);
this.name = name;
CoordinateMatchMaker.addProvider(providerDetails);
CoordinateMatchMaker.addReceiver(receiverDetails);
this.presence = new IntegerPresence((short) 1, new arzumify.presence.maths.Vec3i(pos.getX(), pos.getY(), pos.getZ()));
CoordinateMatchMaker.addProvider(this);
CoordinateMatchMaker.addReceiver(this);
}
public static void tick(SimpleCodeOnlyBattery battery) {
@ -51,7 +48,7 @@ public class SimpleCodeOnlyBattery implements EnergyProvider, EnergyReceiver, Se
leftToFill -= extracted;
}
if (!battery.providing && battery.energy > 0) {
CoordinateMatchMaker.addProvider(battery.providerDetails);
CoordinateMatchMaker.addProvider(battery);
battery.providing = true;
}
}
@ -64,7 +61,7 @@ public class SimpleCodeOnlyBattery implements EnergyProvider, EnergyReceiver, Se
energy -= extracted;
System.out.println(name + " extracted " + extracted + " energy");
if (energy == 0) {
CoordinateMatchMaker.removeProvider(providerDetails);
CoordinateMatchMaker.removeProvider(this);
}
return extracted;
} else {
@ -73,7 +70,7 @@ public class SimpleCodeOnlyBattery implements EnergyProvider, EnergyReceiver, Se
}
@Override
public void exists(EnergyReceiver receiver, ArrayList<Vec3i> pointsOfPresence) {
public void exists(EnergyReceiver receiver) {
System.out.println(name + " found other receiver");
receiver.ready(this);
}
@ -93,16 +90,21 @@ public class SimpleCodeOnlyBattery implements EnergyProvider, EnergyReceiver, Se
@Override
public void onLoad(BlockEntity blockEntity, ServerWorld serverWorld) {
if (energy > 0) {
CoordinateMatchMaker.addProvider(providerDetails);
CoordinateMatchMaker.addProvider(this);
providing = true;
}
CoordinateMatchMaker.addReceiver(receiverDetails);
CoordinateMatchMaker.addReceiver(this);
}
@Override
public void onUnload(BlockEntity blockEntity, ServerWorld serverWorld) {
CoordinateMatchMaker.removeProvider(providerDetails);
CoordinateMatchMaker.removeReceiver(receiverDetails);
CoordinateMatchMaker.removeProvider(this);
CoordinateMatchMaker.removeReceiver(this);
providers.clear();
}
@Override
public Presence<IntegerPresence> presence() {
return presence;
}
}

View file

@ -1,40 +1,46 @@
import arzumify.polyenergy.api.EnergyProvider;
import arzumify.polyenergy.api.EnergyReceiver;
import arzumify.polyenergy.impl.CoordinateMatchMaker;
import arzumify.polyenergy.impl.ProviderDetails;
import arzumify.polyenergy.impl.ReceiverDetails;
import arzumify.presence.presences.IntegerPresence;
import arzumify.presence.presences.Presence;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.Vec3i;
import java.util.ArrayList;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
// Cables can have ONE provider and MANY receivers.
public class SimpleCodeOnlyCable implements EnergyProvider, EnergyReceiver, ServerBlockEntityEvents.Unload, ServerBlockEntityEvents.Load {
public final long capacity;
public final long inputRate;
public final long outputRate;
public final IntegerPresence presence;
public final String name;
public final ProviderDetails providerDetails;
public final ReceiverDetails receiverDetails;
public long energy = 0;
public EnergyProvider currentProvider;
public final Set<EnergyProvider> providers = ConcurrentHashMap.newKeySet();
public SimpleCodeOnlyCable(Vec3i pos, long capacity, long inputRate, long outputRate, String name) {
this.capacity = capacity;
this.inputRate = inputRate;
this.outputRate = outputRate;
this.providerDetails = ProviderDetails.NewSimple(pos, this);
this.receiverDetails = ReceiverDetails.NewSimple(pos, this);
this.name = name;
CoordinateMatchMaker.addReceiver(receiverDetails);
this.presence = new IntegerPresence((short) 1, new arzumify.presence.maths.Vec3i(pos.getX(), pos.getY(), pos.getZ()));
CoordinateMatchMaker.addReceiver(this);
}
public static void tick(SimpleCodeOnlyCable cable) {
System.out.println(cable.name + " ticking");
if (cable.currentProvider != null && cable.energy < cable.capacity) {
cable.energy += cable.currentProvider.extract(Math.min(cable.capacity - cable.energy, cable.inputRate), cable);
var leftToFill = Math.min(cable.inputRate, cable.capacity - cable.energy);
for (EnergyProvider provider : cable.providers) {
// Less than zero shouldn't be possible, but just in case...
if (leftToFill <= 0) {
break;
}
long extracted = provider.extract(leftToFill, cable);
cable.energy += extracted;
leftToFill -= extracted;
}
}
@ -48,9 +54,9 @@ public class SimpleCodeOnlyCable implements EnergyProvider, EnergyReceiver, Serv
}
@Override
public void exists(EnergyReceiver receiver, ArrayList<Vec3i> pointsOfPresence) {
public void exists(EnergyReceiver receiver) {
System.out.println(name + " found other receiver");
if (currentProvider != null) {
if (!providers.isEmpty()) {
receiver.ready(this);
}
}
@ -58,30 +64,34 @@ public class SimpleCodeOnlyCable implements EnergyProvider, EnergyReceiver, Serv
@Override
public void ready(EnergyProvider provider) {
System.out.println(name + " found other provider");
if (currentProvider == null) {
currentProvider = provider;
CoordinateMatchMaker.addProvider(providerDetails);
providers.add(provider);
if (providers.size() == 1) {
CoordinateMatchMaker.addProvider(this);
}
}
@Override
public void unready(EnergyProvider provider) {
if (currentProvider == provider) {
System.out.println(name + " lost other provider");
currentProvider = null;
CoordinateMatchMaker.removeProvider(providerDetails);
providers.remove(provider);
if (providers.isEmpty()) {
CoordinateMatchMaker.removeProvider(this);
}
}
@Override
public void onLoad(BlockEntity blockEntity, ServerWorld serverWorld) {
CoordinateMatchMaker.addReceiver(receiverDetails);
CoordinateMatchMaker.addReceiver(this);
}
@Override
public void onUnload(BlockEntity blockEntity, ServerWorld serverWorld) {
CoordinateMatchMaker.removeProvider(providerDetails);
CoordinateMatchMaker.removeReceiver(receiverDetails);
currentProvider = null;
CoordinateMatchMaker.removeProvider(this);
CoordinateMatchMaker.removeReceiver(this);
providers.clear();
}
@Override
public Presence<IntegerPresence> presence() {
return presence;
}
}