'update'
[vchess.git] / client / src / views / Game.vue
CommitLineData
a6bddfc6
BA
1<!-- TODO: component Game, + handle players + observers connect/disconnect
2 event = "gameconnect" ...etc
3 connect/disconnect with sid+name (ID not required); name slightly redundant but easier
4ce15fd9
BA
4
5quand on arrive dans la partie, on poll les sids pour savoir qui est en ligne (ping)
6(éventuel échange lastate avec les connectés, pong ...etc)
7ensuite quand qqun se deco il suffit d'écouter "disconnect"
8pareil quand quelqu'un reco.
9(c'est assez rudimentaire et écoute trop de messages, mais dans un premier temps...)
7b626bdd 10 // TODO: [in game] send move + elapsed time (in milliseconds); in case of "lastate" message too
a6bddfc6 11-->
a6088c90
BA
12<template lang="pug">
13.row
14 .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
b6c5641f
BA
15 //BaseGame(:variant="variant.name" @game-over=".....TODO")
16 //localStorage["score"] = score;
a6088c90
BA
17
18
19 .button-group(v-if="mode!='analyze'")
20 button(@click="offerDraw") Draw
21 button(@click="abortGame") Abort
22 button(@click="resign") Resign
23 div(v-if="mode=='corr'")
24 textarea(v-show="score=='*' && vr.turn==mycolor" v-model="corrMsg")
25 div(v-show="cursor>=0") {{ moves[cursor].message }}
26</template>
27
28<script>
29// TODO: if I'm an observer and player(s) disconnect/reconnect, how to find me ?
30// onClick :: ask full game to remote player, and register as an observer in game
31// (use gameId to communicate)
32// on landing on game :: if gameId not found locally, check remotely
33// ==> il manque un param dans game : "remoteId"
34import Board from "@/components/Board.vue";
35//import Chat from "@/components/Chat.vue";
36//import MoveList from "@/components/MoveList.vue";
37import { store } from "@/store";
38
39export default {
40 name: 'my-game',
41 components: {
42 BaseGame,
43 },
44 // gameId: to find the game in storage (assumption: it exists)
45 // mode: "live" or "corr" (correspondance game), or "analyze"
46 // gameRef in URL hash (listen for changes)
47 props: ["gid","mode","variant"],
48 data: function() {
49 return {
50 st: store.state,
51 myname: store.state.user.name, //may be anonymous (thus no name)
52 opponents: {}, //filled later (potentially 2 or 3 opponents)
53 drawOfferSent: false, //did I just ask for draw?
54 people: [], //observers
55 };
56 },
57 watch: {
58 gid: function() {
59 this.launchGame();
60 },
61 },
62 // Modal end of game, and then sub-components
63 created: function() {
64 if (!!this.gid)
65 this.launchGame();
66 // TODO: if I'm one of the players in game, then:
67 // Send ping to server (answer pong if opponent[s] is connected)
68 if (true && !!this.conn && !!this.gameRef)
69 {
70 this.conn.onopen = () => {
71 this.conn.send(JSON.stringify({
72 code:"ping",oppid:this.oppid,gameId:this.gameRef.id}));
73 };
74 }
75 // TODO: also handle "draw accepted" (use opponents array?)
76 // --> must give this info also when sending lastState...
77 // and, if all players agree then OK draw (end game ...etc)
78 const socketMessageListener = msg => {
79 const data = JSON.parse(msg.data);
80 let L = undefined;
81 switch (data.code)
82 {
83 case "newmove": //..he played!
84 this.play(data.move, this.variant.name!="Dark" ? "animate" : null);
85 break;
86 case "pong": //received if we sent a ping (game still alive on our side)
87 if (this.gameRef.id != data.gameId)
88 break; //games IDs don't match: definitely over...
89 this.oppConnected = true;
90 // Send our "last state" informations to opponent(s)
91 L = this.vr.moves.length;
92 Object.keys(this.opponents).forEach(oid => {
93 this.conn.send(JSON.stringify({
94 code: "lastate",
95 oppid: oid,
96 gameId: this.gameRef.id,
97 lastMove: (L>0?this.vr.moves[L-1]:undefined),
98 movesCount: L,
99 }));
100 });
101 break;
102 // TODO: refactor this, because at 3 or 4 players we may have missed 2 or 3 moves (not just one)
103 case "lastate": //got opponent infos about last move
104 L = this.vr.moves.length;
105 if (this.gameRef.id != data.gameId)
106 break; //games IDs don't match: nothing we can do...
107 // OK, opponent still in game (which might be over)
108 if (this.score != "*")
109 {
110 // We finished the game (any result possible)
111 this.conn.send(JSON.stringify({
112 code: "lastate",
113 oppid: data.oppid,
114 gameId: this.gameRef.id,
115 score: this.score,
116 }));
117 }
118 else if (!!data.score) //opponent finished the game
119 this.endGame(data.score);
120 else if (data.movesCount < L)
121 {
122 // We must tell last move to opponent
123 this.conn.send(JSON.stringify({
124 code: "lastate",
125 oppid: this.opponent.id,
126 gameId: this.gameRef.id,
127 lastMove: this.vr.moves[L-1],
128 movesCount: L,
129 }));
130 }
131 else if (data.movesCount > L) //just got last move from him
132 this.play(data.lastMove, "animate");
133 break;
134 case "resign": //..you won!
135 this.endGame(this.mycolor=="w"?"1-0":"0-1");
136 break;
137 // TODO: also use (dis)connect info to count online players?
138 case "gameconnect":
139 case "gamedisconnect":
140 if (this.mode=="human")
141 {
142 const online = (data.code == "connect");
143 // If this is an opponent ?
144 if (!!this.opponents[data.id])
145 this.opponents[data.id].online = online;
146 else
147 {
148 // Or an observer ?
149 if (!online)
150 delete this.people[data.id];
151 else
152 this.people[data.id] = data.name;
153 }
154 }
155 break;
156 }
157 };
158 const socketCloseListener = () => {
159 this.conn.addEventListener('message', socketMessageListener);
160 this.conn.addEventListener('close', socketCloseListener);
161 };
162 if (!!this.conn)
163 {
164 this.conn.onmessage = socketMessageListener;
165 this.conn.onclose = socketCloseListener;
166 }
167 },
168 // dans variant.js (plutôt room.js) conn gère aussi les challenges
169 // et les chats dans chat.js. Puis en webRTC, repenser tout ça.
170 methods: {
171 offerDraw: function() {
172 if (!confirm("Offer draw?"))
173 return;
174 // Stay in "draw offer sent" state until next move is played
175 this.drawOfferSent = true;
176 if (this.subMode == "corr")
177 {
178 // TODO: set drawOffer on in game (how ?)
179 }
180 else //live game
181 {
182 this.opponents.forEach(o => {
183 if (!!o.online)
184 {
185 try {
186 this.conn.send(JSON.stringify({code: "draw", oppid: o.id}));
187 } catch (INVALID_STATE_ERR) {
188 return;
189 }
190 }
191 });
192 }
193 },
194 // + conn handling: "draw" message ==> agree for draw (if we have "drawOffered" at true)
195 receiveDrawOffer: function() {
196 //if (...)
197 // TODO: ignore if preventDrawOffer is set; otherwise show modal box with option "prevent future offers"
198 // if accept: send message "draw"
199 },
200 abortGame: function() {
201 if (!confirm("Abort the game?"))
202 return;
203 //+ bouton "abort" avec score == "?" + demander confirmation pour toutes ces actions,
204 //send message: "gameOver" avec score "?"
205 },
206 resign: function(e) {
207 if (!confirm("Resign the game?"))
208 return;
209 if (this.mode == "human" && this.oppConnected(this.oppid))
210 {
211 try {
212 this.conn.send(JSON.stringify({code: "resign", oppid: this.oppid}));
213 } catch (INVALID_STATE_ERR) {
214 return;
215 }
216 }
217 this.endGame(this.mycolor=="w"?"0-1":"1-0");
218 },
219 launchGame: async function() {
220 const vModule = await import("@/variants/" + this.variant.name + ".js");
221 window.V = vModule.VariantRules;
222 this.loadGame(this.gid);
223 },
224 loadGame: function(gid) {
225 // TODO: ask game to remote peer if this.remoteId is set
226 // (or just if game not found locally)
227 // NOTE: if it's a corr game, ask it from server
228 const game = getGameFromStorage(gid); //, this.gameRef.uid); //uid may be blank
229 this.opponent.id = game.oppid; //opponent ID in case of running HH game
230 this.opponent.name = game.oppname; //maye be blank (if anonymous)
231 this.score = game.score;
232 this.mycolor = game.mycolor;
233 this.fenStart = game.fenStart;
234 this.moves = game.moves;
235 this.cursor = game.moves.length-1;
236 this.lastMove = (game.moves.length > 0 ? game.moves[this.cursor] : null);
237 },
238 oppConnected: function(uid) {
239 return this.opponents.any(o => o.id == uidi && o.online);
240 },
241 },
242};
243</script>