“What Not to Do: Do not try to modify, create, or delete UObjects from other threads!”
That doesn’t leave that much left to do; all your world data are in UObjects, and you cannot access them. I guess IO could be done in other threads (if it isn’t done so already by default), and maybe things like “terrain generation” in a procedurally generated world, but I cannot see what I would do to make full use of that “N -1” cores that don’t get any work to do. I mean, I have a 6-core PC, and my PC is basically “old” now; it’s only going to get worst, with “N cores” getting bigger, and the percent of the whole CPU used by the engine main thread is therefore getting smaller. Am I missing something?
I’m used to multi-threading a lot, including using things like (Erlang-type) actors, so being limited to (basically) only one thread feels like moving backward.
I think UE4 already uses several cores by default, for rendering for example, so its not entirely singlecore.
Well, that doesn’t say that you can’t access them at all. You could read from them (do valid-checks, of course) or collect all relevant data in the main thread and send that relevant data over to another thread for calculations.
I haven’t done any multithreading myself in UE4, but as an example what you could do with multithreading:
What about an Ai with complex decision making? Main Thread could want an Ai Controller to choose a target.
Main Thread collects a list of nearby targets, sets AiControllers target to nullptr (which in this case could mean no target, aka it won’t do anything, it is waiting for a decision to be made), activates another thread and passes the list of those nearby targets and some data about the AIs state…
While Main Thread is doing its thing calculating the rest of the world, the new thread does complex stuff like visibility tracing to all targets in the list and is doing decision making algorithms.
When the new thread is done, it activates a mutex lock on the AIController (or any other locking mechanic) to set the new target in the AiController and then releases the mutex lock again.
Main Thread can access AiController again, sees that a new target is set and can make the Ai now attack the target
That would be good, but it wasn’t obviously clear from what I read so far.
I *can *read the data from another thread, but unless I use some kind of synchronization, and block the main thread temporarily, I might read “garbage” (half-old, half-new values) if the main thread is currently modifying those values. And blocking the main thread is probably a Bad Idea, so I guess the simplest/safest is to copy/snapshot the data to be seen by the threads (atomic pointer CAS is pretty cheap on Intel).
That is the other thing that I thought of so far, beyond “procedural generation” and IO. Hopefully this is possible without too much data copying (highly dependent on game specifics).
That seems quite useful. Thanks!
The last thing I thought of, is that the netcode might be *perverted *to have the “other threads” act like “special clients”, and use the netcode to replicate changes to them. But I’m pretty sure this is beyond my abilities to implement, if at all possible.
But isn’t GameMode:Tick (and any Actor:Tick, for that matter) executed on the main thread anyway? So it’s not really reading/writing from another thread.
Could you post an example?
As far as i know modifying and especially spawning or removing UObjects isn’t thread-safe unless you make them thread-safe by using mutexes and such for thread-critical code areas, but i’d love to be proven wrong on this one.
U can use threads and sync with main thread using Dispatch function (add a function to the main thread task queue)
I use this for implementation with a custom MMO server, where the network reader is running on a different thread and sync some functionallity with the main threads.
// This function is being called within the network reader thread
void AMMOMenuController::OnHandshakeResponse(class FMMONetworkMessage& Message)
if (Message.ReadUInt32() == 0)
// Send the authenticate message
// Parse the message
FString ErrorMessage = Message.ReadString();
// Dispatch the events on the game thread
Authenticated(false, FMMONetworkSessionData(), FText::FromString(ErrorMessage));
}, TStatId(), nullptr, ENamedThreads::GameThread_Local);
// Reset the username and password
CachedUsername = TEXT("");
CachedPassword = TEXT("");
Firstly, thanks for contributing to my discussion. I have a totally unrelated question. I’m always a bit confused (and disappointed) when I read that someone is creating a “MMO”, but then it runs on one server (I’m assuming this is the case for you too, simply because it would be near impossible to “cluster” UE4 servers into a single seemless world; please correct me if my assumption is wrong). For me, “massive” starts at least 1000 players, and at least a cluster of 10 servers.
So my question is, how do you decide that your game is “massive”? What is the criterion/limit you use to decide that you’ve created a MMO, as opposed to “just a game”?
I spend over 8 years researching and creating the server system, which was initial inspired by the Torque MMOWorkshop project, but also a bit by open source projects like PlaneShift/Ryzom.
The server system is not a single server system. It contains a master server, char server, realm server, zone server & zone proxy servers. It’s fully writen in C++ using boost asio, but without any use of shared/smart pointers as they have to poor performance for this. Running on both windows and linux (debian tested only)
The logic inside the realm server makes the game world self scalable by spawning/despawning zones in the different zone servers and have internal sync system, client travel between zone server and coordinates the needed information between zone server & zone proxy servers.
The only thing the server system currently not support is client movement synchronisation. I been experimenting with simulation server, where i can load an exported UE4 heightmap, and using PhysX/CUDA for movement simulation, but it’s so hard to get the movement exactly the same as on the game client and get everything synced smoothly troughout the server system (sim => zone => proxy => client).
But TBH, i don’t really care about movement sync at this moment, priorities are somewhere else. Currently im using point and client movement system, where both server and client move in straight line toward the target point and client does collection detection. In future i should add path finding and some basic collision detection on the server side.
Currently working on the client, where most of the UI is based on UnrealGaimeDev’s youtube channel, but using the server as backend to persist information like inventory, spawn mobs, npc’s, vendors, quest system, crafting system, …
So hopefully in few months i will be able to show something and release a simple game that allow testing the real performance and see the limitations.
Anyway, this is very off topic (altho server has same kind of threading model, where dispatchers/schedulers sync tasks between many threads to avoid having locks)
Hope this answered your question and for those who think i can make full MMO game myself … lol no, i have years of experience in creating high performance server system as professional job and love game dev, but i 1000% suck at creating content, maps, open worlds and/or anything graphic, so without content no game. I just want to make the server system and hopefully be able to make profit some day with it
I know how hard it is (from reading articles about it; I did not try myself). That is why I’m always exited when it sounds like someone “solved” that problem (and might consider sharing how it was done).
It sounds like we are in a somewhat similar situation (not that I have experience in creating games, but I do have professional experience in “making things run as fast as possible”), as I cannot create content either.
OTOH, I have a “solution” for the “game content”; I decided to just go with what is available on the marketplace, and spent a boatload of cash there, in the sales; I have 470GB of files in my “marketplace vault”. This obviously restricts the kind of game I want to create, but for “post apocalyptic survival” (with crafting and building), there are plenty of assets. I doubt a game made entirely of “of the shelve” assets will sell, so I’ll probably either give it way free or dirt cheap. I’ve considered looking for an artist to partner with, but I can’t ask anyone else to work on something with basically no hope of ever making a profit. So I think of the whole thing as simply an (expensive) past-time activity.
The only other individual who I know tries to do distributed unreal game is Jin (I’m assuming you are different persons…):
The best use case for threads in UE4 is to do operations that can take a little too long time in a non blocking way. You can spread a task in time instead of blocking the game thread for too long in a single tick.
Just to add my two cents to it, I go with the Unreal becomes dumb UI model at the moment. The game representation and dynamic meshing is done in threads but the most important workload is path-finding for me. Liquid simulation is not that challenging for the CPU (I use a grid based system) than having the decision making and the path-finding driving it done as fast as possible on very large maps (using the notion ‘large map’ as used 5 years ago). It was the main reason why I am fighting with C++ rather than doing stuff in C# (I come from the Java world).
PS: I hope Unreal supports C# or whatever sooner or later. This micromanagement of C++ is error prone and for 90% of the stuff I do unnecessary. But for the 10% of times Unreal + C++ are invaluable for me.
PSS: Have a look at the FPThreadsRWLock class as it is often overlooked. But for some parts I had to do an extension to avoid starving the write lock if read locks are acquired all over the place and every time.