diff options
| author | Mike Vink <mike1994vink@gmail.com> | 2021-07-30 13:41:55 +0200 |
|---|---|---|
| committer | Mike Vink <mike1994vink@gmail.com> | 2021-07-30 13:41:55 +0200 |
| commit | 04b66877f2608d0ee6586e3197569a6289087d58 (patch) | |
| tree | 24455b84a334e6ba39a293c2ee2c4128b6eaa085 | |
| parent | c0004768de6695e2acfa48c392765b03b81ba9d0 (diff) | |
feat(): Working on battle UI
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(); |
