From d45e501c42262488deb4f79183eceb74fdd34f86 Mon Sep 17 00:00:00 2001 From: arzumify Date: Thu, 27 Feb 2025 17:41:29 +0000 Subject: [PATCH] Switched to using the Presence API for Range detection, removed unused util structs, fixed cable implementation to be somewhat sane --- README.md | 4 +- build.gradle | 30 ++--- gradle.properties | 5 +- .../polyenergy/api/EnergyPresence.java | 7 ++ .../polyenergy/api/EnergyProvider.java | 9 +- .../polyenergy/api/EnergyReceiver.java | 2 +- .../polyenergy/impl/CoordinateMatchMaker.java | 71 ++++++------ .../polyenergy/impl/ProviderDetails.java | 28 ----- .../polyenergy/impl/ReceiverDetails.java | 14 --- .../polyenergy/util/SimpleBattery.java | 105 ------------------ .../arzumify/polyenergy/util/SimpleCable.java | 86 -------------- src/test/java/SimpleCodeOnlyBattery.java | 34 +++--- src/test/java/SimpleCodeOnlyCable.java | 58 ++++++---- 13 files changed, 111 insertions(+), 342 deletions(-) create mode 100644 src/main/java/arzumify/polyenergy/api/EnergyPresence.java delete mode 100644 src/main/java/arzumify/polyenergy/impl/ProviderDetails.java delete mode 100644 src/main/java/arzumify/polyenergy/impl/ReceiverDetails.java delete mode 100644 src/main/java/arzumify/polyenergy/util/SimpleBattery.java delete mode 100644 src/main/java/arzumify/polyenergy/util/SimpleCable.java diff --git a/README.md b/README.md index a55fc0f..a5ccfe4 100644 --- a/README.md +++ b/README.md @@ -44,10 +44,10 @@ energy. To create a provider, implement the `EnergyProvider` interface. This interface has two methods: -- `void exists(EnergyReceiver receiver, ArrayList 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);` diff --git a/build.gradle b/build.gradle index fb77326..a7968ba 100644 --- a/build.gradle +++ b/build.gradle @@ -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. - } -} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 0c45d5f..7f808d7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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 \ No newline at end of file +fabric_version=0.118.0+1.21.4 +presence_version=1.1.1 \ No newline at end of file diff --git a/src/main/java/arzumify/polyenergy/api/EnergyPresence.java b/src/main/java/arzumify/polyenergy/api/EnergyPresence.java new file mode 100644 index 0000000..a1e4511 --- /dev/null +++ b/src/main/java/arzumify/polyenergy/api/EnergyPresence.java @@ -0,0 +1,7 @@ +package arzumify.polyenergy.api; + +import arzumify.presence.presences.IntegerPresence; +import arzumify.presence.presences.PresenceProvider; + +public interface EnergyPresence extends PresenceProvider { +} diff --git a/src/main/java/arzumify/polyenergy/api/EnergyProvider.java b/src/main/java/arzumify/polyenergy/api/EnergyProvider.java index fcf9a30..29e2243 100644 --- a/src/main/java/arzumify/polyenergy/api/EnergyProvider.java +++ b/src/main/java/arzumify/polyenergy/api/EnergyProvider.java @@ -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 pointsOfPresence); + void exists(EnergyReceiver receiver); } \ No newline at end of file diff --git a/src/main/java/arzumify/polyenergy/api/EnergyReceiver.java b/src/main/java/arzumify/polyenergy/api/EnergyReceiver.java index 729e1bb..c9e6431 100644 --- a/src/main/java/arzumify/polyenergy/api/EnergyReceiver.java +++ b/src/main/java/arzumify/polyenergy/api/EnergyReceiver.java @@ -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. diff --git a/src/main/java/arzumify/polyenergy/impl/CoordinateMatchMaker.java b/src/main/java/arzumify/polyenergy/impl/CoordinateMatchMaker.java index a2815cb..a05c171 100644 --- a/src/main/java/arzumify/polyenergy/impl/CoordinateMatchMaker.java +++ b/src/main/java/arzumify/polyenergy/impl/CoordinateMatchMaker.java @@ -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 providers = new CopyOnWriteArrayList<>(); - private static final CopyOnWriteArrayList receivers = new CopyOnWriteArrayList<>(); - private static final ConcurrentHashMap> matches = new ConcurrentHashMap<>(); + private static final Channel receivers = new Channel(); + private static final Channel providers = new Channel(); + private static final ConcurrentHashMap> matches = new ConcurrentHashMap<>(); + private static MatchMaker 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); } } diff --git a/src/main/java/arzumify/polyenergy/impl/ProviderDetails.java b/src/main/java/arzumify/polyenergy/impl/ProviderDetails.java deleted file mode 100644 index 420937b..0000000 --- a/src/main/java/arzumify/polyenergy/impl/ProviderDetails.java +++ /dev/null @@ -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 pointsOfPresence, EnergyProvider provider, int range) { - public static ProviderDetails NewSimple(Vec3i position, EnergyProvider provider) { - var pointsOfPresence = new ArrayList(); - pointsOfPresence.add(position); - return new ProviderDetails(pointsOfPresence, provider, 1); - } - - public boolean isInRange(ArrayList 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; - } -} diff --git a/src/main/java/arzumify/polyenergy/impl/ReceiverDetails.java b/src/main/java/arzumify/polyenergy/impl/ReceiverDetails.java deleted file mode 100644 index 4329bc3..0000000 --- a/src/main/java/arzumify/polyenergy/impl/ReceiverDetails.java +++ /dev/null @@ -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 pointsOfPresence, EnergyReceiver receiver) { - public static ReceiverDetails NewSimple(Vec3i position, EnergyReceiver receiver) { - var pointsOfPresence = new ArrayList(); - pointsOfPresence.add(position); - return new ReceiverDetails(pointsOfPresence, receiver); - } -} diff --git a/src/main/java/arzumify/polyenergy/util/SimpleBattery.java b/src/main/java/arzumify/polyenergy/util/SimpleBattery.java deleted file mode 100644 index b669352..0000000 --- a/src/main/java/arzumify/polyenergy/util/SimpleBattery.java +++ /dev/null @@ -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 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 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(); - } -} diff --git a/src/main/java/arzumify/polyenergy/util/SimpleCable.java b/src/main/java/arzumify/polyenergy/util/SimpleCable.java deleted file mode 100644 index 064456c..0000000 --- a/src/main/java/arzumify/polyenergy/util/SimpleCable.java +++ /dev/null @@ -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 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; - } -} diff --git a/src/test/java/SimpleCodeOnlyBattery.java b/src/test/java/SimpleCodeOnlyBattery.java index befb3fb..0762278 100644 --- a/src/test/java/SimpleCodeOnlyBattery.java +++ b/src/test/java/SimpleCodeOnlyBattery.java @@ -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 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 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 presence() { + return presence; + } } diff --git a/src/test/java/SimpleCodeOnlyCable.java b/src/test/java/SimpleCodeOnlyCable.java index e25afaa..01578c8 100644 --- a/src/test/java/SimpleCodeOnlyCable.java +++ b/src/test/java/SimpleCodeOnlyCable.java @@ -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 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 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 presence() { + return presence; } }