8 Commits
v5 ... v5d
28 changed files with 168 additions and 217 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
/bin/
/target/
/~local/
/.rogue-save/
/build/.rogue-save/
/build/out/.rogue-save/
/build/
/build/out/*.jar
/build/in/*.jar
*.log
Binary file not shown.
Binary file not shown.
@@ -15,20 +15,23 @@ import mightypork.gamecore.eventbus.event_flags.SingleReceiverEvent;
public class MainLoopRequest extends BusEvent<MainLoop> {
private final Runnable task;
private final boolean priority;
/**
* @param task task to run on main thread in rendering context
* @param priority if true, skip other tasks in queue
*/
public MainLoopRequest(Runnable task)
public MainLoopRequest(Runnable task, boolean priority)
{
this.task = task;
this.priority = priority;
}
@Override
public void handleBy(MainLoop handler)
{
handler.queueTask(task);
handler.queueTask(task, priority);
}
}
@@ -5,6 +5,7 @@ import mightypork.gamecore.core.modules.MainLoop;
import mightypork.gamecore.eventbus.BusEvent;
import mightypork.gamecore.eventbus.event_flags.NonConsumableEvent;
import mightypork.gamecore.eventbus.event_flags.SingleReceiverEvent;
import mightypork.gamecore.resources.audio.SoundSystem;
/**
@@ -27,6 +28,6 @@ public class ShudownRequest extends BusEvent<MainLoop> {
{
handler.shutdown();
}
});
}, true);
}
}
@@ -1,14 +1,18 @@
package mightypork.gamecore.core.modules;
import java.util.Deque;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
import mightypork.gamecore.eventbus.events.UpdateEvent;
import mightypork.gamecore.gui.screens.ScreenRegistry;
import mightypork.gamecore.logging.Log;
import mightypork.gamecore.render.Renderable;
import mightypork.gamecore.render.TaskTakeScreenshot;
import mightypork.gamecore.render.events.ScreenshotRequestListener;
import mightypork.gamecore.resources.Profiler;
import mightypork.gamecore.util.Utils;
import mightypork.gamecore.util.annot.DefaultImpl;
import mightypork.gamecore.util.math.timing.TimerDelta;
@@ -21,7 +25,10 @@ import mightypork.gamecore.util.math.timing.TimerDelta;
*/
public class MainLoop extends AppModule implements ScreenshotRequestListener {
private final Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<>();
private static final double MAX_TIME_TASKS = 1 / 30D; // (avoid queue from hogging timing)
private static final double MAX_DELTA = 1 / 20D; // (skip huge gaps caused by loading resources etc)
private final Deque<Runnable> tasks = new ConcurrentLinkedDeque<>();
private TimerDelta timer;
private Renderable rootRenderable;
private volatile boolean running = true;
@@ -58,11 +65,23 @@ public class MainLoop extends AppModule implements ScreenshotRequestListener {
while (running) {
getDisplay().beginFrame();
getEventBus().sendDirect(new UpdateEvent(timer.getDelta()));
double delta = timer.getDelta();
if (delta > MAX_DELTA) {
Log.f3("(timing) Cropping delta: was " + delta + " , limit " + MAX_DELTA);
delta = MAX_DELTA;
}
getEventBus().sendDirect(new UpdateEvent(delta));
Runnable r;
while ((r = taskQueue.poll()) != null) {
long t = Profiler.begin();
while ((r = tasks.poll()) != null) {
Log.f3(" * Main loop task.");
r.run();
if (Profiler.end(t) > MAX_TIME_TASKS) {
Log.f3("! Postponing main loop tasks to next cycle.");
break;
}
}
beforeRender();
@@ -109,10 +128,15 @@ public class MainLoop extends AppModule implements ScreenshotRequestListener {
* Add a task to queue to be executed in the main loop (OpenGL thread)
*
* @param request task
* @param priority if true, skip other tasks
*/
public synchronized void queueTask(Runnable request)
public synchronized void queueTask(Runnable request, boolean priority)
{
taskQueue.add(request);
if (priority) {
tasks.addFirst(request);
} else {
tasks.addLast(request);
}
}
@@ -127,7 +151,7 @@ public class MainLoop extends AppModule implements ScreenshotRequestListener {
{
Utils.runAsThread(new TaskTakeScreenshot());
}
});
}, false);
}
}
@@ -1,153 +0,0 @@
package mightypork.gamecore.eventbus;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
/**
* 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
*/
public class BufferedHashSet<E> extends HashSet<E> {
private final List<E> toAdd = new LinkedList<>();
private final List<Object> toRemove = new LinkedList<>();
private boolean buffering = false;
/**
* make empty
*/
public BufferedHashSet()
{
super();
}
/**
* make from elements of a collection
*
* @param c
*/
public BufferedHashSet(Collection<? extends E> c)
{
super(c);
}
/**
* make new
*
* @param initialCapacity
* @param loadFactor
*/
public BufferedHashSet(int initialCapacity, float loadFactor)
{
super(initialCapacity, loadFactor);
}
/**
* make new
*
* @param initialCapacity
*/
public BufferedHashSet(int initialCapacity)
{
super(initialCapacity);
}
@Override
public boolean add(E e)
{
if (buffering) {
toAdd.add(e);
} else {
super.add(e);
}
return true;
}
@Override
public boolean remove(Object e)
{
if (buffering) {
toRemove.add(e);
} else {
super.remove(e);
}
return true;
}
/**
* Flush all
*/
public void flush()
{
for (final E e : toAdd) {
super.add(e);
}
for (final Object e : toRemove) {
super.remove(e);
}
toAdd.clear();
toRemove.clear();
}
@Override
public boolean removeAll(Collection<?> c)
{
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection<?> c)
{
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection<? extends E> c)
{
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c)
{
throw new UnsupportedOperationException();
}
/**
* Toggle buffering
*
* @param enable enable buffering
*/
public void setBuffering(boolean enable)
{
if (this.buffering && !enable) {
flush();
}
this.buffering = enable;
}
}
@@ -4,6 +4,9 @@ package mightypork.gamecore.eventbus;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
@@ -104,7 +107,7 @@ final public class EventBus implements Destroyable, BusAccess {
}
static final String logMark = "<BUS> ";
static final String logMark = "(bus) ";
private static Class<?> getEventListenerClass(BusEvent<?> event)
@@ -132,13 +135,13 @@ final public class EventBus implements Destroyable, BusAccess {
private final QueuePollingThread busThread;
/** Registered clients */
private final BufferedHashSet<Object> clients = new BufferedHashSet<>();
private final Set<Object> clients = Collections.newSetFromMap(new ConcurrentHashMap<Object,Boolean>());
/** Whether the bus was destroyed */
private boolean dead = false;
/** Message channels */
private final ConcurrentLinkedDeque<EventChannel<?, ?>> channels = new ConcurrentLinkedDeque<>();
private final Set<EventChannel<?, ?>> channels = Collections.newSetFromMap(new ConcurrentHashMap<EventChannel<?, ?>,Boolean>());
/** Messages queued for delivery */
private final DelayQueue<DelayQueueEntry> sendQueue = new DelayQueue<>();
@@ -341,12 +344,8 @@ final public class EventBus implements Destroyable, BusAccess {
{
assertLive();
clients.setBuffering(true);
doDispatch(clients, event);
event.onDispatchComplete(this);
clients.setBuffering(false);
}
@@ -6,6 +6,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
import org.newdawn.slick.opengl.GLUtils;
import mightypork.gamecore.core.modules.AppAccess;
import mightypork.gamecore.core.modules.AppModule;
import mightypork.gamecore.gui.events.LayoutChangeEvent;
@@ -83,6 +85,8 @@ public class ScreenRegistry extends AppModule implements ScreenRequestListener,
toShow.setActive(true);
active = toShow;
fireLayoutUpdateEvent();
}
@@ -110,7 +114,7 @@ public class ScreenRegistry extends AppModule implements ScreenRequestListener,
@Override
public void onViewportChanged(ViewportChangeEvent event)
{
fireLayoutUpdateEvent();
if(active != null) fireLayoutUpdateEvent();
}
@@ -67,6 +67,11 @@ public class CrossfadeOverlay extends Overlay {
{
requestedScreenName = screen;
if(screen == null) {
// going for halt
getSoundSystem().fadeOutAllLoops();
}
if (fromDark) {
alpha.setTo(1);
revealTask.run();
@@ -3,6 +3,7 @@ package mightypork.gamecore.gui.screens.impl;
import mightypork.gamecore.gui.screens.Screen;
import mightypork.gamecore.gui.screens.ScreenLayer;
import mightypork.gamecore.util.annot.DefaultImpl;
import mightypork.gamecore.util.math.Easing;
import mightypork.gamecore.util.math.constraints.num.mutable.NumAnimated;
import mightypork.gamecore.util.math.timing.TimedTask;
@@ -73,6 +74,7 @@ public abstract class FadingLayer extends ScreenLayer {
/**
* Called after the fade-out was completed
*/
@DefaultImpl
protected void onHideFinished()
{
}
@@ -81,6 +83,7 @@ public abstract class FadingLayer extends ScreenLayer {
/**
* Called after the fade-in was completed
*/
@DefaultImpl
protected void onShowFinished()
{
}
@@ -98,6 +101,7 @@ public abstract class FadingLayer extends ScreenLayer {
super.show();
numa.fadeIn();
hideTimer.stop();
showTimer.start(numa.getDefaultDuration());
fadingOut = false;
fadingIn = true;
@@ -18,7 +18,7 @@ import mightypork.gamecore.logging.Log;
*/
public class AsyncResourceLoader extends Thread implements ResourceLoader, Destroyable {
private final ExecutorService exs = Executors.newCachedThreadPool();
private final ExecutorService exs = Executors.newFixedThreadPool(2);
private final LinkedBlockingQueue<LazyResource> toLoad = new LinkedBlockingQueue<>();
private volatile boolean stopped;
@@ -57,9 +57,9 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
if (resource.getClass().isAnnotationPresent(TextureBasedResource.class)) {
if (!mainLoopQueuing) {
Log.f3("<LOADER> Cannot load async: " + Log.str(resource));
// just let it be
} else {
Log.f3("<LOADER> Delegating to main thread:\n " + Log.str(resource));
Log.f3("(loader) Delegating to main thread: " + Log.str(resource));
app.getEventBus().send(new MainLoopRequest(new Runnable() {
@@ -68,7 +68,7 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
{
resource.load();
}
}));
}, false));
}
return;
@@ -91,15 +91,17 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
if (!def.isLoaded()) {
Log.f3("<LOADER> Loading: " + Log.str(def));
Log.f3("(loader) Scheduling... " + Log.str(def));
exs.submit(new Runnable() {
@Override
public void run()
{
if(!def.isLoaded()) {
def.load();
}
}
});
}
@@ -6,6 +6,8 @@ import java.io.IOException;
import mightypork.gamecore.eventbus.events.Destroyable;
import mightypork.gamecore.logging.Log;
import mightypork.gamecore.logging.LogAlias;
import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.strings.StringUtils;
/**
@@ -34,8 +36,12 @@ public abstract class BaseLazyResource implements LazyResource, Destroyable {
@Override
public synchronized final void load()
{
if (loadFailed) return;
if (loadAttempted) return;
if (!loadFailed && loadAttempted) return;
//
// if (loadFailed) return;
// if (loadAttempted) return;
//
loadAttempted = true;
loadFailed = false;
@@ -45,12 +51,14 @@ public abstract class BaseLazyResource implements LazyResource, Destroyable {
throw new NullPointerException("Resource string cannot be null for non-null resource.");
}
Log.f3("<RES> Loading: " + this);
long time = Profiler.begin();
Log.f3("(res) + Load: " + this);
loadResource(resource);
Log.f3("<RES> Loaded: " + this);
Log.f3("(res) - Done: " + this + " in " + Profiler.endStr(time));
} catch (final Throwable t) {
loadFailed = true;
Log.e("<RES> Failed to load: " + this, t);
Log.e("(res) Failed to load: " + this, t);
}
}
@@ -74,7 +82,7 @@ public abstract class BaseLazyResource implements LazyResource, Destroyable {
} else {
if (loadFailed) return false;
Log.f3("<RES> (!) Loading on access: " + this);
Log.f3("(res) !! Loading on access: " + this);
load();
}
@@ -99,7 +107,7 @@ public abstract class BaseLazyResource implements LazyResource, Destroyable {
@Override
public String toString()
{
return Log.str(getClass()) + "(\"" + resource + "\")";
return StringUtils.fromLastChar(resource, '/');
}
@@ -0,0 +1,32 @@
package mightypork.gamecore.resources;
import mightypork.gamecore.util.math.Calc;
public class Profiler {
public static long begin()
{
return System.currentTimeMillis();
}
public static double end(long begun)
{
return endLong(begun) / 1000D;
}
public static long endLong(long begun)
{
return System.currentTimeMillis() - begun;
}
public static String endStr(long begun)
{
return Calc.toString(end(begun)) + " s";
}
}
+1 -1
View File
@@ -94,8 +94,8 @@ public final class Res {
public static void load(ResourceSetup binder)
{
binder.addFonts(fonts);
binder.addSounds(sounds);
binder.addTextures(textures);
binder.addSounds(sounds);
}
}
@@ -2,7 +2,9 @@ package mightypork.gamecore.resources.audio;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import mightypork.gamecore.core.modules.AppAccess;
@@ -71,8 +73,8 @@ public class SoundSystem extends RootBusNode implements Updateable {
private final Volume effectsVolume = new JointVolume(masterVolume);
private final Volume loopsVolume = new JointVolume(masterVolume);
private final Set<LoopPlayer> loopPlayers = new HashSet<>();
private final Set<LazyAudio> resources = new HashSet<>();
private final List<LoopPlayer> loopPlayers = new ArrayList<>();
private final List<LazyAudio> resources = new ArrayList<>();
/**
@@ -130,7 +132,7 @@ public class SoundSystem extends RootBusNode implements Updateable {
*/
public EffectPlayer createEffect(String resource, double pitch, double gain)
{
return new EffectPlayer(getResource(resource), pitch, gain, effectsVolume);
return new EffectPlayer(createResource(resource), pitch, gain, effectsVolume);
}
@@ -146,7 +148,7 @@ public class SoundSystem extends RootBusNode implements Updateable {
*/
public LoopPlayer createLoop(String resource, double pitch, double gain, double fadeIn, double fadeOut)
{
final LoopPlayer p = new LoopPlayer(getResource(resource), pitch, gain, loopsVolume);
final LoopPlayer p = new LoopPlayer(createResource(resource), pitch, gain, loopsVolume);
p.setFadeTimes(fadeIn, fadeOut);
loopPlayers.add(p);
return p;
@@ -160,12 +162,10 @@ public class SoundSystem extends RootBusNode implements Updateable {
* @return the resource
* @throws IllegalArgumentException if resource is already registered
*/
private LazyAudio getResource(String res)
private LazyAudio createResource(String res)
{
final LazyAudio a = new LazyAudio(res);
getEventBus().send(new ResourceLoadRequest(a));
if (resources.contains(a)) throw new IllegalArgumentException("Sound resource " + res + " is already registered.");
resources.add(a);
return a;
}
@@ -98,6 +98,8 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
sourceID = getAudio().resumeLoop();
paused = false;
adjustGain(getGain(fadeAnim.value()));
}
@@ -112,7 +114,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
final double gain = getGain(fadeAnim.value());
if (!paused && gain != lastUpdateGain) {
AL10.alSourcef(sourceID, AL10.AL_GAIN, (float) gain);
adjustGain(gain);
lastUpdateGain = gain;
}
@@ -120,6 +122,12 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
}
private void adjustGain(double gain)
{
AL10.alSourcef(sourceID, AL10.AL_GAIN, (float) gain);
}
/**
* Resume if paused, and fade in (pick up from current volume).
*
@@ -129,6 +137,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
{
if (!hasAudio()) return;
if (isPaused()) fadeAnim.setTo(0);
resume();
fadeAnim.fadeIn(secs);
}
@@ -142,7 +151,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable
public void fadeOut(double secs)
{
if (!hasAudio()) return;
if (isPaused()) return;
fadeAnim.fadeOut(secs);
}
@@ -1,6 +1,7 @@
package mightypork.gamecore.resources.fonts;
import mightypork.gamecore.resources.TextureBasedResource;
import mightypork.gamecore.util.math.color.Color;
import mightypork.gamecore.util.math.constraints.vect.Vect;
@@ -19,6 +19,7 @@ import java.util.List;
import java.util.Map;
import mightypork.gamecore.logging.Log;
import mightypork.gamecore.resources.TextureBasedResource;
import mightypork.gamecore.resources.fonts.GLFont;
import mightypork.gamecore.resources.textures.FilterMode;
import mightypork.gamecore.resources.textures.LazyTexture;
+1 -1
View File
@@ -139,7 +139,7 @@ public final class RogueApp extends BaseApp implements ViewportChangeListener, S
getEventBus().send(new RogueStateRequest(RogueState.MAIN_MENU, true));
}
}
}));
}, false));
}
@@ -65,12 +65,12 @@ public class EntityBrownRat extends Entity {
{
// drop rat stuff
if (Calc.rand.nextInt(2) == 0) {
if (Calc.rand.nextInt(2) != 0) {
getLevel().dropNear(getCoord(), Items.MEAT.createItem());
return;
}
if (Calc.rand.nextInt(4) == 0) {
if (Calc.rand.nextInt(3) == 0) {
getLevel().dropNear(getCoord(), Items.CHEESE.createItem());
return;
}
@@ -17,12 +17,15 @@ public class StorageRoom extends SecretRoom {
{
int maxStuff = Calc.randInt(rand, 3, 5);
for (int i = 0; i < Calc.randInt(rand, 0, 2); i++) {
// at least one meat or cheese.
boolean oneMeat = rand.nextBoolean();
for (int i = 0; i < Calc.randInt(rand, oneMeat ? 1 : 0, 3); i++) {
map.addItemInArea(Items.MEAT.createItem(), min, max, 50);
if (--maxStuff == 0) return;
}
for (int i = 0; i < Calc.randInt(rand, 0, 2); i++) {
for (int i = 0; i < Calc.randInt(rand, oneMeat ? 0 : 1, 2); i++) {
map.addItemInArea(Items.CHEESE.createItem(), min, max, 50);
if (--maxStuff == 0) return;
}
+9 -5
View File
@@ -5,15 +5,17 @@ import java.io.IOException;
import mightypork.gamecore.logging.Log;
import mightypork.gamecore.util.annot.DefaultImpl;
import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonObjBlob;
import mightypork.gamecore.util.ion.IonObjBundled;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.rogue.world.PlayerFacade;
public abstract class Item implements IonObjBlob {
public abstract class Item implements IonObjBundled {
private final ItemModel model;
private ItemRenderer renderer;
@@ -42,17 +44,19 @@ public abstract class Item implements IonObjBlob {
@Override
@DefaultImpl
public void save(IonOutput out) throws IOException
public void save(IonBundle out) throws IOException
{
out.writeIntShort(amount);
out.put("c", amount);
out.put("u", uses);
}
@Override
@DefaultImpl
public void load(IonInput in) throws IOException
public void load(IonBundle in) throws IOException
{
amount = in.readIntShort();
amount = in.get("c", amount);
uses = in.get("u", uses);
}
@@ -3,6 +3,8 @@ package mightypork.rogue.world.item;
import java.io.IOException;
import mightypork.gamecore.util.ion.Ion;
import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.gamecore.util.math.Calc;
@@ -46,7 +48,7 @@ public final class ItemModel {
}
public Item loadItem(IonInput in) throws IOException
public Item loadItem(IonBundle in) throws IOException
{
final Item t = createItem();
t.load(in);
@@ -54,11 +56,10 @@ public final class ItemModel {
}
public void saveItem(IonOutput out, Item tile) throws IOException
public void saveItem(IonBundle out, Item item) throws IOException
{
if (itemClass != tile.getClass()) throw new RuntimeException("Item class mismatch.");
tile.save(out);
if (itemClass != item.getClass()) throw new RuntimeException("Item class mismatch.");
item.save(out);
}
+6 -3
View File
@@ -4,6 +4,7 @@ package mightypork.rogue.world.item;
import java.io.IOException;
import java.util.Collection;
import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.rogue.world.item.impl.active.ItemHeartPiece;
@@ -64,9 +65,8 @@ public final class Items {
public static Item loadItem(IonInput in) throws IOException
{
final int id = in.readIntByte();
final ItemModel model = get(id);
return model.loadItem(in);
return model.loadItem(in.readBundle());
}
@@ -75,7 +75,10 @@ public final class Items {
final ItemModel model = item.getModel();
out.writeIntByte(model.id);
model.saveItem(out, item);
IonBundle ib = new IonBundle();
model.saveItem(ib, item);
out.writeBundle(ib);
}
@@ -33,7 +33,7 @@ public class ItemKnife extends ItemBaseWeapon {
@Override
public int getMaxUses()
{
return 60;
return 70;
}
@@ -33,7 +33,7 @@ public class ItemRock extends ItemBaseWeapon {
@Override
public int getMaxUses()
{
return 30;
return 35;
}
@@ -33,7 +33,7 @@ public class ItemSword extends ItemBaseWeapon {
@Override
public int getMaxUses()
{
return 200;
return 210;
}