Up to Main Index                          Up to Journal for February, 2022

                   JOURNAL FOR SATURDAY 5TH FEBRUARY, 2022
______________________________________________________________________________

SUBJECT: A minor setback, moving on to plan C
   DATE: Sat  5 Feb 20:31:07 GMT 2022

Still working on health and HIT for player combat. My initial plan A didn’t
work out. It was getting overly complex with far to many corner cases failing.
So I deleted all the ugly…

I then tried something I really didn’t want to do. I implemented a plan B with
the health regeneration using the event scheduling system. The implementation
was much simpler. However, what would happen if I ran 64,000 bots and had
64,000 additional events registered? Turns out CPU usage goes up a little and
some additional memory is allocated.

Problem solved right? No :( While testing I managed to trigger a nil panic.
This was due to the player being freed on the networking/client side of things
due to a network error (I hit Ctrl-c to abort the botrunner) and the health
regeneration trigger game-side side trying to access now nil maps in the freed
player. It took a good few hours of debugging to realise why the server had
panicked.

I tried to fix the issue by checking if the player had been freed already.
Luckily I test a lot with the race detector as this started causing a data
race. What? Why? The code was locking and everything looked fine:


  func (s *state) Parse(input string) (cmd string) {
    if input = strings.TrimSpace(input); len(input) != 0 {
      BWL.Lock()
      defer BWL.Unlock()

      if s.actor.Is&Freed == Freed {
        return ""
      }

      s.parse(input)
      s.mailman()
    }
    return s.cmd
  }


The “if s.actor.Is&Freed == Freed {” was racing with the “s.parse(input)” ??

Turns out I can’t use the event scheduler for player events without triggering
a data race. I’m not sure of the exact cause but suspect it’s because normally
the networking code always uses the same state, which it creates and controls
outside of the lock and all calls are made on that goroutine. When introducing
the event a new state is created when the event fires and the calls are made
on a different goroutine. Accessing the actor in two different states on two
different goroutines then causes the data race, even though the lock has been
taken by each gorotine in turn. For the above code the race happens with the
read for “s.actor.Is&Freed” in one state and a write by “s.parse(input)” in
another state affect the same actor.

This took a lot more debugging to unravel what was going on there.

I now have to throw away plan B and come up with a plan C — I already have
more ideas to try. In the meantime I’ve reverted all my changes. I’ve also had
a script running that loops through running the botrunner for a while, then
unceremoniously kills it, waits a bit then starts over — just in case the data
race wasn’t introduced by these changes…

--
Diddymus


  Up to Main Index                          Up to Journal for February, 2022