Skip to content

Conversation

@ZombieFreak115
Copy link
Contributor

@ZombieFreak115 ZombieFreak115 commented Jan 13, 2026

  • Import concurrentqueue.h from https://github.com/cameron314/concurrentqueue to be used as MPMC queue where needed.

  • Changes console_log to instead push to a concurrentqueue which is then procsessed by a seperate thread. This thread is initialized in the sys::state constructor, and closed in the destructor

  • Add SPSC queue for queueing up functions on the UI thread from the update thread. Eg changing cursors does not work properly unless executed on the same thread. Did a similar thing to for error windows being queued from the update thread

  • Made it so that only a special "normal_cancel_busy" cursor type can cancel the "busy" cursor, so that it isnt accidentually canceled by the player dragging their mouse or clicking.

  • Fixed a crash bug due to the cache-thread reading from uninitialized memory while the gamestate was reloading. It is fixed by using a shared_mutex, and having the readers (UI-thread, cache-thread) acquire a shared_lock, while the gamestate reset code acquires a unique_lock

  • Change loading a save to run as a command issued by the UI. This makes some other things easier, and also has the benefit of not freezing the UI in the process. It also means the command_lock can be removed fully as this was its only use

  • Add graceful client disconnects. Ie. the client will only be fully disconnected once all the pending data in the buffer has been flushed. This allows for the kicked/banned/disconnected client to know that they have been disconnected

  • Change server outgoing command queue and client outgoing command queue to be a concurrentqueue instead of SPSCqueue, as sometimes it is needed to queue commands directly from the update thread too, not just UI thread

  • Move the network client to dcon, with the exception of dynamic send/receive buffers. Those are a problem since the allocated memory will be freed on gamestate reload, but not recovered afterwards.

  • Change server -> client send buffers to be a queue of shared_ptr<command_data> intead of raw bytes. Increasing the amount of send() calls did not affect network performance much, and it significantly reduces the copying of large commands (eg save game data)

  • On the other hand, repeat recv() calls were a significant bottleneck in network performance in my tests. I changed the command-receive function to buffer the data in a 256KB buffer and then parse the commands from that. This significantly increased network performance when a large amount of commands were sent

  • Replaced the previous system of in-line adding network commands to client buffers directly to instead use the command queue, with a command_data wrapper that selects which clients should receive it. The new system is more stable as previously it relied upon there being no previous data in the send buffer to the client, but that was not a guarrentie. It was therefore possible to receive utility commands out-of-order sometimes

  • Change chat messages to reserve two lines of space per message by default. I was unable to find a solution to the memory corruption bug with the better variadic message length implementation. I may try to get it to work later

  • Add full-flegded private messages as present in other paradox games, in which you can select precisely which players should receive your message from the TAB-menu

  • add player limit to host settings

  • add player status for being OOS in the ui

And in the process of doing the above, refactoring a decent amount of the command/network code.

…. Still need to implement a way to ensure the client receives the message before socket is closed.
…queue instead, by implementing client selectors
…option for pre-execute&broadcast function for commands.

Also add host_execution to allow for commands to be queued that the host does not execute themselves.

Add function queue from update -> UI thread, so update thread can queue up ui-related things without breaking syncronisation.
Changed the "busy" cursor so that only a special "normal_cancel_busy" cursor type can cancel it, so it isnt cancelled by random mouse clicks.
…nction instead.

Experimental: allow host and client to fire off commands, even when some other clients are loading
…oad has been executed by the host, so that it is up to date.

Added command_executed back to send_receive loop
Minor optimizations
ZombieFreak115 and others added 18 commits January 4, 2026 21:56
… refs to command_data, to reduce copying if there are many clients
Fix oos bug if joining while the game is running, by preventing normal commands from being added to send buffer for a client in handshake mode.
Fix crash bug by adding a shared_mutex with the UI thread and cache thread
…f SPSC queue.

Change logging to work on a diffrent thread with a concurrentqueue. Any thread can queue messages to be logged without blocking, and game_loop() spawns a thread at the start which will process any queued log messages.
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
#ifndef WINSOCK2_IMPORTED
#define WINSOCK2_IMPORTED
#include <winsock2.h>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

by including these headers here, you are going to be pulling them into a huge number of places. If you are pulling them in just because you want SOCKET defined, SOCKET is unsigned int*

shutting_down = 2
};
#ifdef _WIN64
typedef SOCKET socket_t;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, using socket_t = ... is generally preferred these days over typedefs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants