-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Reimplemented the event queue - Added WAIT action
- Loading branch information
Showing
10 changed files
with
351 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
190 changes: 190 additions & 0 deletions
190
src/main/java/net/programmer/igoodie/twitchspawn/eventqueue/EventQueue.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
package net.programmer.igoodie.twitchspawn.eventqueue; | ||
|
||
import net.minecraft.entity.player.ServerPlayerEntity; | ||
import net.minecraftforge.fml.network.NetworkDirection; | ||
import net.programmer.igoodie.twitchspawn.TwitchSpawn; | ||
import net.programmer.igoodie.twitchspawn.network.NetworkManager; | ||
import net.programmer.igoodie.twitchspawn.network.packet.GlobalChatCooldownPacket; | ||
import net.programmer.igoodie.twitchspawn.tslanguage.EventArguments; | ||
import net.programmer.igoodie.twitchspawn.tslanguage.event.TSLEvent; | ||
import net.programmer.igoodie.twitchspawn.util.CooldownBucket; | ||
|
||
import java.util.Deque; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
|
||
public class EventQueue { | ||
|
||
private final Thread innerThread; | ||
private volatile EventQueueState state; | ||
private volatile Deque<EventQueueTask> tasks; | ||
private volatile boolean waitingForServer; | ||
private long cooldown; // milliseconds | ||
private int succeededEvents; | ||
private int discardedEvents; | ||
|
||
public EventQueue(long cooldownDuration) { | ||
this.innerThread = new Thread(() -> { | ||
while (true) stepThread(); | ||
}, "TwitchSpawn Event Queue"); | ||
this.state = EventQueueState.PAUSED; | ||
this.tasks = new LinkedList<>(); | ||
this.cooldown = cooldownDuration; | ||
|
||
this.innerThread.start(); | ||
} | ||
|
||
private void stepThread() { | ||
try { | ||
if (hasUnhandledEvent()) { | ||
if (waitingForServer) { | ||
// TODO: Sleep? | ||
return; | ||
} | ||
|
||
EventQueueTask task = tasks.remove(); | ||
|
||
if (task.getType() == EventQueueTask.Type.SLEEP) | ||
state = EventQueueState.COOLDOWN; | ||
|
||
task.run(); | ||
|
||
if (task.getType() == EventQueueTask.Type.SLEEP) | ||
state = EventQueueState.WORKING; | ||
|
||
} else { | ||
pause(); | ||
} | ||
|
||
} catch (Throwable e) { | ||
discardedEvents++; | ||
e.printStackTrace(); // TODO: | ||
} | ||
} | ||
|
||
private void unpause() { | ||
synchronized (innerThread) { | ||
state = EventQueueState.WORKING; | ||
innerThread.notifyAll(); | ||
} | ||
} | ||
|
||
private void pause() { | ||
synchronized (innerThread) { | ||
try { | ||
state = EventQueueState.PAUSED; | ||
innerThread.wait(); | ||
|
||
} catch (InterruptedException e) { | ||
e.printStackTrace(); // TODO | ||
} | ||
} | ||
} | ||
|
||
public void updateThread() { | ||
if (state == EventQueueState.PAUSED) unpause(); | ||
} | ||
|
||
public void cancelUpcomingSleep() { | ||
assert this.tasks instanceof LinkedList; | ||
List<EventQueueTask> tasks = (LinkedList<EventQueueTask>) this.tasks; | ||
for (int i = 0; i < tasks.size(); i++) { | ||
EventQueueTask task = tasks.get(i); | ||
if (task.getType() == EventQueueTask.Type.SLEEP) { | ||
tasks.remove(i); | ||
return; | ||
} | ||
} | ||
} | ||
|
||
public void queueSleepFirst() { | ||
queueSleepFirst(cooldown); | ||
} | ||
|
||
public void queueSleepFirst(long millis) { | ||
tasks.addFirst(new EventQueueTask("Sleep", millis)); | ||
} | ||
|
||
public void queueSleep() { | ||
queueSleep(cooldown); | ||
} | ||
|
||
public void queueSleep(long millis) { | ||
tasks.add(new EventQueueTask("Sleep", millis)); | ||
} | ||
|
||
public void queueFirst(String name, Runnable task) { | ||
tasks.addFirst(new EventQueueTask(name, task)); | ||
|
||
} | ||
|
||
public void queue(Runnable task) { | ||
queue("Runnable task", task); | ||
} | ||
|
||
public void queue(String name, Runnable task) { | ||
tasks.add(new EventQueueTask(name, task)); | ||
} | ||
|
||
public void queue(TSLEvent eventNode, EventArguments args, CooldownBucket cooldownBucket) { | ||
if (eventNode.willPerform(args)) { | ||
if (cooldownBucket != null) { | ||
cooldownBucket.consume(args.actorNickname); | ||
|
||
ServerPlayerEntity playerEntity = TwitchSpawn.SERVER | ||
.getPlayerList() | ||
.getPlayerByUsername(args.streamerNickname); | ||
|
||
if (playerEntity != null) { | ||
NetworkManager.CHANNEL.sendTo( | ||
new GlobalChatCooldownPacket(cooldownBucket.getGlobalCooldownTimestamp()), | ||
playerEntity.connection.netManager, | ||
NetworkDirection.PLAY_TO_CLIENT | ||
); | ||
} | ||
} | ||
} | ||
|
||
tasks.add(new EventQueueTask("TSL Event task", () -> { | ||
waitingForServer = true; | ||
TwitchSpawn.SERVER.execute(() -> { | ||
try { | ||
boolean performed = eventNode.process(args); | ||
|
||
if (performed) succeededEvents++; | ||
else discardedEvents++; | ||
|
||
} catch (Throwable e) { | ||
discardedEvents++; | ||
// TODO: "Event failed HUD" maybe? | ||
|
||
} finally { | ||
waitingForServer = false; | ||
} | ||
}); | ||
})); | ||
} | ||
|
||
public synchronized int succeededEventCount() { | ||
return succeededEvents; | ||
} | ||
|
||
public synchronized int discardedEventCount() { | ||
return discardedEvents; | ||
} | ||
|
||
public synchronized int unhandledEventCount() { | ||
return tasks.size(); | ||
} | ||
|
||
public synchronized boolean hasUnhandledEvent() { | ||
return !tasks.isEmpty(); | ||
} | ||
|
||
public void reset() { | ||
tasks.clear(); | ||
succeededEvents = 0; | ||
discardedEvents = 0; | ||
} | ||
|
||
} |
9 changes: 9 additions & 0 deletions
9
src/main/java/net/programmer/igoodie/twitchspawn/eventqueue/EventQueueState.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package net.programmer.igoodie.twitchspawn.eventqueue; | ||
|
||
public enum EventQueueState { | ||
|
||
WORKING, | ||
COOLDOWN, | ||
PAUSED | ||
|
||
} |
77 changes: 77 additions & 0 deletions
77
src/main/java/net/programmer/igoodie/twitchspawn/eventqueue/EventQueueTask.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package net.programmer.igoodie.twitchspawn.eventqueue; | ||
|
||
import java.util.Timer; | ||
import java.util.TimerTask; | ||
|
||
public class EventQueueTask { | ||
|
||
final String name; | ||
Runnable routine; | ||
long cooldown; | ||
|
||
public EventQueueTask(Runnable routine) { | ||
this("Runnable task", routine); | ||
} | ||
|
||
public EventQueueTask(String name, Runnable routine) { | ||
this.name = name; | ||
this.routine = routine; | ||
} | ||
|
||
public EventQueueTask(long cooldown) { | ||
this("Cooldown task", cooldown); | ||
} | ||
|
||
public EventQueueTask(String name, long cooldown) { | ||
this.name = name; | ||
this.cooldown = cooldown; | ||
} | ||
|
||
private void sleep(long millis) throws InterruptedException { | ||
final Thread currentThread = Thread.currentThread(); | ||
synchronized (currentThread) { | ||
new Timer().schedule(new TimerTask() { | ||
@Override | ||
public void run() { | ||
synchronized (currentThread) { | ||
currentThread.notifyAll(); | ||
} | ||
} | ||
}, cooldown); | ||
|
||
currentThread.wait(); | ||
} | ||
} | ||
|
||
public void run() throws InterruptedException { | ||
switch (getType()) { | ||
case SLEEP: | ||
sleep(cooldown); | ||
return; | ||
|
||
case ROUTINE: | ||
routine.run(); | ||
return; | ||
|
||
default: | ||
System.out.println("Wut?"); | ||
} | ||
} | ||
|
||
public Type getType() { | ||
if (routine != null) return Type.ROUTINE; | ||
return Type.SLEEP; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return name + (cooldown == 0 ? "" : String.format("(%d)", cooldown)); | ||
} | ||
|
||
/* --------------------------------- */ | ||
|
||
public enum Type { | ||
SLEEP, ROUTINE | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.