chiark / gitweb /
dupe nick handling
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 23 Aug 2020 20:02:48 +0000 (21:02 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 23 Aug 2020 20:02:48 +0000 (21:02 +0100)
src/bin/otter.rs
src/global.rs

index 45a91697e210d46331929cd1a22c7c61119b744e..7fa66944e578827d1ef4ee6150e9690fe1c3dddd 100644 (file)
@@ -288,7 +288,8 @@ fn connect(ma: &MainOpts) -> Conn {
   chan
 }
 
-fn setup_table(chan: &mut ConnForGame, spec: &TableSpec) -> Result<(),AE> {
+fn setup_table(ma: &MainOpts, chan: &mut ConnForGame,
+               spec: &TableSpec) -> Result<(),AE> {
   // xxx should delete old players
 
   // create missing players
@@ -306,6 +307,9 @@ fn setup_table(chan: &mut ConnForGame, spec: &TableSpec) -> Result<(),AE> {
     let mut insns = vec![];
     for pspec in &spec.players {
       let st = nick2st.entry(pspec.nick.clone()).or_default();
+      if st.new {
+        Err(anyhow!("duplicate player nick {:?} in spec", &pspec.nick))?;
+      }
       st.new = true;
       if !st.old {
         insns.push(MgmtGameInstruction::AddPlayer(PlayerState {
@@ -313,14 +317,24 @@ fn setup_table(chan: &mut ConnForGame, spec: &TableSpec) -> Result<(),AE> {
         }));
       }
     }
+
+    for (nick, st) in nick2st {
+      if st.new { continue }
+      if !st.old { continue }
+      if ma.verbose >= 1 {
+        eprintln!("removing old player {:?}", &nick);
+      }
+      insns.push(Insn::RemovePlayer(st.id));
+    }
+
     let mut added_players = HashSet::new();
     chan.alter_game(insns, Some(&mut |response| {
-      let player = match response {
-        &Resp::AddPlayer(player) => player,
-        _ => Err(anyhow!("AddPlayer strange answer {:?}",
-                         &response))?,
+      match response {
+        &Resp::AddPlayer(player) => {
+          added_players.insert(player);
+        },
+        _ => { },
       };
-      added_players.insert(player);
       Ok(())
     }))?;
 
@@ -426,7 +440,7 @@ mod create_table {
       how: MgmtGameUpdateMode::Bulk,
     };
 
-    setup_table(&mut chan, &spec)?;
+    setup_table(&ma, &mut chan, &spec)?;
 
     if ma.verbose >= 0 {
       eprintln!("create-table successful.  game still needs setup.");
@@ -486,7 +500,7 @@ mod reset_game {
         Err(e)
       })?;
 
-      setup_table(&mut chan, &table_spec)?;
+      setup_table(&ma, &mut chan, &table_spec)?;
     }
 
     let mut insns = vec![];
index 6ed1ac586da1e9133088813d3037e02103410ef2..fc6867fb4ca999f44b6c8d3eac0b78635cfe6e1b 100644 (file)
@@ -306,11 +306,14 @@ impl DerefMut for InstanceGuard<'_> {
 impl InstanceGuard<'_> {
   /// caller is responsible for logging; threading it through
   /// proves the caller has a log entry.
-  #[throws(ServerFailure)]
+  #[throws(MgmtError)]
   pub fn player_new(&mut self, newplayer: PlayerState,
                     logentry: LogEntry) -> (PlayerId, LogEntry) {
     // saving is fallible, but we can't attempt to save unless
     // we have a thing to serialise with the player in it
+    if self.c.g.gs.players.values().any(|pl| pl.nick == newplayer.nick) {
+      Err(MgmtError::AlreadyExists)?;
+    }
     let player = self.c.g.gs.players.insert(newplayer);
     self.save_game_now().map_err(|e|{
       self.c.g.gs.players.remove(player);