Private
Public Access
1
0

create first working communication

This commit is contained in:
2016-10-25 11:19:50 +02:00
parent 23f034bc1c
commit 5b4fdd088c
27 changed files with 1037 additions and 2546 deletions

View File

@@ -1,8 +1,11 @@
# Topic Configuration
acme_topic:
channel: acme/channel
channel: acme/channel/{game}
handler:
callback: 'acme.topic' #related to the getName() of your topic
# requirements:
# method:
# path: '[a-z1-9A-Z]+'
# Remote Procedure Call Configuration
acme_rpc:

View File

@@ -1,3 +1,16 @@
MineSeekerBundle_homepage:
path: /
defaults: { _controller: MineSeekerBundle:Game:index }
MineSeekerBundle_gamePlay:
path: /play
defaults: { _controller: MineSeekerBundle:Game:play }
MineSeekerBundle_gamePlayWId:
path: /play/{gameAssoc}
defaults: { _controller: MineSeekerBundle:Game:play }
MineSeekerBundle_gameList:
path: /list
defaults: { _controller: MineSeekerBundle:Game:list }

View File

@@ -32,11 +32,14 @@ services:
- { name: gos_web_socket.topic }
arguments:
clientManipulator: "@gos_web_socket.websocket.client_manipulator"
doctrine: '@doctrine.orm.entity_manager'
acme_hello.rpc_sample_service:
class: Mine\SeekerBundle\Rpc\AcmeRpc
tags:
- { name: gos_web_socket.rpc }
arguments:
doctrine: '@doctrine.orm.entity_manager'
gos_web_socket_server.client_event.listener:
class: Mine\SeekerBundle\EventListener\AcmeClientEventListener

View File

@@ -3,6 +3,7 @@ import ReactDOM from 'react-dom';
import MineSeeker from './mine-seeker/app';
ReactDOM.render(
<MineSeeker />,
<MineSeeker env={document.getElementById('mine-wrapper').dataset.env}
gameId={document.getElementById('mine-wrapper').dataset.gameId}/>,
document.getElementById('mine-wrapper')
);

View File

