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