color palettes, fps in overlay, main menu screen w/ buttons
This commit is contained in:
@@ -179,7 +179,7 @@ public class PropertyManager {
|
||||
}
|
||||
}
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
try(FileInputStream fis = new FileInputStream(file)) {
|
||||
props.load(fis);
|
||||
} catch (final IOException e) {
|
||||
needsSave = true;
|
||||
|
||||
@@ -9,6 +9,7 @@ import mightypork.util.constraints.num.caching.NumDigest;
|
||||
import mightypork.util.constraints.num.mutable.NumVar;
|
||||
import mightypork.util.constraints.num.proxy.NumBound;
|
||||
import mightypork.util.constraints.num.proxy.NumBoundAdapter;
|
||||
import mightypork.util.constraints.vect.Vect;
|
||||
import mightypork.util.math.Calc;
|
||||
|
||||
|
||||
@@ -69,7 +70,7 @@ public abstract class Num implements NumBound, Digestable<NumDigest> {
|
||||
private Num p_neg;
|
||||
private Num p_abs;
|
||||
|
||||
private DigestCache<NumDigest> dc = new DigestCache<NumDigest>() {
|
||||
private final DigestCache<NumDigest> dc = new DigestCache<NumDigest>() {
|
||||
|
||||
@Override
|
||||
protected NumDigest createDigest()
|
||||
@@ -747,4 +748,13 @@ public abstract class Num implements NumBound, Digestable<NumDigest> {
|
||||
{
|
||||
return Calc.toString(value());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return vect with both coords of this size
|
||||
*/
|
||||
public Vect toVectXY()
|
||||
{
|
||||
return Vect.make(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ public abstract class Rect implements RectBound, Digestable<RectDigest> {
|
||||
private Rect p_edge_t;
|
||||
private Rect p_edge_b;
|
||||
|
||||
private DigestCache<RectDigest> dc = new DigestCache<RectDigest>() {
|
||||
private final DigestCache<RectDigest> dc = new DigestCache<RectDigest>() {
|
||||
|
||||
@Override
|
||||
protected RectDigest createDigest()
|
||||
@@ -443,6 +443,12 @@ public abstract class Rect implements RectBound, Digestable<RectDigest> {
|
||||
}
|
||||
|
||||
|
||||
public Rect shrink(Num x, Num y)
|
||||
{
|
||||
return shrink(x, x, y, y);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shrink the rect
|
||||
*
|
||||
@@ -603,6 +609,12 @@ public abstract class Rect implements RectBound, Digestable<RectDigest> {
|
||||
}
|
||||
|
||||
|
||||
public Rect grow(Num x, Num y)
|
||||
{
|
||||
return grow(x, x, y, y);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Grow the rect
|
||||
*
|
||||
|
||||
@@ -437,4 +437,15 @@ public class RectConst extends Rect {
|
||||
return super.centerTo(parent).freeze();
|
||||
}
|
||||
|
||||
|
||||
public RectConst shrink(NumConst x, NumConst y)
|
||||
{
|
||||
return super.shrink(x, y).freeze();
|
||||
}
|
||||
|
||||
|
||||
public RectConst grow(NumConst x, NumConst y)
|
||||
{
|
||||
return super.grow(x, y).freeze();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ package mightypork.util.constraints.rect.builders;
|
||||
import mightypork.util.constraints.num.Num;
|
||||
import mightypork.util.constraints.rect.Rect;
|
||||
import mightypork.util.constraints.rect.proxy.RectProxy;
|
||||
import mightypork.util.logging.Log;
|
||||
|
||||
|
||||
/**
|
||||
* Utility for cutting rect into evenly sized cells.<br>
|
||||
* It's by default one-based, but this can be switched by calling the oneBased()
|
||||
* and zeroBased() methods.
|
||||
* Utility for cutting rect into evenly sized cells.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
@@ -20,8 +19,6 @@ public class TiledRect extends RectProxy {
|
||||
final private Num perRow;
|
||||
final private Num perCol;
|
||||
|
||||
private int based = 1;
|
||||
|
||||
|
||||
public TiledRect(Rect source, int horizontal, int vertical) {
|
||||
super(source);
|
||||
@@ -33,30 +30,6 @@ public class TiledRect extends RectProxy {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set to one-based mode, and return itself (for chaining).
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public TiledRect oneBased()
|
||||
{
|
||||
based = 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set to zero-based mode, and return itself (for chaining).
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public TiledRect zeroBased()
|
||||
{
|
||||
based = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a tile.
|
||||
*
|
||||
@@ -67,9 +40,6 @@ public class TiledRect extends RectProxy {
|
||||
*/
|
||||
public Rect tile(int x, int y)
|
||||
{
|
||||
x -= based;
|
||||
y -= based;
|
||||
|
||||
if (x >= tilesX || x < 0) {
|
||||
throw new IndexOutOfBoundsException("X coordinate out fo range.");
|
||||
}
|
||||
@@ -97,22 +67,19 @@ public class TiledRect extends RectProxy {
|
||||
*/
|
||||
public Rect span(int x_from, int y_from, int size_x, int size_y)
|
||||
{
|
||||
x_from -= based;
|
||||
y_from -= based;
|
||||
|
||||
final int x_to = x_from + size_x;
|
||||
final int y_to = y_from + size_y;
|
||||
final int x_to = x_from + size_x - 1;
|
||||
final int y_to = y_from + size_y - 1;
|
||||
|
||||
if (size_x <= 0 || size_y <= 0) {
|
||||
throw new IndexOutOfBoundsException("Size must be > 0.");
|
||||
Log.w("Size must be > 0.", new IllegalAccessException());
|
||||
}
|
||||
|
||||
if (x_from >= tilesX || x_from < 0 || x_to >= tilesX || x_to < 0) {
|
||||
throw new IndexOutOfBoundsException("X coordinate(s) out of range.");
|
||||
Log.w("X coordinate(s) out of range.", new IllegalAccessException());
|
||||
}
|
||||
|
||||
if (y_from >= tilesY || y_from < 0 || y_to >= tilesY || y_to < 0) {
|
||||
throw new IndexOutOfBoundsException("Y coordinate(s) out of range.");
|
||||
Log.w("Y coordinate(s) out of range.", new IllegalAccessException());
|
||||
}
|
||||
|
||||
final Num leftMove = left().add(perCol.mul(x_from));
|
||||
@@ -131,7 +98,7 @@ public class TiledRect extends RectProxy {
|
||||
*/
|
||||
public Rect column(int n)
|
||||
{
|
||||
return tile(n, based);
|
||||
return tile(n, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -144,6 +111,6 @@ public class TiledRect extends RectProxy {
|
||||
*/
|
||||
public Rect row(int n)
|
||||
{
|
||||
return tile(based, n);
|
||||
return tile(0, n);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public class RectDigest {
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("Rect{ at: (%.1f, %.1f), size: (%.1f, %.1f), bounds: L %.1f R %.1f T %.1f B %.1f }", x, y, width, height, left, right, top, bottom);
|
||||
return String
|
||||
.format("Rect{ at: (%.1f, %.1f), size: (%.1f, %.1f), bounds: L %.1f R %.1f T %.1f B %.1f }", x, y, width, height, left, right, top, bottom);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ public abstract class Vect implements VectBound, Digestable<VectDigest> {
|
||||
private Num p_yc;
|
||||
private Num p_zc;
|
||||
|
||||
private DigestCache<VectDigest> dc = new DigestCache<VectDigest>() {
|
||||
private final DigestCache<VectDigest> dc = new DigestCache<VectDigest>() {
|
||||
|
||||
@Override
|
||||
protected VectDigest createDigest()
|
||||
@@ -1216,4 +1216,16 @@ public abstract class Vect implements VectBound, Digestable<VectDigest> {
|
||||
{
|
||||
return String.format("(%.1f, %.1f, %.1f)", x(), y(), z());
|
||||
}
|
||||
|
||||
|
||||
public final boolean isInside(Rect bounds)
|
||||
{
|
||||
return bounds.contains(this);
|
||||
}
|
||||
|
||||
|
||||
public Rect startRect()
|
||||
{
|
||||
return expand(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* HashSet that buffers add and remove calls and performs them all at once when
|
||||
* a flush() method is called.
|
||||
* HashSet that buffers "add" and "remove" calls and performs them all at once
|
||||
* when a flush() method is called.
|
||||
*
|
||||
* @author MightyPork
|
||||
* @param <E> element type
|
||||
@@ -89,7 +89,7 @@ public class BufferedHashSet<E> extends HashSet<E> {
|
||||
/**
|
||||
* Flush all
|
||||
*/
|
||||
private void flush()
|
||||
public void flush()
|
||||
{
|
||||
for (final E e : toAdd) {
|
||||
super.add(e);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package mightypork.util.control.eventbus;
|
||||
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.DelayQueue;
|
||||
import java.util.concurrent.Delayed;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import mightypork.util.annotations.FactoryMethod;
|
||||
import mightypork.util.control.Destroyable;
|
||||
import mightypork.util.control.eventbus.clients.DelegatingClient;
|
||||
import mightypork.util.control.eventbus.events.Event;
|
||||
@@ -18,29 +19,123 @@ import mightypork.util.logging.Log;
|
||||
|
||||
|
||||
/**
|
||||
* An event bus, accommodating multiple {@link EventChannel}s.
|
||||
* An event bus, accommodating multiple EventChannels.<br>
|
||||
* Channel will be created when an event of type is first encountered.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
final public class EventBus implements Destroyable {
|
||||
|
||||
/** Message channels */
|
||||
private final BufferedHashSet<EventChannel<?, ?>> channels = new BufferedHashSet<>();
|
||||
/**
|
||||
* Queued event holder
|
||||
*/
|
||||
private class DelayQueueEntry implements Delayed {
|
||||
|
||||
private final long due;
|
||||
private final Event<?> evt;
|
||||
|
||||
|
||||
public DelayQueueEntry(double seconds, Event<?> event) {
|
||||
super();
|
||||
this.due = System.currentTimeMillis() + (long) (seconds * 1000);
|
||||
this.evt = event;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(Delayed o)
|
||||
{
|
||||
return Long.valueOf(getDelay(TimeUnit.MILLISECONDS)).compareTo(o.getDelay(TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getDelay(TimeUnit unit)
|
||||
{
|
||||
return unit.convert(due - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
|
||||
public Event<?> getEvent()
|
||||
{
|
||||
return evt;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Registered clients */
|
||||
private final BufferedHashSet<Object> clients = new BufferedHashSet<>();
|
||||
/**
|
||||
* Thread handling queued events
|
||||
*/
|
||||
private class QueuePollingThread extends Thread {
|
||||
|
||||
public volatile boolean stopped = false;
|
||||
|
||||
|
||||
public QueuePollingThread() {
|
||||
super("Queue Polling Thread");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
DelayQueueEntry evt;
|
||||
|
||||
while (!stopped) {
|
||||
evt = null;
|
||||
|
||||
try {
|
||||
evt = sendQueue.take();
|
||||
} catch (final InterruptedException ignored) {
|
||||
//
|
||||
}
|
||||
|
||||
if (evt != null) {
|
||||
dispatch(evt.getEvent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Messages queued for delivery */
|
||||
private final DelayQueue<DelayQueueEntry> sendQueue = new DelayQueue<>();
|
||||
static final String logMark = "<BUS> ";
|
||||
|
||||
|
||||
private static Class<?> getEventListenerClass(Event<?> event)
|
||||
{
|
||||
// BEHOLD, MAGIC!
|
||||
final Type[] interfaces = event.getClass().getGenericInterfaces();
|
||||
for (final Type interf : interfaces) {
|
||||
if (interf instanceof ParameterizedType) {
|
||||
if (((ParameterizedType) interf).getRawType() == Event.class) {
|
||||
final Type[] types = ((ParameterizedType) interf).getActualTypeArguments();
|
||||
for (final Type genericType : types) {
|
||||
return (Class<?>) genericType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Could not detect event listener type.");
|
||||
}
|
||||
|
||||
/** Log detailed messages (debug) */
|
||||
public boolean detailedLogging = false;
|
||||
|
||||
/** Queue polling thread */
|
||||
private final QueuePollingThread busThread;
|
||||
|
||||
/** Registered clients */
|
||||
private final BufferedHashSet<Object> clients = new BufferedHashSet<>();
|
||||
|
||||
/** Whether the bus was destroyed */
|
||||
private boolean dead = false;
|
||||
|
||||
/** Log detailed messages (debug) */
|
||||
public boolean detailedLogging = false;
|
||||
/** Message channels */
|
||||
private final BufferedHashSet<EventChannel<?, ?>> channels = new BufferedHashSet<>();
|
||||
|
||||
/** Messages queued for delivery */
|
||||
private final DelayQueue<DelayQueueEntry> sendQueue = new DelayQueue<>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -53,72 +148,21 @@ final public class EventBus implements Destroyable {
|
||||
}
|
||||
|
||||
|
||||
private boolean shallLog(Event<?> event)
|
||||
{
|
||||
if (!detailedLogging) return false;
|
||||
if (event.getClass().isAnnotationPresent(UnloggedEvent.class)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a {@link EventChannel} to this bus.<br>
|
||||
* If a channel of matching types is already added, it is returned instead.
|
||||
*
|
||||
* @param channel channel to be added
|
||||
* @return the channel that's now in the bus
|
||||
* Halt bus thread and reject any future events.
|
||||
*/
|
||||
public EventChannel<?, ?> addChannel(EventChannel<?, ?> channel)
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
assertLive();
|
||||
|
||||
// if the channel already exists, return this instance instead.
|
||||
for (final EventChannel<?, ?> ch : channels) {
|
||||
if (ch.equals(channel)) {
|
||||
Log.w("<bus> Channel of type " + Log.str(channel) + " already registered.");
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
channels.add(channel);
|
||||
|
||||
return channel;
|
||||
busThread.stopped = true;
|
||||
dead = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make & connect a channel for given event and client type.
|
||||
*
|
||||
* @param eventClass event type
|
||||
* @param clientClass client type
|
||||
* @return the created channel instance
|
||||
*/
|
||||
@FactoryMethod
|
||||
public <F_EVENT extends Event<F_CLIENT>, F_CLIENT> EventChannel<?, ?> addChannel(Class<F_EVENT> eventClass, Class<F_CLIENT> clientClass)
|
||||
{
|
||||
assertLive();
|
||||
|
||||
final EventChannel<F_EVENT, F_CLIENT> channel = EventChannel.create(eventClass, clientClass);
|
||||
return addChannel(channel);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a {@link EventChannel} from this bus
|
||||
*
|
||||
* @param channel true if channel was removed
|
||||
*/
|
||||
public void removeChannel(EventChannel<?, ?> channel)
|
||||
{
|
||||
assertLive();
|
||||
|
||||
channels.remove(channel);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send based on annotation.clients
|
||||
* Send based on annotation
|
||||
*
|
||||
* @param event event
|
||||
*/
|
||||
@@ -166,7 +210,9 @@ final public class EventBus implements Destroyable {
|
||||
|
||||
final DelayQueueEntry dm = new DelayQueueEntry(delay, event);
|
||||
|
||||
if (shallLog(event)) Log.f3("<bus> Qu " + Log.str(event) + ", t = +" + delay + "s");
|
||||
if (shallLog(event)) {
|
||||
Log.f3(logMark + "Qu [" + Log.str(event) + "]" + (delay == 0 ? "" : (", delay: " + delay + "s")));
|
||||
}
|
||||
|
||||
sendQueue.add(dm);
|
||||
}
|
||||
@@ -183,7 +229,7 @@ final public class EventBus implements Destroyable {
|
||||
{
|
||||
assertLive();
|
||||
|
||||
if (shallLog(event)) Log.f3("<bus> Di " + Log.str(event));
|
||||
if (shallLog(event)) Log.f3(logMark + "Di [" + Log.str(event) + "]");
|
||||
|
||||
dispatch(event);
|
||||
}
|
||||
@@ -193,61 +239,12 @@ final public class EventBus implements Destroyable {
|
||||
{
|
||||
assertLive();
|
||||
|
||||
if (shallLog(event)) Log.f3("<bus> Di sub " + Log.str(event));
|
||||
if (shallLog(event)) Log.f3(logMark + "Di->sub [" + Log.str(event) + "]");
|
||||
|
||||
doDispatch(delegatingClient.getChildClients(), event);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send immediately.<br>
|
||||
* Should be used for real-time events that require immediate response, such
|
||||
* as timing events.
|
||||
*
|
||||
* @param event event
|
||||
*/
|
||||
private void dispatch(Event<?> event)
|
||||
{
|
||||
assertLive();
|
||||
|
||||
channels.setBuffering(true);
|
||||
clients.setBuffering(true);
|
||||
|
||||
doDispatch(clients, event);
|
||||
|
||||
channels.setBuffering(false);
|
||||
clients.setBuffering(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send to a set of clients
|
||||
*
|
||||
* @param clients clients
|
||||
* @param event event
|
||||
*/
|
||||
private void doDispatch(Collection<Object> clients, Event<?> event)
|
||||
{
|
||||
boolean sent = false;
|
||||
boolean accepted = false;
|
||||
|
||||
final boolean singular = event.getClass().isAnnotationPresent(SingleReceiverEvent.class);
|
||||
|
||||
for (final EventChannel<?, ?> b : channels) {
|
||||
if (b.canBroadcast(event)) {
|
||||
accepted = true;
|
||||
sent |= b.broadcast(event, clients);
|
||||
}
|
||||
|
||||
if (sent && singular) break;
|
||||
}
|
||||
|
||||
if (!accepted) Log.e("<bus> Not accepted by any channel: " + Log.str(event));
|
||||
if (!sent && shallLog(event)) Log.w("<bus> Not delivered: " + Log.str(event));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Connect a client to the bus. The client will be connected to all current
|
||||
* and future channels, until removed from the bus.
|
||||
@@ -262,7 +259,7 @@ final public class EventBus implements Destroyable {
|
||||
|
||||
clients.add(client);
|
||||
|
||||
if (detailedLogging) Log.f3("<bus> Client joined: " + Log.str(client));
|
||||
if (detailedLogging) Log.f3(logMark + "Client joined: " + Log.str(client));
|
||||
}
|
||||
|
||||
|
||||
@@ -277,111 +274,43 @@ final public class EventBus implements Destroyable {
|
||||
|
||||
clients.remove(client);
|
||||
|
||||
if (detailedLogging) Log.f3("<bus> Client left: " + Log.str(client));
|
||||
if (detailedLogging) Log.f3(logMark + "Client left: " + Log.str(client));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if client can be accepted by any channel
|
||||
*
|
||||
* @param client tested client
|
||||
* @return would be accepted
|
||||
*/
|
||||
public boolean isClientValid(Object client)
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean addChannelForEvent(Event<?> event)
|
||||
{
|
||||
assertLive();
|
||||
|
||||
if (client == null) return false;
|
||||
|
||||
for (final EventChannel<?, ?> ch : channels) {
|
||||
if (ch.isClientValid(client)) {
|
||||
return true;
|
||||
try {
|
||||
if (detailedLogging) {
|
||||
Log.f2(logMark + "Setting up channel for new event type: " + Log.str(event.getClass()));
|
||||
}
|
||||
|
||||
final Class<?> listener = getEventListenerClass(event);
|
||||
final EventChannel<?, ?> ch = EventChannel.create(event.getClass(), listener);
|
||||
|
||||
if (ch.canBroadcast(event)) {
|
||||
|
||||
channels.add(ch);
|
||||
//channels.flush();
|
||||
|
||||
if (detailedLogging) {
|
||||
Log.f2("<bus> Created new channel: " + Log.str(event.getClass()) + " -> " + Log.str(listener));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
Log.w(logMark + "Could not create channel for event " + Log.str(event.getClass()));
|
||||
}
|
||||
|
||||
} catch (final Throwable t) {
|
||||
Log.w(logMark + "Error while trying to add channel for event.", t);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private class DelayQueueEntry implements Delayed {
|
||||
|
||||
private final long due;
|
||||
private Event<?> evt = null;
|
||||
|
||||
|
||||
public DelayQueueEntry(double seconds, Event<?> event) {
|
||||
super();
|
||||
this.due = System.currentTimeMillis() + (long) (seconds * 1000);
|
||||
this.evt = event;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(Delayed o)
|
||||
{
|
||||
return Long.valueOf(getDelay(TimeUnit.MILLISECONDS)).compareTo(o.getDelay(TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getDelay(TimeUnit unit)
|
||||
{
|
||||
return unit.convert(due - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
|
||||
public Event<?> getEvent()
|
||||
{
|
||||
return evt;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class QueuePollingThread extends Thread {
|
||||
|
||||
public boolean stopped = false;
|
||||
|
||||
|
||||
public QueuePollingThread() {
|
||||
super("Queue Polling Thread");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
DelayQueueEntry evt;
|
||||
|
||||
while (!stopped) {
|
||||
evt = null;
|
||||
|
||||
try {
|
||||
evt = sendQueue.take();
|
||||
} catch (final InterruptedException ignored) {
|
||||
//
|
||||
}
|
||||
|
||||
if (evt != null) {
|
||||
dispatch(evt.getEvent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Halt bus thread and reject any future events.
|
||||
*/
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
assertLive();
|
||||
|
||||
busThread.stopped = true;
|
||||
|
||||
dead = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make sure the bus is not destroyed.
|
||||
@@ -393,4 +322,66 @@ final public class EventBus implements Destroyable {
|
||||
if (dead) throw new IllegalStateException("EventBus is dead.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send immediately.<br>
|
||||
* Should be used for real-time events that require immediate response, such
|
||||
* as timing events.
|
||||
*
|
||||
* @param event event
|
||||
*/
|
||||
private synchronized void dispatch(Event<?> event)
|
||||
{
|
||||
assertLive();
|
||||
|
||||
clients.setBuffering(true);
|
||||
doDispatch(clients, event);
|
||||
clients.setBuffering(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send to a set of clients
|
||||
*
|
||||
* @param clients clients
|
||||
* @param event event
|
||||
*/
|
||||
private synchronized void doDispatch(Collection<Object> clients, Event<?> event)
|
||||
{
|
||||
boolean sent = false;
|
||||
boolean accepted = false;
|
||||
|
||||
final boolean singular = event.getClass().isAnnotationPresent(SingleReceiverEvent.class);
|
||||
|
||||
for (int i = 0; i < 2; i++) { // two tries.
|
||||
|
||||
channels.setBuffering(true);
|
||||
for (final EventChannel<?, ?> b : channels) {
|
||||
if (b.canBroadcast(event)) {
|
||||
accepted = true;
|
||||
sent |= b.broadcast(event, clients);
|
||||
}
|
||||
|
||||
if (sent && singular) break;
|
||||
}
|
||||
channels.setBuffering(false);
|
||||
|
||||
if (!accepted) if (addChannelForEvent(event)) continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!accepted) Log.e(logMark + "Not accepted by any channel: " + Log.str(event));
|
||||
if (!sent && shallLog(event)) Log.w(logMark + "Not delivered: " + Log.str(event));
|
||||
}
|
||||
|
||||
|
||||
private boolean shallLog(Event<?> event)
|
||||
{
|
||||
if (!detailedLogging) return false;
|
||||
if (event.getClass().isAnnotationPresent(UnloggedEvent.class)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import mightypork.util.logging.Log;
|
||||
* @param <EVENT> event type
|
||||
* @param <CLIENT> client (subscriber) type
|
||||
*/
|
||||
final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
|
||||
class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
|
||||
|
||||
private final Class<CLIENT> clientClass;
|
||||
private final Class<EVENT> eventClass;
|
||||
@@ -79,7 +79,7 @@ final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
|
||||
|
||||
// avoid executing more times
|
||||
if (processed.contains(client)) {
|
||||
Log.w("<bus> Client already served: " + Log.str(client));
|
||||
Log.w(EventBus.logMark + "Client already served: " + Log.str(client));
|
||||
continue;
|
||||
}
|
||||
processed.add(client);
|
||||
@@ -131,7 +131,7 @@ final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
|
||||
|
||||
|
||||
/**
|
||||
* Check if the given event can be broadcasted by this {@link EventChannel}
|
||||
* Check if the given event can be broadcasted by this channel
|
||||
*
|
||||
* @param event event object
|
||||
* @return can be broadcasted
|
||||
|
||||
@@ -65,9 +65,7 @@ public abstract class BusNode implements BusAccess, ClientHub {
|
||||
throw new IllegalArgumentException("Cannot nest RootBusNode.");
|
||||
}
|
||||
|
||||
if (getEventBus().isClientValid(client)) {
|
||||
clients.add(client);
|
||||
}
|
||||
clients.add(client);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import mightypork.util.control.eventbus.events.flags.UnloggedEvent;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Something that can be handled by HANDLER.
|
||||
* Something that can be handled by HANDLER, subscribing to the event bus.
|
||||
* </p>
|
||||
* <p>
|
||||
* Can be annotated as {@link SingleReceiverEvent} to be delivered once only,
|
||||
|
||||
@@ -72,9 +72,11 @@ public class FileTreeDiff {
|
||||
ck1.reset();
|
||||
ck2.reset();
|
||||
|
||||
try (FileInputStream in1 = new FileInputStream(pair.a); FileInputStream in2 = new FileInputStream(pair.b)) {
|
||||
try(FileInputStream in1 = new FileInputStream(pair.a);
|
||||
FileInputStream in2 = new FileInputStream(pair.b)) {
|
||||
|
||||
try (CheckedInputStream cin1 = new CheckedInputStream(in1, ck1); CheckedInputStream cin2 = new CheckedInputStream(in2, ck2)) {
|
||||
try(CheckedInputStream cin1 = new CheckedInputStream(in1, ck1);
|
||||
CheckedInputStream cin2 = new CheckedInputStream(in2, ck2)) {
|
||||
|
||||
while (true) {
|
||||
final int read1 = cin1.read(BUFFER);
|
||||
|
||||
@@ -95,7 +95,8 @@ public class FileUtils {
|
||||
public static void copyFile(File source, File target) throws IOException
|
||||
{
|
||||
|
||||
try (InputStream in = new FileInputStream(source); OutputStream out = new FileOutputStream(target)) {
|
||||
try(InputStream in = new FileInputStream(source);
|
||||
OutputStream out = new FileOutputStream(target)) {
|
||||
|
||||
copyStream(in, out);
|
||||
}
|
||||
@@ -160,7 +161,7 @@ public class FileUtils {
|
||||
*/
|
||||
public static String fileToString(File file) throws IOException
|
||||
{
|
||||
try (FileInputStream fin = new FileInputStream(file)) {
|
||||
try(FileInputStream fin = new FileInputStream(file)) {
|
||||
|
||||
return streamToString(fin);
|
||||
}
|
||||
@@ -360,7 +361,7 @@ public class FileUtils {
|
||||
*/
|
||||
public static void stringToFile(File file, String text) throws IOException
|
||||
{
|
||||
try (PrintStream out = new PrintStream(new FileOutputStream(file), false, "UTF-8")) {
|
||||
try(PrintStream out = new PrintStream(new FileOutputStream(file), false, "UTF-8")) {
|
||||
|
||||
out.print(text);
|
||||
|
||||
@@ -481,7 +482,8 @@ public class FileUtils {
|
||||
*/
|
||||
public static void resourceToFile(String resname, File file) throws IOException
|
||||
{
|
||||
try (InputStream in = FileUtils.getResource(resname); OutputStream out = new FileOutputStream(file)) {
|
||||
try(InputStream in = FileUtils.getResource(resname);
|
||||
OutputStream out = new FileOutputStream(file)) {
|
||||
|
||||
FileUtils.copyStream(in, out);
|
||||
}
|
||||
@@ -498,7 +500,7 @@ public class FileUtils {
|
||||
*/
|
||||
public static String resourceToString(String resname) throws IOException
|
||||
{
|
||||
try (InputStream in = FileUtils.getResource(resname)) {
|
||||
try(InputStream in = FileUtils.getResource(resname)) {
|
||||
return streamToString(in);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class Ion {
|
||||
*/
|
||||
public static Object fromFile(File file) throws IonException
|
||||
{
|
||||
try (InputStream in = new FileInputStream(file)) {
|
||||
try(InputStream in = new FileInputStream(file)) {
|
||||
|
||||
final Object obj = fromStream(in);
|
||||
return obj;
|
||||
@@ -113,7 +113,7 @@ public class Ion {
|
||||
*/
|
||||
public static void toFile(File path, Object obj) throws IonException
|
||||
{
|
||||
try (OutputStream out = new FileOutputStream(path)) {
|
||||
try(OutputStream out = new FileOutputStream(path)) {
|
||||
final String f = path.toString();
|
||||
final File dir = new File(f.substring(0, f.lastIndexOf(File.separator)));
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public class ZipBuilder {
|
||||
|
||||
out.putNextEntry(new ZipEntry(path));
|
||||
|
||||
try (InputStream in = FileUtils.stringToStream(text)) {
|
||||
try(InputStream in = FileUtils.stringToStream(text)) {
|
||||
FileUtils.copyStream(in, out);
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public class ZipBuilder {
|
||||
|
||||
out.putNextEntry(new ZipEntry(path));
|
||||
|
||||
try (InputStream in = FileUtils.getResource(resPath)) {
|
||||
try(InputStream in = FileUtils.getResource(resPath)) {
|
||||
FileUtils.copyStream(in, out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class ZipUtils {
|
||||
*/
|
||||
public static List<String> extractZip(File file, File outputDir, StringFilter filter) throws IOException
|
||||
{
|
||||
try (ZipFile zip = new ZipFile(file)) {
|
||||
try(ZipFile zip = new ZipFile(file)) {
|
||||
return extractZip(zip, outputDir, filter);
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ public class ZipUtils {
|
||||
*/
|
||||
public static List<String> listZip(File zipFile) throws IOException
|
||||
{
|
||||
try (ZipFile zip = new ZipFile(zipFile)) {
|
||||
try(ZipFile zip = new ZipFile(zipFile)) {
|
||||
return listZip(zip);
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,10 @@ public class ZipUtils {
|
||||
{
|
||||
if (!destFile.getParentFile().mkdirs()) throw new IOException("Could not create output directory.");
|
||||
|
||||
try (InputStream in = zip.getInputStream(entry); BufferedInputStream is = new BufferedInputStream(in); FileOutputStream fos = new FileOutputStream(destFile); BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) {
|
||||
try(InputStream in = zip.getInputStream(entry);
|
||||
BufferedInputStream is = new BufferedInputStream(in);
|
||||
FileOutputStream fos = new FileOutputStream(destFile);
|
||||
BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) {
|
||||
|
||||
FileUtils.copyStream(is, dest);
|
||||
}
|
||||
@@ -168,7 +171,7 @@ public class ZipUtils {
|
||||
|
||||
public static boolean entryExists(File selectedFile, String string)
|
||||
{
|
||||
try (ZipFile zf = new ZipFile(selectedFile)) {
|
||||
try(ZipFile zf = new ZipFile(selectedFile)) {
|
||||
return zf.getEntry(string) != null;
|
||||
} catch (final IOException | RuntimeException e) {
|
||||
Log.w("Error reading zip.", e);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package mightypork.util.math.color;
|
||||
|
||||
|
||||
/**
|
||||
* CGA palette
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface CGA {
|
||||
|
||||
Color BLACK = Color.fromHex(0x000000);
|
||||
Color GRAY_DARK = Color.fromHex(0x686868);
|
||||
Color GRAY_LIGHT = Color.fromHex(0xB8B8B8);
|
||||
Color WHITE = Color.fromHex(0xFFFFFF);
|
||||
|
||||
Color RED_DARK = Color.fromHex(0xC41F0C);
|
||||
Color RED_LIGHT = Color.fromHex(0xFF706A);
|
||||
Color MAGENTA_DARK = Color.fromHex(0xC12BB6);
|
||||
Color MAGENTA_LIGHT = Color.fromHex(0xFF76FD);
|
||||
Color BLUE_DARK = Color.fromHex(0x0019B6);
|
||||
Color BLUE_LIGHT = Color.fromHex(0x5F6EFC);
|
||||
Color CYAN_DARK = Color.fromHex(0x00B6B8);
|
||||
Color CYAN_LIGHT = Color.fromHex(0x23FCFE);
|
||||
Color GREEN_DARK = Color.fromHex(0x00B41D);
|
||||
Color GREEN_LIGHT = Color.fromHex(0x39FA6F);
|
||||
|
||||
Color YELLOW = Color.fromHex(0xFFFD72);
|
||||
Color BROWN = Color.fromHex(0xC16A14);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package mightypork.util.math.color;
|
||||
|
||||
|
||||
/**
|
||||
* COMMODORE palette
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface COMMODORE {
|
||||
|
||||
Color BLACK = Color.fromHex(0x040013);
|
||||
Color WHITE = Color.fromHex(0xFFFFFF);
|
||||
Color RED = Color.fromHex(0x883932);
|
||||
Color CYAN = Color.fromHex(0x67B6BD);
|
||||
Color PURPLE = Color.fromHex(0x8B3F96);
|
||||
Color GREEN = Color.fromHex(0x55A049);
|
||||
Color BLUE = Color.fromHex(0x40318D);
|
||||
Color YELLOW = Color.fromHex(0xBFCE72);
|
||||
Color ORANGE = Color.fromHex(0x8B5429);
|
||||
Color BROWN = Color.fromHex(0x574200);
|
||||
Color RED_LIGHT = Color.fromHex(0xB86962);
|
||||
Color GRAY_DARK = Color.fromHex(0x505050);
|
||||
Color GRAY = Color.fromHex(0x787878);
|
||||
Color GREEN_LIGHT = Color.fromHex(0x94E089);
|
||||
Color BLUE_LIGHT = Color.fromHex(0x7869C4);
|
||||
Color GRAY_LIGHT = Color.fromHex(0x9F9F9F);
|
||||
}
|
||||
@@ -19,9 +19,9 @@ public abstract class Color {
|
||||
public static final Color NONE = rgba(0, 0, 0, 0);
|
||||
public static final Color SHADOW = rgba(0, 0, 0, 0.5);
|
||||
|
||||
public static final Color WHITE = rgb(1, 1, 1);
|
||||
public static final Color BLACK = rgb(0, 0, 0);
|
||||
public static final Color DARK_GRAY = rgb(0.25, 0.25, 0.25);
|
||||
public static final Color WHITE = fromHex(0xFFFFFF);
|
||||
public static final Color BLACK = fromHex(0x000000);
|
||||
public static final Color DARK_GRAY = fromHex(0x808080);
|
||||
public static final Color GRAY = rgb(0.5, 0.5, 0.5);
|
||||
public static final Color LIGHT_GRAY = rgb(0.75, 0.75, 0.75);
|
||||
|
||||
@@ -40,6 +40,16 @@ public abstract class Color {
|
||||
private static volatile boolean alphaStackEnabled = true;
|
||||
|
||||
|
||||
@FactoryMethod
|
||||
public static final Color fromHex(int rgb_hex)
|
||||
{
|
||||
final int bi = rgb_hex & 0xff;
|
||||
final int gi = (rgb_hex >> 8) & 0xff;
|
||||
final int ri = (rgb_hex >> 16) & 0xff;
|
||||
return rgb(ri / 255D, gi / 255D, bi / 255D);
|
||||
}
|
||||
|
||||
|
||||
@FactoryMethod
|
||||
public static final Color rgb(double r, double g, double b)
|
||||
{
|
||||
@@ -163,7 +173,7 @@ public abstract class Color {
|
||||
|
||||
if (alphaStackEnabled) {
|
||||
|
||||
for (Num n : alphaStack) {
|
||||
for (final Num n : alphaStack) {
|
||||
alpha *= clamp(n.value());
|
||||
}
|
||||
}
|
||||
@@ -241,4 +251,16 @@ public abstract class Color {
|
||||
{
|
||||
return alphaStackEnabled;
|
||||
}
|
||||
|
||||
|
||||
public Color withAlpha(double multiplier)
|
||||
{
|
||||
return new ColorAlphaAdjuster(this, Num.make(multiplier));
|
||||
}
|
||||
|
||||
|
||||
public Color withAlpha(Num multiplier)
|
||||
{
|
||||
return new ColorAlphaAdjuster(this, Num.make(multiplier));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package mightypork.util.math.color;
|
||||
|
||||
|
||||
import mightypork.util.constraints.num.Num;
|
||||
|
||||
|
||||
public class ColorAlphaAdjuster extends Color {
|
||||
|
||||
private final Color source;
|
||||
private final Num alphaAdjust;
|
||||
|
||||
|
||||
public ColorAlphaAdjuster(Color source, Num alphaMul) {
|
||||
this.source = source;
|
||||
this.alphaAdjust = alphaMul;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double red()
|
||||
{
|
||||
return source.red();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double green()
|
||||
{
|
||||
return source.green();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double blue()
|
||||
{
|
||||
return source.blue();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected double rawAlpha()
|
||||
{
|
||||
return source.rawAlpha() * alphaAdjust.value();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package mightypork.util.math.color;
|
||||
|
||||
|
||||
/**
|
||||
* PAL16 palette via http://androidarts.com/palette/16pal.htm
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface PAL16 {
|
||||
|
||||
Color VOID = Color.fromHex(0x000000);
|
||||
Color ASH = Color.fromHex(0x9D9D9D);
|
||||
Color BLIND = Color.fromHex(0xFFFFFF);
|
||||
|
||||
Color BLOODRED = Color.fromHex(0xBE2633);
|
||||
Color PIGMEAT = Color.fromHex(0xE06F8B);
|
||||
|
||||
Color OLDPOOP = Color.fromHex(0x493C2B);
|
||||
Color NEWPOOP = Color.fromHex(0xA46422);
|
||||
Color BLAZE = Color.fromHex(0xEB8931);
|
||||
Color ZORNSKIN = Color.fromHex(0xF7E26B);
|
||||
|
||||
Color SHADEGREEN = Color.fromHex(0x2F484E);
|
||||
Color LEAFGREEN = Color.fromHex(0x44891A);
|
||||
Color SLIMEGREEN = Color.fromHex(0xA3CE27);
|
||||
|
||||
Color NIGHTBLUE = Color.fromHex(0x1B2632);
|
||||
Color SEABLUE = Color.fromHex(0x005784);
|
||||
Color SKYBLUE = Color.fromHex(0x31A2F2);
|
||||
Color CLOUDBLUE = Color.fromHex(0xB2DCEF);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package mightypork.util.math.color;
|
||||
|
||||
|
||||
/**
|
||||
* Basic RGB palette
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface RGB {
|
||||
|
||||
Color WHITE = Color.fromHex(0xFFFFFF);
|
||||
Color BLACK = Color.fromHex(0x000000);
|
||||
Color GRAY_DARK = Color.fromHex(0x808080);
|
||||
Color GRAY_LIGHT = Color.fromHex(0xC0C0C0);
|
||||
|
||||
Color RED = Color.fromHex(0xFF0000);
|
||||
Color GREEN = Color.fromHex(0x00FF00);
|
||||
Color BLUE = Color.fromHex(0x0000FF);
|
||||
|
||||
Color YELLOW = Color.fromHex(0xFFFF00);
|
||||
Color CYAN = Color.fromHex(0x00FFFF);
|
||||
Color MAGENTA = Color.fromHex(0xFF00FF);
|
||||
|
||||
Color PINK = Color.fromHex(0xFF3FFC);
|
||||
Color ORANGE = Color.fromHex(0xFC4800);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package mightypork.util.math.color;
|
||||
|
||||
|
||||
/**
|
||||
* ZX Spectrum palette
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface ZX {
|
||||
|
||||
Color BLACK = Color.fromHex(0x000000);
|
||||
Color GRAY = Color.fromHex(0xCBCBCB);
|
||||
Color WHITE = Color.fromHex(0xFFFFFF);
|
||||
|
||||
Color RED_DARK = Color.fromHex(0xD8240F);
|
||||
Color RED_LIGHT = Color.fromHex(0xFF3016);
|
||||
Color MAGENTA_DARK = Color.fromHex(0xD530C9);
|
||||
Color MAGENTA_LIGHT = Color.fromHex(0xFF3FFC);
|
||||
Color BLUE_DARK = Color.fromHex(0x001DC8);
|
||||
Color BLUE_LIGHT = Color.fromHex(0x0027FB);
|
||||
Color CYAN_DARK = Color.fromHex(0x00C9CB);
|
||||
Color CYAN_LIGHT = Color.fromHex(0xFFFD33);
|
||||
Color GREEN_DARK = Color.fromHex(0x00C721);
|
||||
Color GREEN_LIGHT = Color.fromHex(0x00F92C);
|
||||
|
||||
Color YELLOW_DARK = Color.fromHex(0xCECA26);
|
||||
Color YELLOW_LIGHT = Color.fromHex(0xFFFD33);
|
||||
}
|
||||
Reference in New Issue
Block a user