@@ -1,55 +1,157 @@
import React from 'react';
import Grid from './grid/grid';
import GridControl from './grid/grid-control';
import Logging from './system/logging';
class MineSeeker extends React.Component {
constructor(props) {
super(props);
var gameAssoc = props.gameId !== '' ? props.gameId : this.makeGameAssoc(50);
var channel = "acme/channel/" + gameAssoc;
var log = new Logging();
log.state.logging = props.env === 'dev';
var grid = new Grid();
this.state = {
gameInherited: props.gameId !== '',
gameAssoc: gameAssoc,
log: log,
websocket: null,
channel: channel,
createGrid: false,
grid: grid.state.grid
}
}
makeGameAssoc(len) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < len; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
topicProcess(payload, grid) {
var log = this.state.log;
/** It is a PUBLISH */
if (typeof payload.data !== 'undefined') {
log.i([payload.user + " has been stepped to coords: " + payload.data.coords[0] + ', ' + payload.data.coords[0], payload]);
/** because the activePlayer has been changed before the data come */
if (this.refs.gridControl.state.webPlayer !== payload.data.player) {
this.refs.gridControl.stepEvent(payload.data.coords, true);
}
} else {
/** It is a SUBSCRIBE */
log.i(["Something happened on the channel!", payload]);
if (this.refs.gridControl.state.webPlayer === null) {
if (payload.userCnt === 1) {
this.refs.gridControl.state.webPlayer = 'red';
}
if (payload.userCnt === 2) {
this.refs.gridControl.state.webPlayer = 'blue';
this.refs.gridControl.state.grid = JSON.parse(grid);
}
}
}
}
/** after rendering */
componentDidMount() {
var websocket = WS.connect("ws://mine.dev:6450");
this.state.websocket = WS.connect("ws://mine.dev:6450");
/** session is an Autobahn JS WAMP session. */
websocket.on("socket/connect", function (session) {
console.info("Successfully Connected!");
var log = this.state.log;
session.subscribe("acme/channel", function(uri, payload){
console.log("Received message", payload.msg);
});
/**
* Connect
* Session is an Autobahn JS WAMP session.
*/
this.state.websocket.on("socket/connect", (session) => {
log.i("Successfully connected to the Server!");
session.call("sample/sum", [2, 5]).then(
function (result) {
console.log("RPC Valid!", result);
},
function (error, desc) {
console.log("RPC Error", error, desc);
}
);
/**
* Connect
* Send grid information to the server
*/
session
.call(
this.state.gameInherited ? "sample/connectGame" : "sample/startGame",
[this.state.grid, this.state.gameAssoc]
)
.then(
(grid) => {
log.l(["Grid has been created! Return w/ gameAssoc."]);
session.publish("acme/channel", {msg: "This is a message!"});
/** Connect */
session.subscribe(
this.state.channel,
(uri, payload, log) => {
// session.publish("acme/channel", {msg: "I'm leaving, I will not see the next message"});
//
// session.unsubscribe("acme/channel");
//
// session.publish("acme/channel", {msg: "I won't see this"});
//
// session.subscribe("acme/channel", function (uri, payload) {
// console.log("Received message", payload.msg);
// });
//
// session.publish("acme/channel", {msg: "I'm back!"});
/** Create GridControl class */
if (this.state.createGrid) {
this.topicProcess(payload, grid);
} else {
this.setState({createGrid: true}, () => {
/** Start GridControl tag */
this.refs.gridControl.setState({grid: this.state.grid}, () => {
this.refs.gridControl.state.session = session;
this.refs.gridControl.state.channel = this.state.channel;
this.topicProcess(payload, grid);
});
});
}
}
);
},
(error, desc) => log.e(["RPC Error", error, desc])
);
});
/** error provides us with some insight into the disconnection: error.reason and error.code */
websocket.on("socket/disconnect", function (error) {
console.info("Disconnected for " + error.reason + " with code " + error.code);
/**
* Connect
* Error provides us with some insight into the disconnection: error.reason and error.code
*/
this.state.websocket.on("socket/disconnect", function (error) {
log.w("Disconnected for " + error.reason + " with code " + error.code);
});
}
createGrid() {
return this.state.createGrid
? <GridControl ref="gridControl"
env={this.props.env === 'dev'}
log={this.state.log}/>
: '';
}
/** FOR DEVELOPMENT */
createLink() {
return this.state.gameAssoc
? <a href={"/play/" + this.state.gameAssoc} target="_blank">Play w/ me!</a>
: '';
}
render() {
return (
<div></div>
// <GridControl ref="gridControl"/>
<div>
<div>
{this.createLink()}
</div>
{this.createGrid()}
{/*<GridControl ref="gridControl"*/}
{/*env={this.props.env === 'dev'}*/}
{/*log={this.state.log}/>*/}
</div>
);
}
}
export default MineSeeker;

View File

@@ -1,21 +1,24 @@
import React from 'react';
import Sound from 'react-sound';
import Grid from './grid';
import GridField from './grid-field';
import UserControl from '../user/user-control';
class GridControl extends React.Component {
constructor() {
super();
var grid = new Grid();
constructor(props) {
super(props);
this.state = {
grid: grid.state.grid,
env: props.env,
log: props.log,
session: null,
channel: null,
webPlayer: null,
grid: null,
updatedFieldCache: [],
bombFieldCache: [],
foundUserMineCache: 0,
playBomb: false,
sound: null,
lastClicked: {
red: null,
blue: null
@@ -191,6 +194,8 @@ class GridControl extends React.Component {
this.state.foundUserMineCache++;
if (!justOnFirstIteration) {
this.playingSound('mine');
/** set last clicked field w/ color */
this.state.lastClicked[activePlayer] = [x, y];
}
@@ -201,7 +206,9 @@ class GridControl extends React.Component {
});
} else {
if (!justOnFirstIteration) {
/** set ACTIVE player */
this.playingSound('click');
/** set __ACTIVE__ player in the UserControl !!!! */
userControl.setState({
activePlayer: userControl.state.activePlayer ? 0 : 1
});
@@ -245,19 +252,20 @@ class GridControl extends React.Component {
}
}
/**
* Most important event!!
* @param coords
*/
onClick(coords) {
stepEvent(coords, isOpponentStepped) {
var activePlayer = this.refs.userControl.state.activePlayer ? 'blue' : 'red';
this.state.foundUserMineCache = 0;
this.state.foundUserMineCache = 0;
this.state.playBomb = true;
console.log(
this.state.playBomb
);
/** Step automatically when not this user stepped */
if (!isOpponentStepped) {
this.state.session
.publish(this.state.channel, {
'coords': coords,
'player': activePlayer
});
}
if (this.refs.userControl.state.bombSelected) {
var radius = this.getBombRadius(coords[0], coords[1]);
@@ -296,7 +304,7 @@ class GridControl extends React.Component {
}
if (this.state.foundUserMineCache) {
/** remove ONE mine from global */
/** remove the found mines from global */
this.refs.userControl.setState({
mines: this.refs.userControl.state.mines - this.state.foundUserMineCache,
foundMines: true
@@ -306,7 +314,7 @@ class GridControl extends React.Component {
this.refs.userControl.setState({foundMines: false})
}.bind(this), 500);
/** add ONE mine to active Player */
/** add the found mines to the active Player */
this.refs.userControl.refs[activePlayer].setState({
mines: this.refs.userControl.refs[activePlayer].state.mines + this.state.foundUserMineCache
});
@@ -321,6 +329,19 @@ class GridControl extends React.Component {
}
}
/**
* Most important event!!
* Click only when the active player is the current client.
* @param coords
*/
onClick(coords) {
var activePlayer = this.refs.userControl.state.activePlayer ? 'blue' : 'red';
if (activePlayer === this.state.webPlayer) {
this.stepEvent(coords, false);
}
}
/**
* On Hover when you want to drop BOMB
* @param coords
@@ -335,34 +356,50 @@ class GridControl extends React.Component {
}
}
playingBomb() {
return this.state.playBomb
? Sound.status.PLAYING
: Sound.status.STOPPED;
/**
* Play sound effets
* @param type
* @returns {*}
*/
playingSound(type) {
this.state.log.i('Sound playing type: ' + type);
return type !== null
? <Sound url={"sound/" + type + ".mp3"} playStatus={Sound.status.PLAYING}/>
: '';
}
/** after rendering */
componentDidMount() {
soundManager.setup({debugMode: false});
/** disable console of soundmanager */
soundManager.setup({
debugMode: this.state.env,
useConsole: this.state.env
});
}
renderGridFields() {
var grid = [];
/** If the app.js filled the this.state.grid var, START the grid render */
if (this.state.grid) {
var grid = [];
for (var i = 0, j = this.state.grid.length; i < j; i++) {
for (var k = 0, l = this.state.grid[i].length; k < l; k++) {
grid.push(
<GridField row={i}
col={k}
ref={this.refString(i, k)}
key={i + k * Math.random() * 0.5}
handleHoverOn={this.onHoverWithBomb.bind(this, [i, k])}
onClick={this.onClick.bind(this, [i, k])}
/>
);
for (var i = 0, j = this.state.grid.length; i < j; i++) {
for (var k = 0, l = this.state.grid[i].length; k < l; k++) {
grid.push(
<GridField row={i}
col={k}
ref={this.refString(i, k)}
key={i + k * Math.random() * 0.5}
handleHoverOn={this.onHoverWithBomb.bind(this, [i, k])}
onClick={this.onClick.bind(this, [i, k])}/>
);
}
}
return grid;
}
return grid;
return "";
}
render() {
@@ -375,11 +412,7 @@ class GridControl extends React.Component {
<div className="grid">
{this.renderGridFields()}
</div>
<Sound url="sound/bomb.mp3" ref="bombSound" playStatus={this.playingBomb()}/>
{/*<Sound url="sound/click.mp3" playStatus={this.playStatus()}/>*/}
{/*<Sound url="sound/mine.mp3" playStatus={this.playStatus()}/>*/}
{/*<Sound url="sound/warning.mp3" playStatus={this.playStatus()}/>*/}
{/*<Sound url="sound/won.mp3" playStatus={this.playStatus()}/>*/}
{this.playingSound(this.state.sound)}
</div>
);
}

View File

@@ -12,7 +12,7 @@ class GridField extends React.Component {
lastClickedBlue: false,
bombTargetArea: null,
icons: {
root: 'bundles/mineseeker/images/',
root: '/bundles/mineseeker/images/',
water: {
1: 'bg-wave-1-outbg.png',
2: 'bg-wave-1-outbg.png',
@@ -35,6 +35,8 @@ class GridField extends React.Component {
componentWillMount() {
var wave = Math.floor(Math.random() * 3) + 1;
console.log('mounted');
this.setState({
currentImage: this.state.icons.root + this.state.icons.water[wave]
});

View File

@@ -0,0 +1,41 @@
class Logging {
constructor() {
this.state = {
logging: null
};
}
output(data, method) {
if (this.state.logging) {
if (typeof data === 'object') {
console.log('-------');
data.forEach((item) => console[method](item));
console.log('\n');
} else {
console[method](data);
}
}
}
i(data) {
this.output(data, 'info');
}
w(data) {
this.output(data, 'warn');
}
t(data) {
this.output(data, 'table');
}
e(data) {
this.output(data, 'error');
}
l(data) {
this.output(data, 'log');
}
}
export default Logging;

View File

@@ -9,6 +9,7 @@ class User extends React.Component {
active: props.active,
color: props.color === 'blue' ? 1 : 0,
mines: 0,
srcRoot: '/bundles/mineseeker/images/',
haveBomb: true,
enabledBomb: true
};
@@ -19,27 +20,27 @@ class User extends React.Component {
}
getSrc(color) {
return 'bundles/mineseeker/images/bg-flag-' + color + '-outbg.png';
return this.state.srcRoot + 'bg-flag-' + color + '-outbg.png';
}
getBomb() {
if (this.state.haveBomb) {
if (this.state.enabledBomb && this.state.active) {
return 'bundles/mineseeker/images/bg-bomb-outbg.png';
return this.state.srcRoot + 'bg-bomb-outbg.png';
} else {
return 'bundles/mineseeker/images/bg-bomb-disabled-outbg.png';
return this.state.srcRoot + 'bg-bomb-disabled-outbg.png';
}
} else {
return 'bundles/mineseeker/images/bg-bomb-exploded-outbg.png';
return this.state.srcRoot + 'bg-bomb-exploded-outbg.png';
}
}
getFigure(color) {
return 'bundles/mineseeker/images/bg-figure-' + color + '-outbg.png';
return this.state.srcRoot + 'bg-figure-' + color + '-outbg.png';
}
getCursor(state, color) {
var cursorImg = 'bundles/mineseeker/images/bg-cursor-' + color + '-outbg.png';
var cursorImg = this.state.srcRoot + 'bg-cursor-' + color + '-outbg.png';
return state
? <img src={cursorImg} alt="cursor" className="user-cursor"/>

View File

@@ -0,0 +1 @@
Bazmeg index.

View File

@@ -8,7 +8,10 @@
{% endblock %}
{% block body %}
<div id="mine-wrapper"></div>
<div id="mine-wrapper"
data-env="{{ env }}"
data-game-id="{{ app.request.get('gameAssoc') }}">
</div>
{% endblock %}
{% block javascripts %}