package openmods.fakeplayer; import java.util.Map; import java.util.Queue; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import openmods.LibConfig; import openmods.Log; public class FakePlayerPool { public interface PlayerUser { public void usePlayer(OpenModsFakePlayer fakePlayer); } public interface PlayerUserReturning<T> { public T usePlayer(OpenModsFakePlayer fakePlayer); } private static PlayerUserReturning<Void> wrap(final PlayerUser user) { return fakePlayer -> { user.usePlayer(fakePlayer); return null; }; } private static class WorldPool { private final Queue<OpenModsFakePlayer> pool = new ConcurrentLinkedQueue<>(); private final AtomicInteger playerCount = new AtomicInteger(); public <T> T executeOnPlayer(WorldServer world, PlayerUserReturning<T> user) { OpenModsFakePlayer player = pool.poll(); if (player == null) { int id = playerCount.incrementAndGet(); if (id > LibConfig.fakePlayerThreshold) Log.warn("Maximum number of fake players in use %d reached. Something may leak them!", id); player = new OpenModsFakePlayer(world, id); } player.isDead = false; T result = user.usePlayer(player); player.setDead(); pool.add(player); return result; } } private FakePlayerPool() {} public static final FakePlayerPool instance = new FakePlayerPool(); private static final Map<World, WorldPool> worldPools = new WeakHashMap<>(); @SubscribeEvent public void onWorldLoad(WorldEvent.Load evt) { worldPools.put(evt.getWorld(), new WorldPool()); } @SubscribeEvent public void onWorldUnload(WorldEvent.Unload evt) { worldPools.remove(evt.getWorld()); } public void executeOnPlayer(WorldServer world, PlayerUser user) { executeOnPlayer(world, wrap(user)); } public <T> T executeOnPlayer(WorldServer world, PlayerUserReturning<T> user) { WorldPool pool = worldPools.get(world); if (pool != null) return pool.executeOnPlayer(world, user); else Log.warn("Trying to execute %s on world %s, but it's not loaded", user, world); return null; } }