Previously, only loadGruntworkPost() would be skipped if the gruntwork
was null, but it was never null at that point because loadGruntworkPre()
would inadvertently create gruntwork["paths"] when it indexes it to
iterate through it.
Now, the gruntwork loading messages will no longer be misleadingly
printed to stdout when there isn't a gruntwork file.
UBSAN complains about the casting approach because it loads a 64-bit
integer from the defaultKeys string which isn't guaranteed to be 64-bit
aligned, which is undefined behavior.
CNSocket::kill() will now no longer call close() on already closed sockets.
close() should never be called on already closed file descriptors, yet
CNSocket::kill() was lacking any protection against that, despite its
use as both a high-level way of killing player connections and as a
means of ensuring that closing connections have been properly terminated
in the poll() loop.
This was causing close() to be erroneously called on each socket at least
one extra time. It was also introducing a race condition where the login
and shard threads could close each other's newly opened sockets due to
file descriptor reuse when a connection was accept()ed after the first
call to close(), but before the second one. See the close(2) manpage for
details.
Previously, terminating a running server from the terminal would
sometimes print a benign warning message if the server was currently
handling an incoming packet. This happened because CNServer::step()
would continue handling the packet after CNServer::kill() released the
activeCrit mutex. Now it first re-checks if active has been set to false
in the mean time after acquiring the mutex.
Revisiting this again; the issue was that the comparison operator was
facing the wrong way, so connections were being pruned every 30 seconds
or less. This was effectively a race condition kicking an unlucky player
every so often when pruning happened exactly during an attempt to enter
the game.
Now that the proper timeout is being enforced, I've reduced it to 5
minutes, down from 15, since it really doesn't need to be that long.
This should fix issues with segfaults when the server is being
terminated that sometimes occur because things like NPC path traversal
keep running while the process is executing the signal handler.
* Separate pruning frequency from timeout
* Pluralize CNShared map: login -> logins
* Increase connection timeout to 15 minutes
* Do not deallocate a nullptr in playerEnter()
* Kill connections rejected by playerEnter()
* Remove redundant inclusions of mutex headers in a few places
* Use a specialized connection object
* Copy the Player object less frequently
* Use a randomly generated serial key for shard auth
* Refuse invalid shard connection attempts
* Clean up connection metadata when a Player joins the shard
* Prune abandoned connections when they time out
This prevents logic errors related to being in chunk 0 0 0.
Also:
* Moved some duplicated chunk teleportation logic to a new helper
function
* Made ChunkPos into a proper class so it can default to INVALID_CHUNK
when default-initialized
* Reversed the inclusion order of Chunking.hpp and Entities.hpp to work
around problems with type definitions
The client will actually do this itself when clicking the quit button in the tilde menu, but for the idle timer the connection would remain open until the game is closed.
* Download and list artifacts after build
* Add commit hash + file extension to artifact name
* Initial SSH implementation
* Don't build artifacts for PRs
* Fetch endpoint from secret
* Zip artifacts before uploading to CDN
* Use short SHA in archive names
In our original implementation, quest item drops were rolled on the
spot, so the chances of getting two quest items for different missions
in a single kill (where both missions have you kill the same mob) were
independent of each other.
When we made quest item drop chances shared between group members so
players doing missions together would progress at the same rate, we
accidentally linked the quest item odds of different missions together.
This change makes it so that the odds are per-task, so they're shared
between different group members doing the same tasks, but distinct for
different tasks being done by the same player.
* Removed a redundant failure case in endTask()
* Fixed a misleading comment in startTask()
* Removed a redundant level check in updateFusionMatter()
* Cleared up misleading comment and code layout in taskEnd()
* Removed unnecessary comment in mobKilled()