From fec7680eeec268b9f142bdaf8ff8c07510178fe2 Mon Sep 17 00:00:00 2001 From: shmyga Date: Thu, 28 May 2020 20:42:41 +0300 Subject: [PATCH] [common] use proto types --- src/app/haxe/ru/m/data/DataStorage.hx | 11 ++ src/app/haxe/ru/m/puzzlez/net/Network.hx | 30 ++-- src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx | 8 +- .../haxe/ru/m/puzzlez/render/CompleteView.hx | 13 +- src/app/haxe/ru/m/puzzlez/render/IRender.hx | 3 +- .../ru/m/puzzlez/render/ImagePartBuilder.hx | 4 +- src/app/haxe/ru/m/puzzlez/render/PartView.hx | 18 +-- src/app/haxe/ru/m/puzzlez/render/Render.hx | 88 +++++++----- .../haxe/ru/m/puzzlez/render/RenderUtil.hx | 35 +++-- .../m/puzzlez/render/part/BasePartBuilder.hx | 8 +- .../puzzlez/render/part/ClassicPartBuilder.hx | 20 +-- .../ru/m/puzzlez/render/part/IPartBuilder.hx | 6 +- .../puzzlez/render/part/SquarePartBuilder.hx | 14 +- .../haxe/ru/m/puzzlez/storage/GameStorage.hx | 19 ++- src/app/haxe/ru/m/puzzlez/view/GameFrame.hx | 13 +- src/app/haxe/ru/m/puzzlez/view/StartFrame.hx | 8 +- .../haxe/ru/m/puzzlez/view/StartFrame.yaml | 4 +- .../ru/m/puzzlez/view/common/PresetView.hx | 13 +- .../ru/m/puzzlez/view/popup/PreviewPopup.hx | 2 +- .../haxe/ru/m/puzzlez/core/BoundType.hx | 7 - .../haxe/ru/m/puzzlez/core/EventUtil.hx | 36 +++++ src/common/haxe/ru/m/puzzlez/core/Game.hx | 101 +++++++------ .../haxe/ru/m/puzzlez/core/GameEvent.hx | 21 --- .../haxe/ru/m/puzzlez/core/GamePreset.hx | 11 -- .../haxe/ru/m/puzzlez/core/GameState.hx | 15 -- src/common/haxe/ru/m/puzzlez/core/GameUtil.hx | 134 +++++++++--------- src/common/haxe/ru/m/puzzlez/core/Grid.hx | 6 - src/common/haxe/ru/m/puzzlez/core/IGame.hx | 4 +- src/common/haxe/ru/m/puzzlez/core/Part.hx | 24 ---- .../haxe/ru/m/puzzlez/core/PartLocation.hx | 10 -- src/common/haxe/ru/m/puzzlez/wrap/PointExt.hx | 41 ++++++ .../haxe/ru/m/puzzlez/wrap/RectangleExt.hx | 50 +++++++ src/common/proto/core.proto | 16 ++- src/common/proto/event.proto | 25 ++-- src/common/proto/game.proto | 61 ++++++-- src/common/proto/pack.proto | 12 +- 36 files changed, 514 insertions(+), 377 deletions(-) delete mode 100644 src/common/haxe/ru/m/puzzlez/core/BoundType.hx create mode 100644 src/common/haxe/ru/m/puzzlez/core/EventUtil.hx delete mode 100644 src/common/haxe/ru/m/puzzlez/core/GameEvent.hx delete mode 100644 src/common/haxe/ru/m/puzzlez/core/GamePreset.hx delete mode 100644 src/common/haxe/ru/m/puzzlez/core/GameState.hx delete mode 100644 src/common/haxe/ru/m/puzzlez/core/Grid.hx delete mode 100644 src/common/haxe/ru/m/puzzlez/core/Part.hx delete mode 100644 src/common/haxe/ru/m/puzzlez/core/PartLocation.hx create mode 100644 src/common/haxe/ru/m/puzzlez/wrap/PointExt.hx create mode 100644 src/common/haxe/ru/m/puzzlez/wrap/RectangleExt.hx diff --git a/src/app/haxe/ru/m/data/DataStorage.hx b/src/app/haxe/ru/m/data/DataStorage.hx index 9978d3b..3d875f7 100644 --- a/src/app/haxe/ru/m/data/DataStorage.hx +++ b/src/app/haxe/ru/m/data/DataStorage.hx @@ -2,8 +2,10 @@ package ru.m.data; import flash.net.SharedObject; import haxe.DynamicAccess; +import haxe.io.Bytes; import haxe.Serializer; import haxe.Unserializer; +import hw.connect.PacketUtil; import promhx.Promise; import ru.m.data.IDataSource; @@ -34,6 +36,15 @@ class DefaultConverter extends Converter { } } +class ProtoConverter extends Converter { + public function new(messageClass:Class) { + super( + item -> PacketUtil.toBytes(item).toHex(), + data -> PacketUtil.fromBytes(Bytes.ofHex(data), messageClass) + ); + } +} + class EmptyConverter extends Converter { public function new() { super(item -> item, data -> data); diff --git a/src/app/haxe/ru/m/puzzlez/net/Network.hx b/src/app/haxe/ru/m/puzzlez/net/Network.hx index 08a3344..b7e8692 100644 --- a/src/app/haxe/ru/m/puzzlez/net/Network.hx +++ b/src/app/haxe/ru/m/puzzlez/net/Network.hx @@ -1,17 +1,18 @@ package ru.m.puzzlez.net; -import haxe.Unserializer; import hw.connect.ConnectionFactory; import hw.connect.IConnection; import hw.signal.Signal; import hw.storage.SharedObjectStorage; import promhx.Promise; import ru.m.data.IDataSource; -import ru.m.puzzlez.core.GameEvent; -import ru.m.puzzlez.core.GameState; import ru.m.puzzlez.core.Id; -import ru.m.puzzlez.proto.game.GameProto; -import ru.m.puzzlez.proto.core.UserProto; +import ru.m.puzzlez.proto.core.User; +import ru.m.puzzlez.proto.event.GameAction; +import ru.m.puzzlez.proto.event.GameEvent; +import ru.m.puzzlez.proto.game.GameItem; +import ru.m.puzzlez.proto.game.GameState; +import ru.m.puzzlez.proto.pack.GameActionRequest; import ru.m.puzzlez.proto.pack.GameCreateRequest; import ru.m.puzzlez.proto.pack.GameJoinRequest; import ru.m.puzzlez.proto.pack.LoginRequest; @@ -19,14 +20,14 @@ import ru.m.puzzlez.proto.pack.Request; import ru.m.puzzlez.proto.pack.Response; @:provide class Network implements IDataIndex { - public var user(default, null):UserProto; - public var userSignal(default, null):Signal = new Signal(); + public var user(default, null):User; + public var userSignal(default, null):Signal = new Signal(); - public var gameList(default, null):Array; - public var gameListSignal(default, null):Signal> = new Signal(); + public var gameList(default, null):Array; + public var gameListSignal(default, null):Signal> = new Signal(); - public var game(default, null):GameProto; - public var gameSignal(default, null):Signal = new Signal(); + public var game(default, null):GameItem; + public var gameSignal(default, null):Signal = new Signal(); public var gameEventSignal(default, null):Signal = new Signal(); @@ -37,11 +38,11 @@ import ru.m.puzzlez.proto.pack.Response; public function new() { gameList = []; - storage = new SharedObjectStorage("network"); + storage = new SharedObjectStorage("network/2"); if (storage.exists(USER_KEY)) { user = storage.read(USER_KEY); } else { - user = new UserProto().setName('Anonimus #${IdUtil.generate()}'); + user = new User().setName('Anonimus #${IdUtil.generate()}'); storage.write(USER_KEY, user); } connection = ConnectionFactory.buildClientConnection("127.0.0.1", 5000, Response); @@ -63,8 +64,7 @@ import ru.m.puzzlez.proto.pack.Response; } public function sendGameAction(action:GameAction):Void { - // ToDo: send action - //connection.send(new Request().setGameEvent()); + connection.send(new Request().setGameAction(new GameActionRequest().setActions([action]))); } private function onConnectionChange(event:ConnectionEvent):Void { diff --git a/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx b/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx index 72850cc..e46ce5b 100644 --- a/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx +++ b/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx @@ -1,9 +1,11 @@ package ru.m.puzzlez.net; import hw.signal.Signal; -import ru.m.puzzlez.core.GameState; -import ru.m.puzzlez.core.GameEvent; import ru.m.puzzlez.core.IGame; +import ru.m.puzzlez.proto.event.GameAction; +import ru.m.puzzlez.proto.event.GameEvent; +import ru.m.puzzlez.proto.game.GameState; +import ru.m.puzzlez.proto.game.GameStatus; class NetworkGame implements IGame { public var state(default, null):GameState; @@ -23,7 +25,7 @@ class NetworkGame implements IGame { public function start():Void { network.gameEventSignal.connect(onEvent); switch state.status { - case READY: + case GameStatus.READY: network.startGame(state); case _: network.joinGame(state); diff --git a/src/app/haxe/ru/m/puzzlez/render/CompleteView.hx b/src/app/haxe/ru/m/puzzlez/render/CompleteView.hx index 43445fe..27d4726 100644 --- a/src/app/haxe/ru/m/puzzlez/render/CompleteView.hx +++ b/src/app/haxe/ru/m/puzzlez/render/CompleteView.hx @@ -1,8 +1,9 @@ package ru.m.puzzlez.render; +import ru.m.puzzlez.wrap.RectangleExt; +import ru.m.puzzlez.proto.game.GamePreset; import flash.display.Shape; import flash.geom.Matrix; -import ru.m.puzzlez.core.GamePreset; import ru.m.puzzlez.render.part.IPartBuilder; class CompleteView extends Shape { @@ -29,8 +30,8 @@ class CompleteView extends Shape { return; } - var partWidth = preset.imageRect.width / preset.grid.width; - var partHeight = preset.imageRect.height / preset.grid.height; + var partWidth = preset.imageRect.width / preset.grid.x; + var partHeight = preset.imageRect.height / preset.grid.y; graphics.clear(); graphics.lineStyle(2, 0xCCCCCC); @@ -51,9 +52,9 @@ class CompleteView extends Shape { graphics.endFill(); } - var rect = part.rect.clone(); - rect.x = part.gridX * part.rect.width; - rect.y = part.gridY * part.rect.height; + var rect = cast(part.rect, RectangleExt).clone(); + rect.x = part.point.x * part.rect.width; + rect.y = part.point.y * part.rect.height; var path = builder.build(rect, part.bounds); for (value in RenderUtil.borderSettings) { graphics.lineStyle(1, value.color, value.opacity); diff --git a/src/app/haxe/ru/m/puzzlez/render/IRender.hx b/src/app/haxe/ru/m/puzzlez/render/IRender.hx index cff1f90..c296d94 100644 --- a/src/app/haxe/ru/m/puzzlez/render/IRender.hx +++ b/src/app/haxe/ru/m/puzzlez/render/IRender.hx @@ -2,7 +2,8 @@ package ru.m.puzzlez.render; import hw.signal.Signal; import hw.view.IView; -import ru.m.puzzlez.core.GameEvent; +import ru.m.puzzlez.proto.event.GameAction; +import ru.m.puzzlez.proto.event.GameEvent; interface IRender extends IView { public var actions(default, null):Signal; diff --git a/src/app/haxe/ru/m/puzzlez/render/ImagePartBuilder.hx b/src/app/haxe/ru/m/puzzlez/render/ImagePartBuilder.hx index eb7b4d6..fab5906 100644 --- a/src/app/haxe/ru/m/puzzlez/render/ImagePartBuilder.hx +++ b/src/app/haxe/ru/m/puzzlez/render/ImagePartBuilder.hx @@ -1,11 +1,11 @@ package ru.m.puzzlez.render; -import ru.m.puzzlez.render.RenderUtil; import flash.display.BitmapData; import haxe.Timer; import promhx.PublicStream; import promhx.Stream; -import ru.m.puzzlez.core.Part; +import ru.m.puzzlez.proto.game.Part; +import ru.m.puzzlez.render.RenderUtil; typedef Result = { var part:Part; diff --git a/src/app/haxe/ru/m/puzzlez/render/PartView.hx b/src/app/haxe/ru/m/puzzlez/render/PartView.hx index 3751998..8a0af2e 100644 --- a/src/app/haxe/ru/m/puzzlez/render/PartView.hx +++ b/src/app/haxe/ru/m/puzzlez/render/PartView.hx @@ -1,14 +1,16 @@ package ru.m.puzzlez.render; -import flash.display.BitmapData; import flash.display.Bitmap; +import flash.display.BitmapData; import flash.display.PixelSnapping; import flash.display.Sprite; -import hw.geom.Point; -import ru.m.puzzlez.core.Part; import ru.m.puzzlez.core.Id; -import ru.m.puzzlez.render.RenderUtil; +import ru.m.puzzlez.proto.core.Point; +import ru.m.puzzlez.proto.game.Part; import ru.m.puzzlez.render.part.IPartBuilder; +import ru.m.puzzlez.render.RenderUtil; +import ru.m.puzzlez.wrap.PointExt; +import ru.m.puzzlez.wrap.RectangleExt; class PartView extends Sprite { @@ -19,7 +21,7 @@ class PartView extends Sprite { public var target(default, null):Point; private function set_position(value:Point):Point { - position = value.clone(); + position = cast(value, PointExt).clone(); refresh(); return position; } @@ -58,8 +60,8 @@ class PartView extends Sprite { super(); this.id = part.id; this.part = part; - this.size = part.rect.size.clone(); - this.target = new Point(part.gridX * size.x, part.gridY * size.y); + this.size = cast(part.rect, RectangleExt).size; + this.target = new Point().setX(part.point.x * size.x).setY(part.point.y * size.y); } private function redraw():Void { @@ -101,7 +103,7 @@ class SpritePartView extends PartView { graphics.endFill(); if (playerId != null) { - var rect = part.rect.clone(); + var rect = cast(part.rect, RectangleExt).clone(); rect.x += (image.width - size.x) / 2; rect.y += (image.height - size.y) / 2; var path = builder.build(rect, part.bounds); diff --git a/src/app/haxe/ru/m/puzzlez/render/Render.hx b/src/app/haxe/ru/m/puzzlez/render/Render.hx index 9b7aaf7..15e4101 100644 --- a/src/app/haxe/ru/m/puzzlez/render/Render.hx +++ b/src/app/haxe/ru/m/puzzlez/render/Render.hx @@ -1,7 +1,5 @@ package ru.m.puzzlez.render; -import ru.m.puzzlez.core.Id; -import ru.m.puzzlez.net.Network; import flash.display.BitmapData; import flash.display.PNGEncoderOptions; import flash.display.Sprite; @@ -10,16 +8,20 @@ import flash.geom.Point as FlashPoint; import flash.geom.Rectangle; import flash.net.FileReference; import flash.utils.ByteArray; -import hw.geom.Point; import hw.signal.Signal; import hw.view.popup.AlertView; import hw.view.SpriteView; -import ru.m.puzzlez.core.GameEvent; -import ru.m.puzzlez.core.GameState; -import ru.m.puzzlez.core.PartLocation; +import ru.m.puzzlez.core.Id; +import ru.m.puzzlez.net.Network; +import ru.m.puzzlez.proto.event.gameaction.Action; +import ru.m.puzzlez.proto.event.GameAction; +import ru.m.puzzlez.proto.event.GameEvent; +import ru.m.puzzlez.proto.game.GameState; +import ru.m.puzzlez.proto.game.PartLocation; import ru.m.puzzlez.render.ImagePartBuilder; import ru.m.puzzlez.storage.ImageStorage; import ru.m.puzzlez.storage.SettingsStorage; +import ru.m.puzzlez.wrap.PointExt; class Render extends SpriteView implements IRender { @@ -33,7 +35,7 @@ class Render extends SpriteView implements IRender { private var playerId(get, never):PlayerId; private function get_playerId():PlayerId { - return network.user.uuid; + return network.user.hasUuid() ? network.user.uuid : "local"; } private function get_scale():Float { @@ -57,7 +59,7 @@ class Render extends SpriteView implements IRender { private var imageView:CompleteView; private var parts:Map; private var activePart:PartView; - private var activePoint:Point; + private var activePoint:PointExt; private var movePoint:FlashPoint; @@ -79,25 +81,21 @@ class Render extends SpriteView implements IRender { } public function onGameEvent(event:GameEvent):Void { - switch event { - case START(state, resume): - onStart(state); - case CHANGE(PART_UPDATE(id, TABLE(point))): - var part:PartView = parts[id]; - part.position = point; - part.playerId = null; - case CHANGE(PART_UPDATE(id, HAND(playerId, point))): - var part:PartView = parts[id]; - part.position = point; - part.playerId = playerId; - case CHANGE(PART_UPDATE(id, IMAGE)): - var part:PartView = parts[id]; - part.complete(); - imageView.addChild(part); - imageView.redraw(); - case COMPLETE: - AlertView.alert("Complete!"); - case _: + if (event.hasStart()) { + onStart(event.start.state); + } else if (event.hasChange()) { + var part:PartView = parts[event.change.partId]; + part.playerId = event.change.playerId; + part.position = event.change.position; + switch event.change.location { + case PartLocation.IMAGE: + part.complete(); + imageView.addChild(part); + imageView.redraw(); + case _: + } + } else if (event.hasComplete()) { + AlertView.alert("Complete!"); } } @@ -108,10 +106,10 @@ class Render extends SpriteView implements IRender { var partView = PartView.factory(part); parts.set(part.id, partView); switch part.location { - case TABLE(point): - partView.position = point; + case PartLocation.TABLE: + partView.position = part.position; tableView.addChild(partView); - case IMAGE: + case PartLocation.IMAGE: partView.complete(); imageView.addChild(partView); case _: @@ -200,24 +198,38 @@ class Render extends SpriteView implements IRender { } activePart = pointPart; tableView.setChildIndex(activePart, tableView.numChildren - 1); - activePoint = RenderUtil.convertPoint(tableView.globalToLocal(point)); + activePoint = tableView.globalToLocal(point); tableView.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); tableView.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); - actions.emit(PART_TAKE(playerId, activePart.id)); + actions.emit(new GameAction() + .setAction(Action.TAKE) + .setPlayerId(playerId) + .setPartId(activePart.id) + ); } } private function onMouseMove(event:MouseEvent):Void { - var newPoint:Point = RenderUtil.convertPoint(tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY))); - var partPosition = activePart.position.add(newPoint).subtract(activePoint); - actions.emit(PART_MOVE(playerId, activePart.id, partPosition.clone())); + var newPoint:PointExt = tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY)); + var partPosition = cast(activePart.position, PointExt).add(newPoint).subtract(activePoint); + actions.emit(new GameAction() + .setAction(Action.MOVE) + .setPlayerId(playerId) + .setPartId(activePart.id) + .setPosition(partPosition) + ); activePoint = newPoint; } private function onMouseUp(event:MouseEvent):Void { - var newPoint:Point = RenderUtil.convertPoint(tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY))); - var partPosition = activePart.position.add(newPoint).subtract(activePoint); - actions.emit(PART_PUT(playerId, activePart.id, partPosition.clone())); + var newPoint:PointExt = tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY)); + var partPosition = cast(activePart.position, PointExt).add(newPoint).subtract(activePoint); + actions.emit(new GameAction() + .setAction(Action.PUT) + .setPlayerId(playerId) + .setPartId(activePart.id) + .setPosition(partPosition) + ); tableView.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); tableView.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); activePart = null; diff --git a/src/app/haxe/ru/m/puzzlez/render/RenderUtil.hx b/src/app/haxe/ru/m/puzzlez/render/RenderUtil.hx index ccf559a..507ff54 100644 --- a/src/app/haxe/ru/m/puzzlez/render/RenderUtil.hx +++ b/src/app/haxe/ru/m/puzzlez/render/RenderUtil.hx @@ -4,12 +4,13 @@ import flash.display.BitmapData; import flash.display.Shape; import flash.geom.Matrix; import hw.color.Color; -import hw.geom.Point; -import hw.geom.Rectangle; import ru.m.draw.DrawPath; -import ru.m.puzzlez.core.Part; +import ru.m.puzzlez.proto.core.Point; +import ru.m.puzzlez.proto.core.Rectangle; +import ru.m.puzzlez.proto.game.Part; import ru.m.puzzlez.render.part.IPartBuilder; import ru.m.puzzlez.render.part.PartMask; +import ru.m.puzzlez.wrap.RectangleExt; typedef DrawSetting = { var offset:Point; @@ -24,13 +25,13 @@ typedef PartImage = { class RenderUtil { public static var shadowSettings(default, null):Array = [ - {offset: new Point(-2, -2), color: 0x000000, opacity: 0.4}, - {offset: new Point(2, 2), color: 0xffffff, opacity: 0.4}, + {offset: new Point().setX(-2).setY(-2), color: 0x000000, opacity: 0.4}, + {offset: new Point().setX(2).setY(2), color: 0xffffff, opacity: 0.4}, ]; public static var borderSettings(default, null):Array = [ - {offset: new Point(-1, -1), color: 0x555555, opacity: 0.4}, - {offset: new Point(1, 1), color: 0xcccccc, opacity: 0.4}, + {offset: new Point().setX(-1).setY(-1), color: 0x555555, opacity: 0.4}, + {offset: new Point().setX(1).setY(1), color: 0xcccccc, opacity: 0.4}, ]; @:provide static var builder:IPartBuilder; @@ -46,14 +47,18 @@ class RenderUtil { } private static function buildPartGeometry(part:Part):{rect:Rectangle, drawRect:Rectangle} { - var source = new Rectangle(part.rect.width * part.gridX, part.rect.height * part.gridY, part.rect.width, part.rect.height); - var rect = source.clone(); + var source = new Rectangle() + .setX(part.rect.width * part.point.x) + .setY(part.rect.height * part.point.y) + .setWidth(part.rect.width) + .setHeight(part.rect.height); + var rect = cast(source, RectangleExt).clone(); var offset = rect.width / 4 + rect.width * 0.05; rect.x -= offset; rect.y -= offset; rect.width += offset * 2; rect.height += offset * 2; - var drawRect = source.clone(); + var drawRect = cast(source, RectangleExt).clone(); drawRect.x = offset; drawRect.y = offset ; return {rect:rect, drawRect:drawRect}; @@ -113,10 +118,10 @@ class RenderUtil { var s = Math.min(1, Math.min(target.width / source.width, target.height / source.height)); var width = source.width * s; var height = source.height * s; - return new Rectangle((target.width - width) / 2, (target.height - height) / 2, width, height); - } - - public static function convertPoint(point:flash.geom.Point):Point { - return new Point(point.x, point.y); + return new Rectangle() + .setX((target.width - width) / 2) + .setY((target.height - height) / 2) + .setWidth(width) + .setHeight(height); } } diff --git a/src/app/haxe/ru/m/puzzlez/render/part/BasePartBuilder.hx b/src/app/haxe/ru/m/puzzlez/render/part/BasePartBuilder.hx index 8b41c70..cb9fd19 100644 --- a/src/app/haxe/ru/m/puzzlez/render/part/BasePartBuilder.hx +++ b/src/app/haxe/ru/m/puzzlez/render/part/BasePartBuilder.hx @@ -1,8 +1,10 @@ package ru.m.puzzlez.render.part; -import hw.geom.Rectangle; +import ru.m.puzzlez.wrap.RectangleExt; +import ru.m.puzzlez.proto.core.Rectangle; import ru.m.draw.DrawPath; -import ru.m.puzzlez.core.Part; +import ru.m.puzzlez.proto.game.PartBound; +import ru.m.puzzlez.proto.game.PartBounds; import ru.m.puzzlez.render.part.IPartBuilder; class BasePartBuilder implements IPartBuilder { @@ -17,7 +19,7 @@ class BasePartBuilder implements IPartBuilder { private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, bound:PartBound):Void { } - public function build(rect:Rectangle, bounds:PartBounds):DrawPath { + public function build(rect:RectangleExt, bounds:PartBounds):DrawPath { var path = new DrawPath(); createAngle(path, rect.left, rect.top, true); createBound(path, rect.left, rect.top, rect.right, rect.top, bounds.top); diff --git a/src/app/haxe/ru/m/puzzlez/render/part/ClassicPartBuilder.hx b/src/app/haxe/ru/m/puzzlez/render/part/ClassicPartBuilder.hx index e36a714..b8a6edc 100644 --- a/src/app/haxe/ru/m/puzzlez/render/part/ClassicPartBuilder.hx +++ b/src/app/haxe/ru/m/puzzlez/render/part/ClassicPartBuilder.hx @@ -1,8 +1,8 @@ package ru.m.puzzlez.render.part; import ru.m.draw.DrawPath; -import ru.m.puzzlez.core.BoundType; -import ru.m.puzzlez.core.Part; +import ru.m.puzzlez.proto.game.BoundType; +import ru.m.puzzlez.proto.game.PartBound; class ClassicPartBuilder extends BasePartBuilder { @@ -13,18 +13,17 @@ class ClassicPartBuilder extends BasePartBuilder { var spikeWidth = boundLength * 0.2; var spikeOffset = (boundLength - spikeWidth) / 2; var spikeDepth = switch bound.spike { - case NONE: 0; - case IN: spikeWidth; - case OUT: -spikeWidth; + case BoundType.IN: spikeWidth; + case BoundType.OUT: -spikeWidth; + case _: 0; }; var spikeSideOffset = switch bound.side { - case NONE: 0; - case IN: boundLength * -0.04; - case OUT: boundLength * 0.04; + case BoundType.IN: boundLength * -0.04; + case BoundType.OUT: boundLength * 0.04; + case _: 0; } switch bound.spike { - case NONE: - case IN | OUT: + case BoundType.IN | BoundType.OUT: path.commands.push(LINE_TO( fromX + spikeOffset * dx + spikeSideOffset * dy, fromY + spikeOffset * dy + spikeSideOffset * dx @@ -41,6 +40,7 @@ class ClassicPartBuilder extends BasePartBuilder { fromX + (spikeOffset + spikeWidth) * dx + spikeSideOffset * dy, fromY + (spikeOffset + spikeWidth) * dy + spikeSideOffset * dx )); + case _: } } } diff --git a/src/app/haxe/ru/m/puzzlez/render/part/IPartBuilder.hx b/src/app/haxe/ru/m/puzzlez/render/part/IPartBuilder.hx index 00a74bc..40ee83a 100644 --- a/src/app/haxe/ru/m/puzzlez/render/part/IPartBuilder.hx +++ b/src/app/haxe/ru/m/puzzlez/render/part/IPartBuilder.hx @@ -1,9 +1,9 @@ package ru.m.puzzlez.render.part; -import hw.geom.Rectangle; import ru.m.draw.DrawPath; -import ru.m.puzzlez.core.Part; +import ru.m.puzzlez.proto.game.PartBounds; +import ru.m.puzzlez.wrap.RectangleExt; @:provide(ClassicPartBuilder) interface IPartBuilder { - public function build(rect:Rectangle, bound:PartBounds):DrawPath; + public function build(rect:RectangleExt, bound:PartBounds):DrawPath; } diff --git a/src/app/haxe/ru/m/puzzlez/render/part/SquarePartBuilder.hx b/src/app/haxe/ru/m/puzzlez/render/part/SquarePartBuilder.hx index beac8c3..8ab3330 100644 --- a/src/app/haxe/ru/m/puzzlez/render/part/SquarePartBuilder.hx +++ b/src/app/haxe/ru/m/puzzlez/render/part/SquarePartBuilder.hx @@ -1,8 +1,8 @@ package ru.m.puzzlez.render.part; import ru.m.draw.DrawPath; -import ru.m.puzzlez.core.BoundType; -import ru.m.puzzlez.core.Part; +import ru.m.puzzlez.proto.game.BoundType; +import ru.m.puzzlez.proto.game.PartBound; class SquarePartBuilder extends BasePartBuilder { @@ -13,13 +13,13 @@ class SquarePartBuilder extends BasePartBuilder { var spikeWidth = boundLength * 0.2; var spikeOffset = (boundLength - spikeWidth) / 2; var spikeDepth = switch bound.spike { - case NONE: 0; - case IN: spikeWidth; - case OUT: -spikeWidth; + case BoundType.NONE: 0; + case BoundType.IN: spikeWidth; + case BoundType.OUT: -spikeWidth; } switch bound.spike { - case NONE: - case IN | OUT: + case BoundType.NONE: + case BoundType.IN | BoundType.OUT: path.commands.push(LINE_TO( fromX + spikeOffset * dx, fromY + spikeOffset * dy diff --git a/src/app/haxe/ru/m/puzzlez/storage/GameStorage.hx b/src/app/haxe/ru/m/puzzlez/storage/GameStorage.hx index a6cae1f..ca0389d 100644 --- a/src/app/haxe/ru/m/puzzlez/storage/GameStorage.hx +++ b/src/app/haxe/ru/m/puzzlez/storage/GameStorage.hx @@ -1,27 +1,32 @@ package ru.m.puzzlez.storage; import ru.m.data.DataStorage; -import ru.m.puzzlez.core.GameState; import ru.m.puzzlez.core.Id; import ru.m.puzzlez.core.ImageListSource; +import ru.m.puzzlez.proto.game.GameState; @:provide class GameStorage extends DataStorage { inline private static var NAME = "game"; - inline private static var VERSION = 4; + inline private static var VERSION = 6; public function new() { super( '${NAME}/${VERSION}', - new MetaBuilder(item -> ["id" => item.preset.imageId, "status" => item.status, "date" => Date.now().toString()]), - new Converter(id -> id.toString(), data -> ImageId.fromString(data)) + new MetaBuilder(item -> [ + "id" => item.preset.imageId, + "status" => Std.string(item.status), + "date" => Date.now().toString() + ]), + new Converter(id -> id.toString(), data -> ImageId.fromString(data)), + new ProtoConverter(GameState) ); } - public function statusSource(status:GameStatus):ImageListSource { + public function statusSource(status:Int):ImageListSource { return { - title: status, + title: Std.string(status), // # ToDo: source: this, - filter: ["status" => status], + filter: ["status" => Std.string(status)], } } } diff --git a/src/app/haxe/ru/m/puzzlez/view/GameFrame.hx b/src/app/haxe/ru/m/puzzlez/view/GameFrame.hx index a242024..1737656 100644 --- a/src/app/haxe/ru/m/puzzlez/view/GameFrame.hx +++ b/src/app/haxe/ru/m/puzzlez/view/GameFrame.hx @@ -1,15 +1,16 @@ package ru.m.puzzlez.view; +import ru.m.puzzlez.proto.game.GameStatus; import haxe.Timer; import hw.view.frame.FrameSwitcher; import hw.view.frame.FrameView; import hw.view.popup.ConfirmView; import promhx.Promise; import ru.m.puzzlez.core.Game; -import ru.m.puzzlez.core.GameEvent; -import ru.m.puzzlez.core.GameState; import ru.m.puzzlez.core.IGame; import ru.m.puzzlez.net.NetworkGame; +import ru.m.puzzlez.proto.event.GameEvent; +import ru.m.puzzlez.proto.game.GameState; import ru.m.puzzlez.render.IRender; import ru.m.puzzlez.storage.GameStorage; import ru.m.puzzlez.storage.SettingsStorage; @@ -73,10 +74,8 @@ import ru.m.puzzlez.view.popup.PreviewPopup; } private function onGameEvent(event:GameEvent):Void { - switch event { - case START(_) | ACTION(PART_PUT(_, _)): - toSave(); - case _: + if (event.hasStart() || event.hasAction()) { + toSave(); } } @@ -94,7 +93,7 @@ import ru.m.puzzlez.view.popup.PreviewPopup; } private function back():Void { - (game.state.status == COMPLETE ? Promise.promise(true) : ConfirmView.confirm("Exit?")) + (game.state.status == GameStatus.COMPLETE ? Promise.promise(true) : ConfirmView.confirm("Exit?")) .then(result -> { if (result) { switcher.change(ImageListFrame.ID, storage.statusSource(game.state.status)); diff --git a/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx b/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx index 3e297b4..cbc3b1f 100644 --- a/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx +++ b/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx @@ -1,5 +1,6 @@ package ru.m.puzzlez.view; +import ru.m.puzzlez.proto.game.GameStatus; import ru.m.puzzlez.net.Network; import hw.view.data.DataView; import hw.view.form.ButtonView; @@ -7,7 +8,6 @@ import hw.view.frame.FrameSwitcher; import hw.view.frame.FrameView; import ru.m.data.IDataSource; import ru.m.pixabay.PixabayApi; -import ru.m.puzzlez.core.GameState.GameStatus; import ru.m.puzzlez.core.ImageListSource; import ru.m.puzzlez.source.AssetSource; import ru.m.puzzlez.source.FileSource; @@ -43,13 +43,13 @@ import ru.m.update.Updater; } private function refresh():Void { - var startedRequest:Page = {index: 0, count: 0, filter: ["status" => STARTED]}; + var startedRequest:Page = {index: 0, count: 0, filter: ["status" => Std.string(GameStatus.STARTED)]}; gameStorage.getIndexPage(startedRequest).then(page -> { var total = page.total; loadButton.text = 'Resume (${total})'; loadButton.disabled = total == 0; }); - var completeRequest:Page = {index: 0, count: 0, filter: ["status" => COMPLETE]}; + var completeRequest:Page = {index: 0, count: 0, filter: ["status" => Std.string(GameStatus.COMPLETE)]}; gameStorage.getIndexPage(completeRequest).then(page -> { var total = page.total; completeButton.text = 'Complete (${total})'; @@ -77,7 +77,7 @@ import ru.m.update.Updater; switcher.change(ImageListFrame.ID, source); } - private function openGames(status:GameStatus):Void { + private function openGames(status:Int):Void { switcher.change(ImageListFrame.ID, gameStorage.statusSource(status)); } diff --git a/src/app/haxe/ru/m/puzzlez/view/StartFrame.yaml b/src/app/haxe/ru/m/puzzlez/view/StartFrame.yaml index e0b5d43..9ca2ab6 100644 --- a/src/app/haxe/ru/m/puzzlez/view/StartFrame.yaml +++ b/src/app/haxe/ru/m/puzzlez/view/StartFrame.yaml @@ -35,11 +35,11 @@ views: - id: load $type: hw.view.form.ButtonView text: Load - +onPress: ~openGames('started') + +onPress: ~openGames(1) - id: complete $type: hw.view.form.ButtonView text: Complete - +onPress: ~openGames('complete') + +onPress: ~openGames(2) - id: network $type: hw.view.form.ButtonView text: Network diff --git a/src/app/haxe/ru/m/puzzlez/view/common/PresetView.hx b/src/app/haxe/ru/m/puzzlez/view/common/PresetView.hx index 3d573b1..00bfe48 100644 --- a/src/app/haxe/ru/m/puzzlez/view/common/PresetView.hx +++ b/src/app/haxe/ru/m/puzzlez/view/common/PresetView.hx @@ -1,10 +1,11 @@ package ru.m.puzzlez.view.common; +import ru.m.puzzlez.wrap.RectangleExt; +import ru.m.puzzlez.proto.game.GameState; import flash.display.Graphics; import flash.display.BitmapData; import flash.display.Shape; import hw.view.group.GroupView; -import ru.m.puzzlez.core.GameState; import ru.m.puzzlez.render.part.IPartBuilder; import ru.m.puzzlez.render.RenderUtil; import ru.m.puzzlez.storage.ImageStorage; @@ -57,8 +58,8 @@ class PresetView extends GroupView { return; } var preset = state.preset; - var partWidth = preset.imageRect.width / preset.grid.width; - var partHeight = preset.imageRect.height / preset.grid.height; + var partWidth = preset.imageRect.width / preset.grid.x; + var partHeight = preset.imageRect.height / preset.grid.y; var graphics:Graphics = table.graphics; graphics.clear(); graphics.beginBitmapFill(image, null, false, true); @@ -66,9 +67,9 @@ class PresetView extends GroupView { graphics.endFill(); for (part in state.parts) { - var rect = part.rect.clone(); - rect.x = part.gridX * part.rect.width; - rect.y = part.gridY * part.rect.height; + var rect = cast(part.rect, RectangleExt).clone(); + rect.x = part.point.x * part.rect.width; + rect.y = part.point.y * part.rect.height; var path = builder.build(rect, part.bounds); for (value in RenderUtil.borderSettings) { graphics.lineStyle(1, value.color, value.opacity); diff --git a/src/app/haxe/ru/m/puzzlez/view/popup/PreviewPopup.hx b/src/app/haxe/ru/m/puzzlez/view/popup/PreviewPopup.hx index 125f45c..dccd948 100644 --- a/src/app/haxe/ru/m/puzzlez/view/popup/PreviewPopup.hx +++ b/src/app/haxe/ru/m/puzzlez/view/popup/PreviewPopup.hx @@ -1,9 +1,9 @@ package ru.m.puzzlez.view.popup; +import ru.m.puzzlez.proto.game.GameState; import flash.events.MouseEvent; import hw.view.popup.PopupView; import promhx.Promise; -import ru.m.puzzlez.core.GameState; import ru.m.puzzlez.view.common.PresetView; @:singleton @:template class PreviewPopup extends PopupView { diff --git a/src/common/haxe/ru/m/puzzlez/core/BoundType.hx b/src/common/haxe/ru/m/puzzlez/core/BoundType.hx deleted file mode 100644 index 2af2e6a..0000000 --- a/src/common/haxe/ru/m/puzzlez/core/BoundType.hx +++ /dev/null @@ -1,7 +0,0 @@ -package ru.m.puzzlez.core; - -enum BoundType { - NONE; - OUT; - IN; -} diff --git a/src/common/haxe/ru/m/puzzlez/core/EventUtil.hx b/src/common/haxe/ru/m/puzzlez/core/EventUtil.hx new file mode 100644 index 0000000..2ab3a83 --- /dev/null +++ b/src/common/haxe/ru/m/puzzlez/core/EventUtil.hx @@ -0,0 +1,36 @@ +package ru.m.puzzlez.core; + +import ru.m.puzzlez.proto.event.GameComplete; +import ru.m.puzzlez.proto.event.GameChange; +import ru.m.puzzlez.proto.game.Part; +import ru.m.puzzlez.proto.event.GameAction; +import ru.m.puzzlez.proto.event.GameStart; +import ru.m.puzzlez.proto.event.GameEvent; +import ru.m.puzzlez.proto.game.GameState; + +class EventUtil { + + public static function start(state:GameState, resume: Bool):GameEvent { + return new GameEvent().setStart(new GameStart() + .setState(state) + .setResume(resume) + ); + } + + public static function complete():GameEvent { + return new GameEvent().setComplete(new GameComplete()); + } + + public static function action(action:GameAction):GameEvent { + return new GameEvent().setAction(action); + } + + public static function change(part:Part):GameEvent { + return new GameEvent().setChange(new GameChange() + .setPartId(part.id) + .setLocation(part.location) + .setPosition(part.position) + .setPlayerId(part.playerId) + ); + } +} diff --git a/src/common/haxe/ru/m/puzzlez/core/Game.hx b/src/common/haxe/ru/m/puzzlez/core/Game.hx index 4d9486d..2b3c31c 100644 --- a/src/common/haxe/ru/m/puzzlez/core/Game.hx +++ b/src/common/haxe/ru/m/puzzlez/core/Game.hx @@ -1,10 +1,15 @@ package ru.m.puzzlez.core; -import hw.geom.Point; +import ru.m.puzzlez.proto.core.Point; import hw.signal.Signal; -import ru.m.puzzlez.core.GameEvent; -import ru.m.puzzlez.core.GameState; -import ru.m.puzzlez.core.PartLocation; +import ru.m.puzzlez.proto.event.gameaction.Action; +import ru.m.puzzlez.proto.event.GameAction; +import ru.m.puzzlez.proto.event.GameEvent; +import ru.m.puzzlez.proto.game.GameState; +import ru.m.puzzlez.proto.game.GameStatus; +import ru.m.puzzlez.proto.game.Part; +import ru.m.puzzlez.proto.game.PartLocation; +import ru.m.puzzlez.wrap.PointExt; class Game implements IGame { public var state(default, null):GameState; @@ -23,42 +28,42 @@ class Game implements IGame { } public function action(action:GameAction):Void { - events.emit(ACTION(action)); + events.emit(EventUtil.action(action)); } public function start():Void { switch state.status { - case READY: + case GameStatus.READY: shuffle(); - state.status = STARTED; - events.emit(START(state, false)); + state.status = GameStatus.STARTED; + events.emit(EventUtil.start(state, false)); case _: - events.emit(START(state, true)); + events.emit(EventUtil.start(state, true)); } } private function shuffle():Void { for (part in state.parts) { switch part.location { - case TABLE(_): + case PartLocation.TABLE: var bound = part.rect.width * 0.25; var x = bound + Math.random() * (state.preset.tableRect.width - part.rect.width - bound * 2); var y = bound + Math.random() * (state.preset.tableRect.height - part.rect.height - bound * 2); - part.location = TABLE(new Point(x, y)); + part.position = new PointExt(x, y); case _: } } } - private static function distance(a:Point, b:Point):Float { - var diff = a.subtract(b); + private static function distance(a:PointExt, b:PointExt):Float { + var diff:Point = a.subtract(b); return Math.abs(diff.x) + Math.abs(diff.y); } private function checkIsComplete():Bool { for (part in partsById) { switch part.location { - case IMAGE: + case PartLocation.IMAGE: case _: return false; } } @@ -66,40 +71,42 @@ class Game implements IGame { } private function onGameEvent(event:GameEvent):Void { - switch event { - case ACTION(PART_TAKE(playerId, partId)): - var part = partsById[partId]; - switch part.location { - case TABLE(point): - part.location = HAND(playerId, point); - events.emit(CHANGE(PART_UPDATE(partId, part.location))); - case _: - } - case ACTION(PART_MOVE(playerId, partId, point)): - var part = partsById[partId]; - switch part.location { - case HAND(currentPlayerId, _) if (currentPlayerId == playerId): - part.location = HAND(playerId, point); - events.emit(CHANGE(PART_UPDATE(partId, part.location))); - case _: - } - case ACTION(PART_PUT(playerId, partId, point)): - var part:Part = partsById[partId]; - var target:Point = state.preset.imageRect.position.clone(); - target = target.add(new Point(part.gridX * part.rect.width, part.gridY * part.rect.height)); - var d = distance(target, point); - if (d < 70) { - part.location = IMAGE; - events.emit(CHANGE(PART_UPDATE(partId, part.location))); - if (checkIsComplete()) { - state.status = COMPLETE; - events.emit(COMPLETE); + if (event.hasAction()) { + var part:Part = partsById[event.action.partId]; + switch event.action.action { + case Action.TAKE: + switch part.location { + case PartLocation.TABLE: + part.location = PartLocation.HAND; + part.playerId = event.action.playerId; + events.emit(EventUtil.change(part)); + case _: } - } else { - part.location = TABLE(point); - events.emit(CHANGE(PART_UPDATE(partId, part.location))); - } - case _: + case Action.MOVE: + switch part.location { + case PartLocation.HAND if (event.action.playerId == part.playerId): + part.position = event.action.position; + events.emit(EventUtil.change(part)); + case _: + } + case Action.PUT: + part.playerId = null; + var target = new PointExt(state.preset.imageRect.x, state.preset.imageRect.y) + .add(new PointExt(part.point.x * part.rect.width, part.point.y * part.rect.height)); + var d = distance(target, event.action.position); + if (d < 70) { + part.location = PartLocation.IMAGE; + events.emit(EventUtil.change(part)); + if (checkIsComplete()) { + state.status = GameStatus.COMPLETE; + events.emit(EventUtil.complete()); + } + } else { + part.location = PartLocation.TABLE; + part.position = event.action.position; + events.emit(EventUtil.change(part)); + } + } } } diff --git a/src/common/haxe/ru/m/puzzlez/core/GameEvent.hx b/src/common/haxe/ru/m/puzzlez/core/GameEvent.hx deleted file mode 100644 index 6dce154..0000000 --- a/src/common/haxe/ru/m/puzzlez/core/GameEvent.hx +++ /dev/null @@ -1,21 +0,0 @@ -package ru.m.puzzlez.core; - -import ru.m.puzzlez.core.Id; -import hw.geom.Point; - -enum GameAction { - PART_TAKE(playerId:PlayerId, partId:PartId); - PART_MOVE(playerId:PlayerId, partId:PartId, point:Point); - PART_PUT(playerId:PlayerId, partId:PartId, point:Point); -} - -enum GameChange { - PART_UPDATE(id:Int, location:PartLocation); -} - -enum GameEvent { - START(state:GameState, resume:Bool); - ACTION(action:GameAction); - CHANGE(change:GameChange); - COMPLETE; -} diff --git a/src/common/haxe/ru/m/puzzlez/core/GamePreset.hx b/src/common/haxe/ru/m/puzzlez/core/GamePreset.hx deleted file mode 100644 index a21c2dd..0000000 --- a/src/common/haxe/ru/m/puzzlez/core/GamePreset.hx +++ /dev/null @@ -1,11 +0,0 @@ -package ru.m.puzzlez.core; - -import hw.geom.Rectangle; -import ru.m.puzzlez.core.Id; - -typedef GamePreset = { - var imageId:ImageId; - var grid:Grid; - var tableRect:Rectangle; - var imageRect:Rectangle; -} diff --git a/src/common/haxe/ru/m/puzzlez/core/GameState.hx b/src/common/haxe/ru/m/puzzlez/core/GameState.hx deleted file mode 100644 index bf63087..0000000 --- a/src/common/haxe/ru/m/puzzlez/core/GameState.hx +++ /dev/null @@ -1,15 +0,0 @@ -package ru.m.puzzlez.core; - -enum abstract GameStatus(String) from String to String { - var READY = "ready"; - var STARTED = "started"; - var COMPLETE = "complete"; -} - -typedef GameState = { - var id:String; - var status:GameStatus; - var preset:GamePreset; - var parts:Array; - @:optional var online:Bool; -} diff --git a/src/common/haxe/ru/m/puzzlez/core/GameUtil.hx b/src/common/haxe/ru/m/puzzlez/core/GameUtil.hx index 4bd121d..4bce064 100644 --- a/src/common/haxe/ru/m/puzzlez/core/GameUtil.hx +++ b/src/common/haxe/ru/m/puzzlez/core/GameUtil.hx @@ -1,65 +1,64 @@ package ru.m.puzzlez.core; -import hw.geom.Point; -import hw.geom.Rectangle; -import ru.m.puzzlez.core.BoundType; -import ru.m.puzzlez.core.GameState; import ru.m.puzzlez.core.Id; -import ru.m.puzzlez.core.Part; -import ru.m.puzzlez.core.PartLocation; import ru.m.puzzlez.core.Side; +import ru.m.puzzlez.proto.core.IntPoint; +import ru.m.puzzlez.proto.core.Point; +import ru.m.puzzlez.proto.core.Rectangle; +import ru.m.puzzlez.proto.game.BoundType; +import ru.m.puzzlez.proto.game.GamePreset; +import ru.m.puzzlez.proto.game.GameState; +import ru.m.puzzlez.proto.game.GameStatus; +import ru.m.puzzlez.proto.game.Part; +import ru.m.puzzlez.proto.game.PartBound; +import ru.m.puzzlez.proto.game.PartBounds; +import ru.m.puzzlez.proto.game.PartLocation; class BoundsMap { - private var grid:Grid; + private var grid:IntPoint; private var bounds:Array; - public function new(grid:Grid) { + public function new(grid:IntPoint) { this.grid = grid; bounds = []; - for (x in 0...grid.width + 1) { - for (y in 0...grid.height + 1) { + for (x in 0...grid.x + 1) { + for (y in 0...grid.y + 1) { bounds.push(buildPartBound()); bounds.push(buildPartBound()); } } } - public function buildBound():BoundType { + public function buildBound():Int { return Math.random() > 0.5 ? BoundType.OUT : BoundType.IN; } public function buildPartBound():PartBound { - return { - spike: buildBound(), - side: buildBound(), - } + return new PartBound().setSpike(buildBound()).setSide(buildBound()); } public function buildNonePartBound():PartBound { - return { - spike: NONE, - side: NONE, - } + return new PartBound().setSpike(BoundType.NONE).setSide(BoundType.NONE); } - public function revert(type:BoundType):BoundType { + public function revert(type:Int):Int { return switch type { - case IN: OUT; - case OUT: IN; - case NONE: NONE; + case BoundType.IN: BoundType.OUT; + case BoundType.OUT: BoundType.IN; + case _: BoundType.NONE; } } public function getBound(x:Int, y:Int, side:Side):PartBound { var index = switch side { - case TOP: x + (grid.width + 1) * (y * 2); - case LEFT: x + (grid.width + 1) * (y + 1); - case RIGHT: x + (grid.width + 1) * (y + 1) + 1; - case BOTTOM: x + (grid.width + 1) * (y * 2) + (grid.width + 1) * 2; + case TOP: x + (grid.x + 1) * (y * 2); + case LEFT: x + (grid.x + 1) * (y + 1); + case RIGHT: x + (grid.x + 1) * (y + 1) + 1; + case BOTTOM: x + (grid.x + 1) * (y * 2) + (grid.x + 1) * 2; } return switch side { - case TOP | LEFT: {spike: revert(bounds[index].spike), side: revert(bounds[index].side)}; + case TOP | LEFT: new PartBound().setSpike(revert(bounds[index].spike)).setSide(revert(bounds[index].side)); case _: bounds[index]; } } @@ -80,67 +79,72 @@ class GameUtil { var offsetY = 200; var imageSize = 1024; var s = width / height; - var imageRect = new Rectangle(offsetX, offsetY, imageSize, imageSize / s); - var tableRect = new Rectangle(0, 0, imageRect.width + offsetX * 2, imageRect.height + offsetY * 2); - return { - imageId: imageId, - grid: {width: width, height: height}, - tableRect: tableRect, - imageRect: imageRect, - } + var imageRect = new Rectangle() + .setX(offsetX) + .setY(offsetY) + .setWidth(imageSize) + .setHeight(imageSize / s); + var tableRect = new Rectangle() + .setX(0) + .setY(0) + .setWidth(imageRect.width + offsetX * 2) + .setHeight(imageRect.height + offsetY * 2); + return new GamePreset() + .setImageId(imageId) + .setGrid(new IntPoint().setX(width).setY(height)) + .setTableRect(tableRect) + .setImageRect(imageRect); } public static function buildState(preset:GamePreset):GameState { var parts:Array = []; - var partWidth = preset.imageRect.width / preset.grid.width; - var partHeight = preset.imageRect.height / preset.grid.height; - var position = preset.imageRect.position; + var partWidth = preset.imageRect.width / preset.grid.x; + var partHeight = preset.imageRect.height / preset.grid.y; + var position = new Point().setX(preset.imageRect.x).setY(preset.imageRect.y); var boundsMap = new BoundsMap(preset.grid); - for (y in 0...preset.grid.height) { - for (x in 0...preset.grid.width) { - var bounds:PartBounds = { - left: boundsMap.getBound(x, y, LEFT), - right: boundsMap.getBound(x, y, RIGHT), - top: boundsMap.getBound(x, y, TOP), - bottom: boundsMap.getBound(x, y, BOTTOM), - } + for (y in 0...preset.grid.y) { + for (x in 0...preset.grid.x) { + var bounds:PartBounds = new PartBounds() + .setLeft(boundsMap.getBound(x, y, LEFT)) + .setRight(boundsMap.getBound(x, y, RIGHT)) + .setTop(boundsMap.getBound(x, y, TOP)) + .setBottom(boundsMap.getBound(x, y, BOTTOM)); if (x == 0) { bounds.left = boundsMap.buildNonePartBound(); } if (y == 0) { bounds.top = boundsMap.buildNonePartBound(); } - if (x == preset.grid.width - 1) { + if (x == preset.grid.x - 1) { bounds.right = boundsMap.buildNonePartBound(); } - if (y == preset.grid.height - 1) { + if (y == preset.grid.y - 1) { bounds.bottom = boundsMap.buildNonePartBound(); } var id = (x << 16) + y; - var position = new Point(position.x + x * partWidth, position.y + y * partHeight); - parts.push({ - id: id, - gridX: x, - gridY: y, - location: TABLE(position), - bounds: bounds, - rect: new Rectangle(0, 0, partWidth, partHeight), - }); + var position = new Point().setX(position.x + x * partWidth).setY(position.y + y * partHeight); + parts.push(new Part() + .setId(id) + .setPoint(new IntPoint().setX(x).setY(y)) + .setLocation(PartLocation.TABLE) + .setPosition(position) + .setBounds(bounds) + .setRect(new Rectangle().setX(0).setY(0).setWidth(partWidth).setHeight(partHeight)) + ); } } - return { - id: IdUtil.generate(), - status: READY, - preset: preset, - parts: parts, - } + return new GameState() + .setId(IdUtil.generate()) + .setStatus(GameStatus.READY) + .setPreset(preset) + .setParts(parts); } public static function calcProgress(state:GameState):{complete:Int, total:Int} { var complete = 0; for (part in state.parts) { switch part.location { - case IMAGE: complete++; + case PartLocation.IMAGE: complete++; case _: } } diff --git a/src/common/haxe/ru/m/puzzlez/core/Grid.hx b/src/common/haxe/ru/m/puzzlez/core/Grid.hx deleted file mode 100644 index 4e0456d..0000000 --- a/src/common/haxe/ru/m/puzzlez/core/Grid.hx +++ /dev/null @@ -1,6 +0,0 @@ -package ru.m.puzzlez.core; - -typedef Grid = { - var width:Int; - var height:Int; -} diff --git a/src/common/haxe/ru/m/puzzlez/core/IGame.hx b/src/common/haxe/ru/m/puzzlez/core/IGame.hx index ef0b942..f4ee109 100644 --- a/src/common/haxe/ru/m/puzzlez/core/IGame.hx +++ b/src/common/haxe/ru/m/puzzlez/core/IGame.hx @@ -1,7 +1,9 @@ package ru.m.puzzlez.core; -import ru.m.puzzlez.core.GameEvent.GameAction; import hw.signal.Signal; +import ru.m.puzzlez.proto.event.GameAction; +import ru.m.puzzlez.proto.event.GameEvent; +import ru.m.puzzlez.proto.game.GameState; interface IGame { public var state(default, null):GameState; diff --git a/src/common/haxe/ru/m/puzzlez/core/Part.hx b/src/common/haxe/ru/m/puzzlez/core/Part.hx deleted file mode 100644 index 6d0bdd1..0000000 --- a/src/common/haxe/ru/m/puzzlez/core/Part.hx +++ /dev/null @@ -1,24 +0,0 @@ -package ru.m.puzzlez.core; - -import hw.geom.Rectangle; - -typedef PartBound = { - var spike:BoundType; - var side:BoundType; -} - -typedef PartBounds = { - var left:PartBound; - var right:PartBound; - var top:PartBound; - var bottom:PartBound; -} - -typedef Part = { - var id:Int; - var gridX:Int; - var gridY:Int; - var location:PartLocation; - var bounds:PartBounds; - var rect:Rectangle; -} diff --git a/src/common/haxe/ru/m/puzzlez/core/PartLocation.hx b/src/common/haxe/ru/m/puzzlez/core/PartLocation.hx deleted file mode 100644 index 58979f0..0000000 --- a/src/common/haxe/ru/m/puzzlez/core/PartLocation.hx +++ /dev/null @@ -1,10 +0,0 @@ -package ru.m.puzzlez.core; - -import hw.geom.Point; -import ru.m.puzzlez.core.Id; - -enum PartLocation { - HAND(playerId:PlayerId, point:Point); - TABLE(point:Point); - IMAGE; -} diff --git a/src/common/haxe/ru/m/puzzlez/wrap/PointExt.hx b/src/common/haxe/ru/m/puzzlez/wrap/PointExt.hx new file mode 100644 index 0000000..4eada39 --- /dev/null +++ b/src/common/haxe/ru/m/puzzlez/wrap/PointExt.hx @@ -0,0 +1,41 @@ +package ru.m.puzzlez.wrap; + +import ru.m.puzzlez.proto.core.Point; +#if openfl +import flash.geom.Point as FlashPoint; +#end + +abstract PointExt(Point) from Point to Point { + + public function new(x: Float = 0, y: Float = 0) { + this = new Point() + .setX(x) + .setY(y); + } + + public function clone():PointExt { + return new Point() + .setX(this.x) + .setY(this.y); + } + + public function add(point:Point):PointExt { + return new Point() + .setX(this.x + point.x) + .setY(this.y + point.y); + } + + public function subtract(point:Point):PointExt { + return new Point() + .setX(this.x - point.x) + .setY(this.y - point.y); + } + + #if openfl + @:from public static function fromFlashPoint(point:FlashPoint):PointExt { + return new Point() + .setX(point.x) + .setY(point.y); + } + #end +} diff --git a/src/common/haxe/ru/m/puzzlez/wrap/RectangleExt.hx b/src/common/haxe/ru/m/puzzlez/wrap/RectangleExt.hx new file mode 100644 index 0000000..440b106 --- /dev/null +++ b/src/common/haxe/ru/m/puzzlez/wrap/RectangleExt.hx @@ -0,0 +1,50 @@ +package ru.m.puzzlez.wrap; + +import ru.m.puzzlez.proto.core.Point; +import ru.m.puzzlez.proto.core.Rectangle; + +abstract RectangleExt(Rectangle) from Rectangle to Rectangle { + public var left(get, never):Float; + public var right(get, never):Float; + public var top(get, never):Float; + public var bottom(get, never):Float; + public var size(get, never):Point; + + public function new(x:Float = 0, y:Float = 0, width:Float = 0, height:Float = 0) { + this = new Rectangle() + .setX(x) + .setY(y) + .setWidth(width) + .setHeight(height); + } + + private function get_left():Float { + return this.x; + } + + private function get_right():Float { + return this.x + this.width; + } + + private function get_top():Float { + return this.y; + } + + private function get_bottom():Float { + return this.y + this.height; + } + + private function get_size():Point { + return new Point() + .setX(this.width) + .setY(this.height); + } + + public function clone():Rectangle { + return new Rectangle() + .setX(this.x) + .setY(this.y) + .setWidth(this.width) + .setHeight(this.height); + } +} diff --git a/src/common/proto/core.proto b/src/common/proto/core.proto index b945657..27c3fb5 100644 --- a/src/common/proto/core.proto +++ b/src/common/proto/core.proto @@ -2,12 +2,24 @@ syntax = "proto3"; package ru.m.puzzlez.proto.core; -message PointProto { +message Point { float x = 1; float y = 2; } -message UserProto { +message IntPoint { + int32 x = 1; + int32 y = 2; +} + +message Rectangle { + float x = 1; + float y = 2; + float width = 3; + float height = 4; +} + +message User { string uuid = 1; string name = 2; } diff --git a/src/common/proto/event.proto b/src/common/proto/event.proto index 5a29f86..40d4770 100644 --- a/src/common/proto/event.proto +++ b/src/common/proto/event.proto @@ -5,16 +5,16 @@ import "game.proto"; package ru.m.puzzlez.proto.event; -message GameStartProto { - ru.m.puzzlez.proto.game.GameStateProto state = 1; +message GameStart { + ru.m.puzzlez.proto.game.GameState state = 1; bool resume = 2; } -message GameCompleteProto { +message GameComplete { } -message GameActionProto { +message GameAction { string playerId = 1; int32 partId = 2; enum Action { @@ -23,19 +23,22 @@ message GameActionProto { PUT = 2; } Action action = 3; - ru.m.puzzlez.proto.core.PointProto point = 4; + ru.m.puzzlez.proto.core.Point position = 4; } -message GameChangeProto { +message GameChange { int32 partId = 1; + ru.m.puzzlez.proto.core.Point position = 2; + ru.m.puzzlez.proto.game.PartLocation location = 3; + string playerId = 4; } -message GameEventProto { +message GameEvent { int32 time = 1; oneof event { - GameStartProto start = 10; - GameCompleteProto complete = 11; - GameActionProto action = 12; - GameChangeProto change = 13; + GameStart start = 10; + GameComplete complete = 11; + GameAction action = 12; + GameChange change = 13; } } diff --git a/src/common/proto/game.proto b/src/common/proto/game.proto index 851a2e9..b18bf78 100644 --- a/src/common/proto/game.proto +++ b/src/common/proto/game.proto @@ -4,27 +4,62 @@ import "core.proto"; package ru.m.puzzlez.proto.game; -message PartProto { - +enum BoundType { + NONE = 0; + OUT = 1; + IN = 2; } -message GridProto { - int32 width = 1; - int32 height = 2; +message PartBound { + BoundType spike = 1; + BoundType side = 2; } -message GamePresetProto { +message PartBounds { + PartBound left = 1; + PartBound right = 2; + PartBound top = 3; + PartBound bottom = 4; +} + +enum PartLocation { + TABLE = 0; + HAND = 1; + IMAGE = 2; +} + +message Part { + int32 id = 1; + ru.m.puzzlez.proto.core.IntPoint point = 2; + PartBounds bounds = 3; + ru.m.puzzlez.proto.core.Point position = 4; + PartLocation location = 5; + ru.m.puzzlez.proto.core.Rectangle rect = 6; + string playerId = 7; +} + +message GamePreset { string imageId = 1; - GridProto grid = 2; + ru.m.puzzlez.proto.core.IntPoint grid = 2; + ru.m.puzzlez.proto.core.Rectangle tableRect = 3; + ru.m.puzzlez.proto.core.Rectangle imageRect = 4; } -message GameStateProto { +enum GameStatus { + READY = 0; + STARTED = 1; + COMPLETE = 2; +} + +message GameState { string id = 1; - GamePresetProto preset = 2; - repeated PartProto parts = 3; + GameStatus status = 2; + GamePreset preset = 3; + repeated Part parts = 4; + bool online = 5; } -message GameProto { - GameStateProto state = 2; - repeated ru.m.puzzlez.proto.core.UserProto users = 3; +message GameItem { + GameState state = 2; + repeated ru.m.puzzlez.proto.core.User users = 3; } diff --git a/src/common/proto/pack.proto b/src/common/proto/pack.proto index 4f5b493..9ba4740 100644 --- a/src/common/proto/pack.proto +++ b/src/common/proto/pack.proto @@ -12,11 +12,11 @@ message ErrorResponse { } message LoginRequest { - ru.m.puzzlez.proto.core.UserProto user = 1; + ru.m.puzzlez.proto.core.User user = 1; } message LoginResponse { - ru.m.puzzlez.proto.core.UserProto user = 1; + ru.m.puzzlez.proto.core.User user = 1; } message LogoutRequest {} @@ -34,7 +34,7 @@ message GameJoinRequest { message GameLeaveRequest {} message GameResponse { - ru.m.puzzlez.proto.game.GameProto game = 1; + ru.m.puzzlez.proto.game.GameItem game = 1; } message GameListRequest { @@ -42,15 +42,15 @@ message GameListRequest { } message GameListResponse { - repeated ru.m.puzzlez.proto.game.GameProto games = 1; + repeated ru.m.puzzlez.proto.game.GameItem games = 1; } message GameActionRequest { - repeated ru.m.puzzlez.proto.event.GameActionProto actions = 1; + repeated ru.m.puzzlez.proto.event.GameAction actions = 1; } message GameEventResponse { - repeated ru.m.puzzlez.proto.event.GameEventProto events = 1; + repeated ru.m.puzzlez.proto.event.GameEvent events = 1; } message Request {