Add asynchronous event API from issue #200

This commit is contained in:
md_5 2013-03-19 20:09:15 +11:00
parent 1edd27963f
commit 692610cd7e
4 changed files with 88 additions and 7 deletions

View File

@ -0,0 +1,72 @@
package net.md_5.bungee.api.event;
import com.google.common.base.Preconditions;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.plugin.Event;
import net.md_5.bungee.api.plugin.Plugin;
/**
* Represents an event which depends on the result of asynchronous operations.
*/
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class AsyncEvent extends Event
{
private final Callback done;
private final Set<Plugin> intents = Collections.newSetFromMap( new ConcurrentHashMap<Plugin, Boolean>() );
private final AtomicBoolean fired = new AtomicBoolean();
private final AtomicInteger latch = new AtomicInteger();
@Override
@SuppressWarnings("unchecked")
public void postCall()
{
fired.set( true );
if ( latch.get() == 0 )
{
done.done( this, null );
}
}
/**
* Register an intent that this plugin will continue to perform work on a
* background task, and wishes to let the event proceed once the registered
* background task has completed.
*
* @param plugin the plugin registering this intent
*/
public void registerIntent(Plugin plugin)
{
Preconditions.checkState( !fired.get(), "Event %s has already been fired", this );
Preconditions.checkState( !intents.contains( plugin ), "Plugin %s already registered intent for event %s", plugin, this );
intents.add( plugin );
}
/**
* Notifies this event that this plugin has done all its required processing
* and wishes to let the event proceed.
*
* @param plugin a plugin which has an intent registered for this evemt
*/
@SuppressWarnings("unchecked")
public void completeIntent(Plugin plugin)
{
Preconditions.checkState( intents.contains( plugin ), "Plugin %s has not registered intent for event %s", plugin, this );
intents.remove( plugin );
if ( latch.decrementAndGet() == 0 )
{
done.done( this, null );
}
}
}

View File

@ -5,4 +5,11 @@ package net.md_5.bungee.api.plugin;
*/ */
public abstract class Event public abstract class Event
{ {
/**
* Method called after this event has been dispatched to all handlers.
*/
public void postCall()
{
}
} }

View File

@ -227,8 +227,11 @@ public class PluginManager
*/ */
public <T extends Event> T callEvent(T event) public <T extends Event> T callEvent(T event)
{ {
Preconditions.checkNotNull( event, "event" );
long start = System.nanoTime(); long start = System.nanoTime();
eventBus.post( event ); eventBus.post( event );
event.postCall();
// TODO: No exceptions! // TODO: No exceptions!
if ( !( event instanceof LoginEvent ) ) if ( !( event instanceof LoginEvent ) )
{ {

View File

@ -1,6 +1,7 @@
package net.md_5.bungee.tablist; package net.md_5.bungee.tablist;
import java.util.Map; import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import net.md_5.bungee.BungeeCord; import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.UserConnection; import net.md_5.bungee.UserConnection;
@ -12,9 +13,7 @@ import net.md_5.bungee.packet.PacketC9PlayerListItem;
public class GlobalTabList implements TabListHandler public class GlobalTabList implements TabListHandler
{ {
// Sweet trick to avoid locking, basically reimplement HashSet based on a ConcurrentHashMap private final Set<ProxiedPlayer> sentPings = Collections.newSetFromMap( new ConcurrentHashMap<ProxiedPlayer, Boolean>() );
private static final Object PRESENT = new Object();
private final Map<ProxiedPlayer, Object> sentPings = new ConcurrentHashMap<>();
@Override @Override
public void onConnect(ProxiedPlayer player) public void onConnect(ProxiedPlayer player)
@ -22,7 +21,7 @@ public class GlobalTabList implements TabListHandler
UserConnection con = (UserConnection) player; UserConnection con = (UserConnection) player;
for ( ProxiedPlayer p : ProxyServer.getInstance().getPlayers() ) for ( ProxiedPlayer p : ProxyServer.getInstance().getPlayers() )
{ {
con.sendPacket(new PacketC9PlayerListItem( p.getDisplayName(), true, p.getPing() ) ); con.sendPacket( new PacketC9PlayerListItem( p.getDisplayName(), true, p.getPing() ) );
} }
BungeeCord.getInstance().broadcast( new PacketC9PlayerListItem( player.getDisplayName(), true, player.getPing() ) ); BungeeCord.getInstance().broadcast( new PacketC9PlayerListItem( player.getDisplayName(), true, player.getPing() ) );
} }
@ -30,10 +29,10 @@ public class GlobalTabList implements TabListHandler
@Override @Override
public void onPingChange(ProxiedPlayer player, int ping) public void onPingChange(ProxiedPlayer player, int ping)
{ {
if ( !sentPings.containsKey( player ) ) if ( !sentPings.contains( player ) )
{ {
BungeeCord.getInstance().broadcast( new PacketC9PlayerListItem( player.getDisplayName(), true, player.getPing() ) ); BungeeCord.getInstance().broadcast( new PacketC9PlayerListItem( player.getDisplayName(), true, player.getPing() ) );
sentPings.put( player, PRESENT ); sentPings.add( player );
} }
} }