[common] use proto types

This commit is contained in:
2020-05-28 20:42:41 +03:00
parent b7b1ac3871
commit fec7680eee
36 changed files with 514 additions and 377 deletions

View File

@@ -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<D> extends Converter<D, String> {
}
}
class ProtoConverter<D:protohx.Message> extends Converter<D, String> {
public function new(messageClass:Class<D>) {
super(
item -> PacketUtil.toBytes(item).toHex(),
data -> PacketUtil.fromBytes(Bytes.ofHex(data), messageClass)
);
}
}
class EmptyConverter<T> extends Converter<T, T> {
public function new() {
super(item -> item, data -> data);

View File

@@ -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<ImageId> {
public var user(default, null):UserProto;
public var userSignal(default, null):Signal<UserProto> = new Signal();
public var user(default, null):User;
public var userSignal(default, null):Signal<User> = new Signal();
public var gameList(default, null):Array<GameProto>;
public var gameListSignal(default, null):Signal<Array<GameProto>> = new Signal();
public var gameList(default, null):Array<GameItem>;
public var gameListSignal(default, null):Signal<Array<GameItem>> = new Signal();
public var game(default, null):GameProto;
public var gameSignal(default, null):Signal<GameProto> = new Signal();
public var game(default, null):GameItem;
public var gameSignal(default, null):Signal<GameItem> = new Signal();
public var gameEventSignal(default, null):Signal<GameEvent> = 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 {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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<Dynamic> {
public var actions(default, null):Signal<GameAction>;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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<Int, PartView>;
private var activePart:PartView;
private var activePoint:Point;
private var activePoint:PointExt;
private var movePoint:FlashPoint;
@@ -79,26 +81,22 @@ 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];
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 COMPLETE:
AlertView.alert("Complete!");
case _:
}
} else if (event.hasComplete()) {
AlertView.alert("Complete!");
}
}
private function onStart(state:GameState):Void {
@@ -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;

View File

@@ -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<DrawSetting> = [
{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<DrawSetting> = [
{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);
}
}

View File

@@ -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);

View File

@@ -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 _:
}
}
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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<ImageId, GameState> {
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<GameState>(item -> ["id" => item.preset.imageId, "status" => item.status, "date" => Date.now().toString()]),
new Converter<ImageId, String>(id -> id.toString(), data -> ImageId.fromString(data))
new MetaBuilder<GameState>(item -> [
"id" => item.preset.imageId,
"status" => Std.string(item.status),
"date" => Date.now().toString()
]),
new Converter<ImageId, String>(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)],
}
}
}

View File

@@ -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(_, _)):
if (event.hasStart() || event.hasAction()) {
toSave();
case _:
}
}
@@ -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));

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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<Dynamic> {

View File

@@ -1,7 +0,0 @@
package ru.m.puzzlez.core;
enum BoundType {
NONE;
OUT;
IN;
}

View File

@@ -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)
);
}
}

View File

@@ -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];
if (event.hasAction()) {
var part:Part = partsById[event.action.partId];
switch event.action.action {
case Action.TAKE:
switch part.location {
case TABLE(point):
part.location = HAND(playerId, point);
events.emit(CHANGE(PART_UPDATE(partId, part.location)));
case PartLocation.TABLE:
part.location = PartLocation.HAND;
part.playerId = event.action.playerId;
events.emit(EventUtil.change(part));
case _:
}
case ACTION(PART_MOVE(playerId, partId, point)):
var part = partsById[partId];
case Action.MOVE:
switch part.location {
case HAND(currentPlayerId, _) if (currentPlayerId == playerId):
part.location = HAND(playerId, point);
events.emit(CHANGE(PART_UPDATE(partId, part.location)));
case PartLocation.HAND if (event.action.playerId == part.playerId):
part.position = event.action.position;
events.emit(EventUtil.change(part));
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);
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 = IMAGE;
events.emit(CHANGE(PART_UPDATE(partId, part.location)));
part.location = PartLocation.IMAGE;
events.emit(EventUtil.change(part));
if (checkIsComplete()) {
state.status = COMPLETE;
events.emit(COMPLETE);
state.status = GameStatus.COMPLETE;
events.emit(EventUtil.complete());
}
} else {
part.location = TABLE(point);
events.emit(CHANGE(PART_UPDATE(partId, part.location)));
part.location = PartLocation.TABLE;
part.position = event.action.position;
events.emit(EventUtil.change(part));
}
}
case _:
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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<Part>;
@:optional var online:Bool;
}

View File

@@ -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<PartBound>;
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<Part> = [];
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 _:
}
}

View File

@@ -1,6 +0,0 @@
package ru.m.puzzlez.core;
typedef Grid = {
var width:Int;
var height:Int;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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 {