summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Vink <mike1994vink@gmail.com>2021-07-30 13:41:55 +0200
committerMike Vink <mike1994vink@gmail.com>2021-07-30 13:41:55 +0200
commit04b66877f2608d0ee6586e3197569a6289087d58 (patch)
tree24455b84a334e6ba39a293c2ee2c4128b6eaa085
parentc0004768de6695e2acfa48c392765b03b81ba9d0 (diff)
feat(): Working on battle UI
-rw-r--r--api/src/main/java/akkamon/api/MessagingEngine.java24
-rw-r--r--api/src/main/java/akkamon/api/models/BattleInitEvent.java15
-rw-r--r--api/src/main/java/akkamon/api/models/EventType.java3
-rw-r--r--client/src/akkamon/GameConfig.ts7
-rw-r--r--client/src/akkamon/PhaserTypes.ts2
-rw-r--r--client/src/akkamon/client/Client.ts36
-rw-r--r--client/src/akkamon/client/EventType.ts3
-rw-r--r--client/src/akkamon/client/InteractionEngine.ts2
-rw-r--r--client/src/akkamon/render/BattleControls.ts19
-rw-r--r--client/src/akkamon/render/BattleEngine.ts17
-rw-r--r--client/src/akkamon/scenes/BattleScene.ts173
-rw-r--r--client/src/akkamon/scenes/UIElement.ts13
-rw-r--r--client/src/akkamon/scenes/WorldScene.ts6
-rw-r--r--domain/src/main/java/akkamon/domain/AkkamonMessageEngine.java2
-rw-r--r--domain/src/main/java/akkamon/domain/InteractionHandshaker.java1
-rw-r--r--domain/src/main/java/akkamon/domain/actors/AkkamonBattle.java59
-rw-r--r--domain/src/main/java/akkamon/domain/actors/AkkamonNexus.java43
-rw-r--r--domain/src/main/java/akkamon/domain/actors/SceneTrainerGroup.java17
-rw-r--r--domain/src/main/java/akkamon/domain/actors/Trainer.java29
19 files changed, 435 insertions, 36 deletions
diff --git a/api/src/main/java/akkamon/api/MessagingEngine.java b/api/src/main/java/akkamon/api/MessagingEngine.java
index fb913ca..1c3a2b5 100644
--- a/api/src/main/java/akkamon/api/MessagingEngine.java
+++ b/api/src/main/java/akkamon/api/MessagingEngine.java
@@ -38,6 +38,13 @@ public class MessagingEngine implements AkkamonMessageEngine {
}
private void heartBeat() {
+ for (AkkamonSession session : trainerIDToAkkamonSessions.values()) {
+ session.send(
+ gson.toJson(
+ new HeartBeatEvent(null)
+ )
+ );
+ }
nexus.tell(new AkkamonNexus.RequestHeartBeat(
UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE,
nexus
@@ -170,6 +177,23 @@ public class MessagingEngine implements AkkamonMessageEngine {
System.out.println("Handshake fail not implemented yet!");
}
+ @Override
+ public void broadCastBattleStart(Set<AkkamonNexus.TrainerID> participants) {
+ System.out.println("Sending battle start event!!");
+ for (AkkamonNexus.TrainerID trainerID : participants) {
+ AkkamonSession session = trainerIDToAkkamonSessions.get(trainerID);
+ Set<AkkamonNexus.TrainerID> withoutself = new HashSet<>(participants);
+ withoutself.remove(trainerID);
+ if (session != null) {
+ session.send(
+ gson.toJson(
+ new BattleInitEvent(new ArrayList<>(withoutself))
+ )
+ );
+ }
+ }
+ }
+
void incoming(AkkamonSession session, String message) {
System.out.println(message);
Event event = gson.fromJson(message, Event.class);
diff --git a/api/src/main/java/akkamon/api/models/BattleInitEvent.java b/api/src/main/java/akkamon/api/models/BattleInitEvent.java
new file mode 100644
index 0000000..71402c2
--- /dev/null
+++ b/api/src/main/java/akkamon/api/models/BattleInitEvent.java
@@ -0,0 +1,15 @@
+package akkamon.api.models;
+
+import akkamon.domain.actors.AkkamonNexus;
+
+import java.util.ArrayList;
+
+public class BattleInitEvent extends Event {
+
+ public ArrayList<AkkamonNexus.TrainerID> participants;
+
+ public BattleInitEvent(ArrayList<AkkamonNexus.TrainerID> participants) {
+ this.type = EventType.BATTLE_INIT;
+ this.participants = participants;
+ }
+}
diff --git a/api/src/main/java/akkamon/api/models/EventType.java b/api/src/main/java/akkamon/api/models/EventType.java
index 610318f..497da49 100644
--- a/api/src/main/java/akkamon/api/models/EventType.java
+++ b/api/src/main/java/akkamon/api/models/EventType.java
@@ -30,6 +30,9 @@ public enum EventType {
@SerializedName("InteractionReplyEvent")
INTERACTION_REPLY,
+ @SerializedName("BattleInitEvent")
+ BATTLE_INIT,
+
@SerializedName("InteractionStarting")
INTERACTION_START
diff --git a/client/src/akkamon/GameConfig.ts b/client/src/akkamon/GameConfig.ts
index a0abf11..34915f7 100644
--- a/client/src/akkamon/GameConfig.ts
+++ b/client/src/akkamon/GameConfig.ts
@@ -1,12 +1,13 @@
import DemoScene from './scenes/DemoScene';
import BootScene from './scenes/BootScene';
+import BattleScene from './scenes/BattleScene';
export const gameConfig: Phaser.Types.Core.GameConfig & Phaser.Types.Core.RenderConfig = {
type: Phaser.AUTO,
- backgroundColor: '#125555',
+ backgroundColor: '#FFFFFF',
width: 800,
- height: 800,
+ height: 750,
pixelArt: true,
- scene: [BootScene, DemoScene]
+ scene: [BootScene, DemoScene, BattleScene]
};
diff --git a/client/src/akkamon/PhaserTypes.ts b/client/src/akkamon/PhaserTypes.ts
index 4725a31..77ef4da 100644
--- a/client/src/akkamon/PhaserTypes.ts
+++ b/client/src/akkamon/PhaserTypes.ts
@@ -1,3 +1,3 @@
// type Constructor = new (...args: any[]) => {};
-type GConstructor<T = {}> = new (...args: any[]) => T;
+export type GConstructor<T = {}> = new (...args: any[]) => T;
export type BasePhaserScene = GConstructor<Phaser.Scene>
diff --git a/client/src/akkamon/client/Client.ts b/client/src/akkamon/client/Client.ts
index 4adaec5..c85ed10 100644
--- a/client/src/akkamon/client/Client.ts
+++ b/client/src/akkamon/client/Client.ts
@@ -12,6 +12,8 @@ import { RemotePlayerEngine } from '../render/engine/RemotePlayerEngine';
import { InteractionEngine } from './InteractionEngine';
+import { BattleEngine } from '../render/BattleEngine';
+
import type { AkkamonClient } from './AkkamonClient';
import type { WorldScene } from '../scenes/WorldScene';
@@ -45,6 +47,9 @@ import {
StopMovingEvent
} from './OutgoingEvents';
+import type BattleScene from '../scenes/BattleScene';
+import { BattleControls } from '../render/BattleControls';
+
export class Client implements AkkamonClient
{
@@ -53,12 +58,14 @@ export class Client implements AkkamonClient
private scene?: WorldScene;
private gridPhysics?: GridPhysics;
- private controls?: GridControls | UIControls;
+ private controls?: GridControls | UIControls | BattleControls;
private remotePlayerEngine?: RemotePlayerEngine;
private interactionEngine?: InteractionEngine
+ private BattleEngine?: BattleEngine
+
constructor(
private url: string
) {
@@ -82,7 +89,7 @@ export class Client implements AkkamonClient
// console.log(event);
switch (event.type) {
case EventType.HEART_BEAT:
- if (this.remotePlayerEngine !== undefined) {
+ if (this.remotePlayerEngine !== undefined && event.remoteMovementQueues) {
this.remotePlayerEngine.push(event.remoteMovementQueues!);
}
this.send(new HeartBeatReplyEvent());
@@ -107,6 +114,14 @@ export class Client implements AkkamonClient
this.interactionEngine!.setWaitingDialogue(`Waiting for ${event.interactionType!} to start...`);
}
break;
+ case EventType.BATTLE_INIT:
+ console.log("Received battle init");
+ if (!this.BattleEngine) {
+ this.scene!.switchToBattleScene();
+ } else {
+ console.log("There was already a battle engine!");
+ }
+ break;
default:
console.log("ignored incoming event, doesn't match EventType interface.");
console.log(event.type);
@@ -129,6 +144,12 @@ export class Client implements AkkamonClient
this.interactionEngine!.update();
}
+ updateBattle(delta: number) {
+ console.log("updating battle");
+ this.controls!.update();
+ this.BattleEngine!.update();
+ }
+
setUIControls(input: Phaser.Input.InputPlugin, menu: any) {
console.log("setting ui controls!");
this.controls = new UIControls(input, menu);
@@ -208,7 +229,11 @@ export class Client implements AkkamonClient
return this.gridPhysics!.getPlayerPixelPos();
}
- requestInitBattle() {
+ requestInitBattle(scene: BattleScene) {
+ this.BattleEngine = new BattleEngine(
+ scene
+ );
+
}
requestRemotePlayerData() {
@@ -263,4 +288,9 @@ export class Client implements AkkamonClient
);
}
+
+ setBattleControls(input: Phaser.Input.InputPlugin, menu: any) {
+ console.log("setting battle controls!");
+ this.controls! = new BattleControls(input, menu);
+ }
}
diff --git a/client/src/akkamon/client/EventType.ts b/client/src/akkamon/client/EventType.ts
index de296e0..7685f79 100644
--- a/client/src/akkamon/client/EventType.ts
+++ b/client/src/akkamon/client/EventType.ts
@@ -12,6 +12,7 @@ export enum EventType {
INTERACTION_REQUEST = "InteractionRequestEvent",
INTERACTION_REPLY = "InteractionReplyEvent",
INTERACTION_ABORTED = "InteractionAbortedEvent",
- INTERACTION_START = "InteractionStarting"
+ INTERACTION_START = "InteractionStarting",
+ BATTLE_INIT = "BattleInitEvent"
}
diff --git a/client/src/akkamon/client/InteractionEngine.ts b/client/src/akkamon/client/InteractionEngine.ts
index ee5b4ac..7027a35 100644
--- a/client/src/akkamon/client/InteractionEngine.ts
+++ b/client/src/akkamon/client/InteractionEngine.ts
@@ -84,7 +84,7 @@ export class InteractionEngine extends AkkamonEngine {
}
setWaitingDialogue(text: string) {
- this.scene.clearMenus();
+ this.scene.traverseMenusBackwards();
this.scene.pushMenu(new WaitingDialogue(this.scene, new Phaser.GameObjects.Group(this.scene), 20, text));
}
diff --git a/client/src/akkamon/render/BattleControls.ts b/client/src/akkamon/render/BattleControls.ts
index d6699c8..d61e9d4 100644
--- a/client/src/akkamon/render/BattleControls.ts
+++ b/client/src/akkamon/render/BattleControls.ts
@@ -1,25 +1,34 @@
import { Direction } from './Direction';
import type { BattleEngine } from './BattleEngine';
+import type { AkkamonMenu } from '../scenes/UIElement';
export class BattleControls {
private cursors: Phaser.Types.Input.Keyboard.CursorKeys;
constructor(
private input: Phaser.Input.InputPlugin,
- private battleEngine: BattleEngine,
+ private menu: AkkamonMenu,
) {
this.cursors = this.input.keyboard.createCursorKeys();
}
update() {
+ console.log("updating battle controls");
if (Phaser.Input.Keyboard.JustDown(this.cursors.left)) {
- // this.battleEngine.
+ console.log("left");
+ this.menu.selectButton(Direction.LEFT);
} else if (Phaser.Input.Keyboard.JustDown(this.cursors.right)) {
- // this.battleEngine.
+ console.log("right");
+ this.menu.selectButton(Direction.RIGHT);
} else if (Phaser.Input.Keyboard.JustDown(this.cursors.up)) {
- // this.battleEngine.
+ console.log("up");
+ this.menu.selectButton(Direction.UP);
} else if (Phaser.Input.Keyboard.JustDown(this.cursors.down)) {
- // this.battleEngine.
+ console.log("down");
+ this.menu.selectButton(Direction.DOWN);
+ } else if (Phaser.Input.Keyboard.JustDown(this.cursors.space)) {
+ console.log("confirm");
+ this.menu.confirm();
}
}
}
diff --git a/client/src/akkamon/render/BattleEngine.ts b/client/src/akkamon/render/BattleEngine.ts
index 7127e2d..87ff355 100644
--- a/client/src/akkamon/render/BattleEngine.ts
+++ b/client/src/akkamon/render/BattleEngine.ts
@@ -1,2 +1,17 @@
-export class BattleEngine {
+import type BattleScene from '../scenes/BattleScene';
+import type { WorldScene } from '../scenes/WorldScene';
+import {
+ AkkamonEngine
+} from './engine/AkkamonEngine';
+
+export class BattleEngine extends AkkamonEngine {
+
+ constructor(
+ public scene: BattleScene
+ ) {
+ super();
+ }
+
+ update() {
+ }
}
diff --git a/client/src/akkamon/scenes/BattleScene.ts b/client/src/akkamon/scenes/BattleScene.ts
index 320712f..b77150e 100644
--- a/client/src/akkamon/scenes/BattleScene.ts
+++ b/client/src/akkamon/scenes/BattleScene.ts
@@ -1,18 +1,183 @@
import { client } from '../../app';
+import { baseStack, Queue, queueFromArray } from '../DataWrappers';
+import type { BasePhaserScene, GConstructor } from '../PhaserTypes';
+import type { Direction } from '../render/Direction';
+import { AkkamonMenu, Dialogue, Menu, MenuText, Picker } from './UIElement';
+import type { WorldScene } from './WorldScene';
-export class BattleScene extends Phaser.Scene {
- client = client;
+export default class BattleScene extends Phaser.Scene {
+ menus = baseStack<AkkamonMenu>();
+ dialogue?: BattleDialogue;
constructor() {
super('BattleScene')
}
create() {
- this.client.requestInitBattle(this);
+ console.log("Creating Battle Scene");
+ let initialDialogue = new BattleDialogue(
+ this,
+ new Phaser.GameObjects.Group(this),
+ 10);
+ this.pushMenu(initialDialogue);
+
+ initialDialogue!.setDialogueQueue(queueFromArray([
+ "hello",
+ "Bye"
+ ]));
+
+ client.requestInitBattle(this);
+ }
+
+ update(time: number, delta: number) {
+ client.updateBattle(delta);
+ }
+
+ pushMenu(menu: AkkamonMenu) {
+ this.menus.push(menu);
+ this.menuTakesUIControl(this.input, menu);
+ console.log("New menu stack:");
+ console.log(this.menus);
+ }
+
+ popMenu() {
+ return this.menus.pop();
+ }
+
+ peekMenu() {
+ return this.menus.peek();
+ }
+
+
+ traverseMenusBackwards() {
+ this.popMenu();
+ if (this.menus.size() > 1) {
+ this.menuTakesUIControl(this.input, this.menus.peek()!);
+ this.menus.peek()!.setMenuVisible(true);
+ }
+ console.log("menu stack after traversing back:");
+ console.log(this.menus);
+ }
+
+ menuTakesUIControl(input: Phaser.Input.InputPlugin, menu: AkkamonMenu): void {
+ client.setBattleControls(input, menu);
+ }
+}
+
+class BattleDialogue extends Dialogue {
+ battleScene: BattleScene
+
+ constructor(scene: BattleScene, group: Phaser.GameObjects.Group, depth: number) {
+ super(scene, group, depth)
+ this.battleScene = scene;
+ }
+
+ setDialogueQueue(queue: Queue<string>) {
+ this.messageQueue! = queue;
+ this.displayNextDialogue();
+ }
+
+ confirm() {
+ if (this.messageQueue.isEmpty()) {
+ this.battleScene.pushMenu(new BattleOptions(
+ this.battleScene
+ ));
+ }
+ this.displayNextDialogue();
+ }
+
+}
+
+enum BattleOptionsPos {
+ TOP_RIGHT = "PKMN",
+ TOP_LEFT = "FIGHT",
+ BOT_RIGHT = "ITEM",
+ BOT_LEFT = "RUN"
+}
+
+class BattleOptions extends Phaser.GameObjects.Image implements AkkamonMenu {
+ battleScene: BattleScene;
+ group: Phaser.GameObjects.Group;
+ camera: Phaser.Cameras.Scene2D.Camera;
+ buttons: Map<string, MenuText>;
+ groupDepth?: number;
+
+ constructor(scene: BattleScene) {
+ let camera = scene.cameras.main;
+ super(scene, camera.scrollX + camera.width, camera.scrollY + camera.height, "options-dialogue")
+ this.setOrigin(1,1)
+ this.setVisible(true)
+ this.setDisplaySize(0.56 * camera.width, 0.28 * camera.width);
+
+
+
+ this.battleScene = scene;
+ this.group = new Phaser.GameObjects.Group(scene);
+ this.camera = camera;
+
+
+ this.group = new Phaser.GameObjects.Group(scene);
+
+ scene.add.existing(this);
+ this.group.add(this);
+
+ this.buttons = new Map();
+ this.groupDepth = 20;
+ this.setDepth(this.groupDepth);
+
+ this.setButtons();
+ this.setPicker(BattleOptionsPos.TOP_LEFT);
+
+ }
+
+ setButtons() {
+ for (let pos in BattleOptionsPos) {
+ let x;
+ let y;
+
+ switch (pos) {
+ case BattleOptionsPos.TOP_LEFT:
+ break;
+ case BattleOptionsPos.TOP_RIGHT:
+ break;
+ case BattleOptionsPos.BOT_LEFT:
+ break;
+ case BattleOptionsPos.BOT_RIGHT:
+ break;
+
+ }
+
+ this.buttons.set(
+ pos,
+ new MenuText(
+ this.battleScene,
+ this.group,
+ this.groupDepth!,
+ this.x,
+ this.y,
+ pos
+ )
+ )
+ }
+ }
+
+ selectButton() {
+ }
+
+ destroyAndGoBack() {
+ }
+
+ confirm() {
+ }
+
+ destroyGroup() {
+ }
+
+ setMenuVisible() {
}
- update() {
+ setPicker(position: BattleOptionsPos) {
}
}
diff --git a/client/src/akkamon/scenes/UIElement.ts b/client/src/akkamon/scenes/UIElement.ts
index 1c87ef4..5476eda 100644
--- a/client/src/akkamon/scenes/UIElement.ts
+++ b/client/src/akkamon/scenes/UIElement.ts
@@ -7,9 +7,10 @@ import {
baseQueue,
Queue
} from '../DataWrappers';
+import type BattleScene from './BattleScene';
-class MenuText extends Phaser.GameObjects.Text {
+export class MenuText extends Phaser.GameObjects.Text {
public static TEXT_HEIGHT: number = 16;
constructor(scene: Phaser.Scene, group: Phaser.GameObjects.Group, groupDepth: number, x: number, y: number, text: string) {
@@ -56,7 +57,7 @@ class WrappedMenuText extends MenuText {
}
}
-class Picker extends Phaser.GameObjects.Image {
+export class Picker extends Phaser.GameObjects.Image {
constructor(scene: Phaser.Scene, group: Phaser.GameObjects.Group, x: number, y: number, name: string) {
super(scene, x, y, name);
@@ -76,7 +77,7 @@ export interface AkkamonMenu {
}
-class Menu extends Phaser.GameObjects.Image implements AkkamonMenu {
+export class Menu extends Phaser.GameObjects.Image implements AkkamonMenu {
akkamonScene: WorldScene
@@ -359,13 +360,13 @@ class ConfirmationDialogue extends Menu implements AkkamonMenu {
}
-class Dialogue extends Phaser.GameObjects.Image implements AkkamonMenu {
+export class Dialogue extends Phaser.GameObjects.Image implements AkkamonMenu {
public messageQueue: Queue<string>;
public displayedText: MenuText;
- public akkamonScene: WorldScene;
+ public akkamonScene: WorldScene | BattleScene;
public group: Phaser.GameObjects.Group;
- constructor(scene: WorldScene, group: Phaser.GameObjects.Group, depth: number) {
+ constructor(scene: WorldScene | BattleScene, group: Phaser.GameObjects.Group, depth: number) {
let camera = scene.cameras.main;
super(scene, camera.scrollX, camera.scrollY, "general-dialogue-box")
this.setOrigin(0,1);
diff --git a/client/src/akkamon/scenes/WorldScene.ts b/client/src/akkamon/scenes/WorldScene.ts
index f570cde..df44256 100644
--- a/client/src/akkamon/scenes/WorldScene.ts
+++ b/client/src/akkamon/scenes/WorldScene.ts
@@ -47,6 +47,8 @@ export interface WorldScene extends Phaser.Scene {
clearMenus: () => void
requestConfirmInteractionReply: (v: boolean, requestName: string) => void
+
+ switchToBattleScene: () => void
}
@@ -172,5 +174,9 @@ export function createWorldScene<PhaserScene extends BasePhaserScene>(scene: Pha
client.sendInteractionReply(value, requestName);
}
+ switchToBattleScene() {
+ console.log(this.scene);
+ this.scene.start('BattleScene');
+ }
}
}
diff --git a/domain/src/main/java/akkamon/domain/AkkamonMessageEngine.java b/domain/src/main/java/akkamon/domain/AkkamonMessageEngine.java
index 0172770..919d21f 100644
--- a/domain/src/main/java/akkamon/domain/AkkamonMessageEngine.java
+++ b/domain/src/main/java/akkamon/domain/AkkamonMessageEngine.java
@@ -24,4 +24,6 @@ public interface AkkamonMessageEngine {
void broadCastInteractionStart(String requestName, String interactionType, Set<AkkamonNexus.TrainerID> waitingToStartInteraction);
void broadCastHandshakeFail(String requestName, Set<AkkamonNexus.TrainerID> waitingToStartInteraction);
+
+ void broadCastBattleStart(Set<AkkamonNexus.TrainerID> participants);
}
diff --git a/domain/src/main/java/akkamon/domain/InteractionHandshaker.java b/domain/src/main/java/akkamon/domain/InteractionHandshaker.java
index 9817be1..186c310 100644
--- a/domain/src/main/java/akkamon/domain/InteractionHandshaker.java
+++ b/domain/src/main/java/akkamon/domain/InteractionHandshaker.java
@@ -131,6 +131,7 @@ public class InteractionHandshaker extends AbstractBehavior<InteractionHandshake
private Behavior<Command> respondIfAllRepliesReceived() {
getContext().getLog().info(String.valueOf(stillWaiting));
+
if (this.stillWaiting.isEmpty()) {
getContext().getLog().info("Sending out interaction Start!");
replyTo.tell(new RespondInteractionHandshaker(
diff --git a/domain/src/main/java/akkamon/domain/actors/AkkamonBattle.java b/domain/src/main/java/akkamon/domain/actors/AkkamonBattle.java
index 6f65845..21c4239 100644
--- a/domain/src/main/java/akkamon/domain/actors/AkkamonBattle.java
+++ b/domain/src/main/java/akkamon/domain/actors/AkkamonBattle.java
@@ -7,30 +7,83 @@ import akka.actor.typed.javadsl.AbstractBehavior;
import akka.actor.typed.javadsl.Behaviors;
import akka.actor.typed.javadsl.Receive;
+import java.util.HashSet;
+import java.util.Set;
+
public class AkkamonBattle extends AbstractBehavior<AkkamonBattle.Command> {
public interface Command { }
public static class BattleCreatedResponse implements AkkamonNexus.Command {
+ public Set<AkkamonNexus.TrainerID> participants;
+
+ public BattleCreatedResponse(Set<AkkamonNexus.TrainerID> participants) {
+ this.participants = participants;
+ }
}
public static Behavior<Command> create(
+ Set<AkkamonNexus.TrainerID> participants,
ActorRef<AkkamonNexus.Command> replyTo
) {
return Behaviors.setup(
- context -> new AkkamonBattle(context)
+ context -> new AkkamonBattle(context, participants, replyTo)
);
}
- public AkkamonBattle(ActorContext<Command> context) {
+ private Set<AkkamonNexus.TrainerID> participants;
+
+ private Set<AkkamonNexus.TrainerID> needLink;
+
+ private ActorRef<AkkamonNexus.Command> replyTo;
+
+ public AkkamonBattle(
+ ActorContext<Command> context,
+ Set<AkkamonNexus.TrainerID> participants,
+ ActorRef<AkkamonNexus.Command> replyTo
+ ) {
super(context);
+
+ this.participants = participants;
+
+ this.needLink = new HashSet(participants);
+
+ this.replyTo = replyTo;
}
@Override
public Receive<Command> createReceive() {
- return null;
+ return initial();
+ }
+
+ private Receive<Command> initial() {
+ return newReceiveBuilder()
+ .onMessage(AkkamonNexus.BattleStart.class, this::onBattleStart)
+ .build();
+ }
+
+ private Behavior<Command> onBattleStart(AkkamonNexus.BattleStart start) {
+ AkkamonNexus.TrainerID linkingTrainer = start.trainerID;
+ getContext().getLog().info(String.valueOf(needLink));
+ needLink.remove(linkingTrainer);
+ getContext().getLog().info(String.valueOf(needLink));
+ if (needLink.isEmpty()) {
+ getContext().getLog().info("Sending Battle Created Response!");
+ replyTo.tell(
+ new BattleCreatedResponse(participants)
+ );
+ return inProgress();
+ } else {
+ getContext().getLog().info("Need to link trainers {}", needLink);
+ return this;
+ }
+ }
+
+ private Behavior<Command> inProgress() {
+ return Behaviors.receive(Command.class)
+ .build();
}
}
diff --git a/domain/src/main/java/akkamon/domain/actors/AkkamonNexus.java b/domain/src/main/java/akkamon/domain/actors/AkkamonNexus.java
index e560a69..17625b7 100644
--- a/domain/src/main/java/akkamon/domain/actors/AkkamonNexus.java
+++ b/domain/src/main/java/akkamon/domain/actors/AkkamonNexus.java
@@ -17,8 +17,8 @@ public class AkkamonNexus extends AbstractBehavior<AkkamonNexus.Command> {
public interface Command {}
public static class TrainerID {
- public String id;
- public String scene;
+ public final String id;
+ public final String scene;
public TrainerID(String id, String scene) {
this.id = id;
@@ -47,8 +47,18 @@ public class AkkamonNexus extends AbstractBehavior<AkkamonNexus.Command> {
}
}
- public static class BattleStart implements SceneTrainerGroup.Command, Trainer.Command {
+ public static class BattleStart
+ implements Command, SceneTrainerGroup.Command, Trainer.Command, AkkamonBattle.Command {
+ public TrainerID trainerID;
+ public ActorRef<AkkamonBattle.Command> ref;
+ public ActorRef<AkkamonNexus.Command> replyTo;
+
+ public BattleStart(TrainerID trainerID, ActorRef<AkkamonBattle.Command> battle, ActorRef<AkkamonNexus.Command> replyTo) {
+ this.trainerID = trainerID;
+ this.ref = battle;
+ this.replyTo = replyTo;
+ }
}
public static class RespondInteractionHandshaker implements Command {
@@ -284,6 +294,7 @@ public class AkkamonNexus extends AbstractBehavior<AkkamonNexus.Command> {
.onMessage(RequestNewTilePos.class, this::onNewTilePos)
.onMessage(RequestInteraction.class, this::onInteractionRequest)
+
.onMessage(RespondInteractionHandshaker.class, this::onInteractionHandshakerResponse)
.onMessage(AkkamonBattle.BattleCreatedResponse.class, this::onBattleCreatedResponse)
@@ -292,21 +303,43 @@ public class AkkamonNexus extends AbstractBehavior<AkkamonNexus.Command> {
private AkkamonNexus onBattleCreatedResponse(AkkamonBattle.BattleCreatedResponse r) {
getContext().getLog().info("Created battle between {} and {}, they should now only be listening to battle commands!");
+ messageEngine.broadCastBattleStart(r.participants);
return this;
}
private Behavior<Command> onInteractionHandshakerResponse(RespondInteractionHandshaker r) {
+ getContext().getLog().info("received interaction response");
this.messageEngine.removeInteractionHandshaker(r.requestName);
+
+ StringBuilder battlename = new StringBuilder();
+ battlename.append("battle");
+ for (TrainerID trainerID : r.waitingToStartInteraction) {
+ battlename.append("-" + trainerID.id);
+ }
+
if (r.result.equals(InteractionHandshaker.HandshakeResult.SUCCESS)) {
messageEngine.broadCastInteractionStart(r.requestName, r.interactionType, r.waitingToStartInteraction);
switch (r.interactionType) {
case "battle":
- getContext().spawn(AkkamonBattle.create(
+ ActorRef<AkkamonBattle.Command> battle = getContext().spawn(AkkamonBattle.create(
+ r.waitingToStartInteraction,
getContext().getSelf()
),
- r.requestName);
+ battlename.toString());
+ for (TrainerID trainerID : r.waitingToStartInteraction) {
+ ActorRef<SceneTrainerGroup.Command> scene = sceneIdToActor.get(trainerID.scene);
+ if (scene != null) {
+ scene.tell(new BattleStart(
+ trainerID,
+ battle,
+ getContext().getSelf()
+ ));
+ } else {
+ getContext().getLog().info("Ignoring battle in scene {}, it isn't mapped to a sceneTrainerActor.", trainerID.scene);
+ }
+ }
break;
}
diff --git a/domain/src/main/java/akkamon/domain/actors/SceneTrainerGroup.java b/domain/src/main/java/akkamon/domain/actors/SceneTrainerGroup.java
index 31f53b5..933e2b1 100644
--- a/domain/src/main/java/akkamon/domain/actors/SceneTrainerGroup.java
+++ b/domain/src/main/java/akkamon/domain/actors/SceneTrainerGroup.java
@@ -77,9 +77,26 @@ public class SceneTrainerGroup extends AbstractBehavior<SceneTrainerGroup.Comman
AkkamonNexus.RequestHeartBeat.class,
this::onHeartBeat
)
+ .onMessage(AkkamonNexus.BattleStart.class,
+ this::onBattleStarting)
.build();
}
+ private SceneTrainerGroup onBattleStarting(AkkamonNexus.BattleStart battle) {
+ ActorRef<Trainer.Command> trainer = this.trainerIDToActor.get(battle.trainerID);
+ if (trainer != null) {
+ trainer.tell(battle);
+ } else {
+ getContext()
+ .getLog()
+ .warn(
+ "Ignoring battle for trainerID {}. There is no actor mapped to it.",
+ battle.trainerID
+ );
+ }
+ return this;
+ }
+
private SceneTrainerGroup onWatchedTrainerOffline(TrainerOffline trainerOfflineMsg) {
trainerOfflineMsg.replyTo.tell(trainerOfflineMsg);
trainerIDToActor.remove(trainerOfflineMsg.trainerID);
diff --git a/domain/src/main/java/akkamon/domain/actors/Trainer.java b/domain/src/main/java/akkamon/domain/actors/Trainer.java
index 4d4d9c5..2ebe2ed 100644
--- a/domain/src/main/java/akkamon/domain/actors/Trainer.java
+++ b/domain/src/main/java/akkamon/domain/actors/Trainer.java
@@ -30,9 +30,9 @@ public class Trainer extends AbstractBehavior<Trainer.Command> {
}
public static final class RespondMovementQueue {
- final long requestId;
- final TrainerID trainerID;
- final Queue<Direction> value;
+ final public long requestId;
+ final public TrainerID trainerID;
+ final public Queue<Direction> value;
public RespondMovementQueue(
long requestId,
@@ -57,6 +57,8 @@ public class Trainer extends AbstractBehavior<Trainer.Command> {
private Optional<TilePos> lastValidTilePos = Optional.empty();
+ private ActorRef<AkkamonBattle.Command> battleRef;
+
public Trainer(ActorContext<Command> context, TrainerID trainerID) {
super(context);
this.trainerID = trainerID;
@@ -64,6 +66,10 @@ public class Trainer extends AbstractBehavior<Trainer.Command> {
@Override
public Receive<Command> createReceive() {
+ return moving();
+ }
+
+ private Receive<Command> moving() {
return newReceiveBuilder()
.onMessage(
ReadMovementQueue.class,
@@ -84,9 +90,26 @@ public class Trainer extends AbstractBehavior<Trainer.Command> {
RequestNewTilePos.class,
this::onNewTilePos
)
+ .onMessage(AkkamonNexus.BattleStart.class, this::onBattleStart)
+ .build();
+ }
+
+ private Behavior<Command> battling() {
+ return Behaviors.receive(Command.class)
+ .onMessage(ReadMovementQueue.class, this::onReadMovementQueue)
.build();
}
+ private Behavior<Command> onBattleStart(AkkamonNexus.BattleStart battle) {
+ getContext().getLog().info("Trainer {} now has a battle ref and has battle behavior", trainerID);
+ this.battleRef = battle.ref;
+ battle.ref.tell(
+ battle
+ );
+ return battling();
+ }
+
+
private Behavior<Command> onTrainerOffline(RequestTrainerOffline trainerOfflineRequest) {
getContext().getLog().info("Trainer {} went offline, the actor has stopped! My supervisor should handle closing my connection!");
return Behaviors.stopped();