Add handling for a spectators list in addition to the players list
authorCarl Worth <cworth@cworth.org>
Sun, 24 May 2020 15:27:09 +0000 (08:27 -0700)
committerCarl Worth <cworth@cworth.org>
Sun, 24 May 2020 15:27:09 +0000 (08:27 -0700)
The model is that when people initially join the game, (providing a
name for themselves), they are a spectator. They then move from the
spectator list to the player list when then they choose a character
name.

The server isn't very clever about this. It has distinct endpoints for
adding/removing players and adding/removing spectators. So in this
code we have to explicitly remove ourselves as a spectator when we add
ourselves as a player.

empires/game.css
empires/game.js

index 1bb0e62eb0eada366c08f28a523def5ed75ee10d..57cd206e989ce20c41288a1d6bb4d1c99b284e6a 100644 (file)
     display:block;
 }
 
-/* Players list starts out hidden (until a player is added). */
+/* Spectators and players lists start out hidden (until people are added). */
+#spectators-div {
+    display:none;
+}
+
 #players-div {
     display:none;
 }
index 3f45e7de730bbd8c35037a25cef5a4f7e802ebb2..8043d32dc281799adf2734c3ce1306bd50168617 100644 (file)
@@ -34,6 +34,12 @@ function GAME_API(endpoint) {
   return path;
 }
 
+var state = {
+  spectator_id: undefined,
+  spectators: [],
+  players: []
+};
+
 function undisplay(element) {
   element.style.display="none";
 }
@@ -48,14 +54,20 @@ ${message}
 }
 
 function register(form) {
-  var request = new XMLHttpRequest();
+  const spectator_req = new XMLHttpRequest();
+
+  /* Before registering as a player, first remove us as a spectator. */
+  spectator_req.open("DELETE", GAME_API("spectator/") + state.spectator_id);
+  spectator_req.send();
+
+  const register_req = new XMLHttpRequest();
 
-  request.open("POST", GAME_API("register"));
-  request.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
+  register_req.open("POST", GAME_API("register"));
+  register_req.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
   var data = {
     "character": form.character.value
   };
-  request.send(JSON.stringify(data));
+  register_req.send(JSON.stringify(data));
 
   form.reset();
 }
@@ -100,6 +112,45 @@ events.onerror = function(event) {
   }
 };
 
+events.addEventListener("spectators", function(event) {
+  const spectators_div = document.getElementById("spectators-div");
+  const spectators_element = document.getElementById("spectators");
+  const spectators = JSON.parse(event.data);
+
+  spectators_element.innerHTML = '';
+  for (const spectator of spectators) {
+    var li = document.createElement('li');
+    li.id = "spectator-" + spectator.id;
+    li.innerText = spectator.name;
+    spectators_element.appendChild(li);
+  }
+
+  /* Force players list to be visible. */
+  spectators_div.style.display = "block";
+});
+
+events.addEventListener("spectator-join", function(event) {
+  const spectators_div = document.getElementById("spectators-div");
+  const spectators = document.getElementById("spectators");
+  const spectator = JSON.parse(event.data);
+
+  const li = document.createElement('li');
+  li.id = "spectator-" + spectator.id;
+  li.innerText = spectator.name;
+  spectators.appendChild(li);
+
+  /* Force spectators list to be visible. */
+  spectators_div.style.display = "block";
+});
+
+events.addEventListener("spectator-leave", function(event) {
+  const spectators = document.getElementById("spectators");
+  const id = JSON.parse(event.data);
+  const spectator = document.getElementById("spectator-" + id.id);
+
+  spectators.removeChild(spectator);
+});
+
 events.addEventListener("players", function(event) {
   const players_div = document.getElementById("players-div");
   const players_element = document.getElementById("players");
@@ -140,6 +191,10 @@ events.addEventListener("player-leave", function(event) {
   players.removeChild(player);
 });
 
+function spectator_on_load() {
+  state.spectator_id = JSON.parse(this.response);
+}
+
 events.addEventListener("game-state", function(event) {
   const data = JSON.parse(event.data);
   const old_state = data.old_state;
@@ -159,6 +214,15 @@ events.addEventListener("game-state", function(event) {
   for (const elt of elts) {
     elt.style.display = "block";
   }
+
+  /* Whenever the game enters the "join" state, add ourselves as a spectator. */
+  if (new_state === "join") {
+    const request = new XMLHttpRequest();
+
+    request.addEventListener("load", spectator_on_load);
+    request.open("POST", GAME_API("spectator"));
+    request.send();
+  }
 });
 
 events.addEventListener("character-reveal", function(event) {