gamecreator Posted January 29, 2018 Share Posted January 29, 2018 Say I were to have a 32 player game where players were exploring a dungeon. The rooms are pulled randomly from presets I created in the editor, including a navmesh for each (for enemy character controllers). How would you go about doing this, assuming that each player could be in a different room? The partial solution I have so far was that each room is a different world. All each player and the server care about is the room the player is in at the moment. However, each player can be in a different room so this would mean having up to 32 worlds, all simulated by the server. Questions: 1. Is it feasible to call World::SetCurrent up to 32 times per frame and then do character controller/navmesh simulations on each? 2. Is there a smarter way to do this? Quote Link to comment Share on other sites More sharing options...
Rick Posted January 29, 2018 Share Posted January 29, 2018 I assume moving from room to room in the dungeon is a loading screen situation? Otherwise, why not just load the entire dungeon scene on the server and the client assuming the player can run to any other area in the dungeon and that you want those 32 players to share the same dungeon. 1 Quote Link to comment Share on other sites More sharing options...
gamecreator Posted January 29, 2018 Author Share Posted January 29, 2018 43 minutes ago, Rick said: why not just load the entire dungeon scene on the server and the client I don't think I can move the navmesh (some rooms may be duplicated in different parts of the dungeon). Besides, can one world even have multiple maps loaded into it at the same time with working navmeshes? Quote Link to comment Share on other sites More sharing options...
Rick Posted January 29, 2018 Share Posted January 29, 2018 This is probably my not understanding your game. To get a better idea: 1. Is the overall dungeon the same for all 32 players? 2. Are you sort of building the dungeon in code at match startup from all these separate rooms? I believe you can generate the navmesh from code. So if each room is a prefab instead of it's own map, then load the prefab and gen the navmesh? I don't have a great understanding of how your game is working though. If you're thinking about the server and it's storing 32 different rooms I wonder what the performance would be if each room was it's own prefab and the navmesh was loaded on each new room for the rooms that exist in the 1 map. If you place the rooms apart from each other in the 3D space they won't ever touch but building the navmesh could still work. It would most likely take a few seconds though which would pause the server from processing anything else I think. Just talking it out Quote Link to comment Share on other sites More sharing options...
gamecreator Posted January 29, 2018 Author Share Posted January 29, 2018 Pretend that the following dungeon layout/rooms is randomly generated at the start of the game. They are randomly connected by doors. Each room that you go into is a random map pulled from a premade room in the editor. There will be duplicates, so the room 1 preset could be multiple rooms (I can toggle things like decals and other visuals to add variety). Yes, all 32 players are on the same map/dungeon and can interact with each other if they meet each other in the same room. I've generated a navmesh by code before and unfortunately it's too slow for this type of gameplay (and really, multiplayer in general, I think). Players will feel like they're walking from room to room in a dungeon but that will be just the illusion. All the premade rooms will be loaded at 0, 0 as they leave one room and go to another. If you're familiar with Binding of Isaac, it can give you an idea of what this could look like, but the rooms don't have to be square in the end. Edit: Let me know if you have any more questions. I'm excited about the possibilities and it seems like a doable project as far as assets and coding but I don't know if it's practical for Leadwerks. I'm also debating just ditching the navmesh/controller part and making the enemies kind of dumb (not being able to easily go around pillars and such), which would just let me load the rooms as models wherever I want. Quote Link to comment Share on other sites More sharing options...
Rick Posted January 29, 2018 Share Posted January 29, 2018 Quote Pretend that the following dungeon layout/rooms is randomly generated at the start of the game. With that comment, for me, the solution is then to build the 1 map on the host from prefab rooms and then the host gens the final navmesh via code for itself. Tell the clients what prefab rooms go where and have the clients load those room prefabs and build the navmesh as well via code locally (they should match since LE built both). This is all done once at startup so once it's built you don't have to worry about it anymore. This is part of the loading screen so even if it takes 20 seconds it's not a big deal. This should be much easier than messing around with dynamic loading/unloading during run-time of rooms and navmeshes. This all assumes you don't care if the client gets the entire map info at startup. If you simply don't want them to see other rooms you can hide them, but if somehow knowing the design of the entire dungeon right away gives them an unfair advantage then this wouldn't work as they'll have that data and a hacker could figure the entire design out even though they only see 1 room on the screen at a time. So this is a question in requirements. They obviously wouldn't see where the other players are because your server wouldn't tell them where they are until they need to know (it should work that way anyway), so it's simply the design/layout that is in question here. When you're developing the rooms you make 1 room at a time in a map and test the navmesh generation there. Save that map with a name of just that room and that's your development map for that room. You'll then have a ton of these which is fine, but they aren't used for the game. After updating a map room you always save out the top level entity of the room as prefab (make a top level pivot for the room entities). 1 Quote Link to comment Share on other sites More sharing options...
gamecreator Posted January 29, 2018 Author Share Posted January 29, 2018 It's a good idea. I'm just concerned that the navmesh generation time, even during a loading screen at the beginning, will be too much. I remember when I did this for simple rooms with pillars it took a good several seconds just for that. For 50 or so rooms it's a lot to ask for someone to sit through. Still, I don't see a better option right now. I think I'll do some testing to see what it really looks like. Thank you both. Quote Link to comment Share on other sites More sharing options...
Rick Posted January 29, 2018 Share Posted January 29, 2018 Yeah it would be interesting to see the results of the test. I would assume there are efficiency techniques to help speed up the navmesh generation. Probably use invisible csg around models instead of detailed models for obstructions as maybe that reduces complexity in generation? Be able to walk through some props if it’s not vital for gameplay. Stuff like that. Rust takes about 3 mins to load the map and a lot of ppl play that game ? Quote Link to comment Share on other sites More sharing options...
gamecreator Posted January 31, 2018 Author Share Posted January 31, 2018 So... I'm a little shocked. I don't understand why this is so fast. I feel like I'm missing something. I wrote a quick program to test this. I basically modified the BuildNavMesh doc example to generate a number of rooms and measure the time it takes BuildNavMesh to do its thing. I also added 4 randomly placed "pillars" in each room to give it something more to work with. Here are my results: 1 room - 31 milliseconds 10 rooms - 93 milliseconds 50 rooms - 343 milliseconds 100 rooms - 359 milliseconds 1000 rooms - 561 milliseconds That's right - milliseconds. Even 1000 rooms took less than a second to generate the navmesh. So I'm pretty happy with going forward with this method. Below are a screenshot and the full source. #include "Leadwerks.h" #define MAXNUMBEROFROOMS 1000 #define OBSTACLESPERROOM 4 using namespace Leadwerks; Model* ground[MAXNUMBEROFROOMS]; Entity* entity[MAXNUMBEROFROOMS*OBSTACLESPERROOM]; void createrooms(int howmany) { float xoffset=0; int entityindex=0; if(howmany>MAXNUMBEROFROOMS) { MessageBoxA(0, "Number of rooms requested for generation exceeds MAXNUMBEROFROOMS.", "Error", 0); exit(1); } for(int i=0; i<howmany; i++) { //Create the ground ground[i] = Model::Box(10, 1, 10); ground[i]->SetPosition(xoffset, -0.5, 0); ground[i]->SetColor(0.0, 0.25, 0.0); //Create a shape Shape* shape = Shape::Box(0, 0, 0, 0, 0, 0, 10, 1, 10); ground[i]->SetShape(shape); shape->Release(); //Enable navigation obstacle ground[i]->SetNavigationMode(true); //Create 4 randomly placed obstacles per room for(int j=0; j<OBSTACLESPERROOM; j++) { //Create a model entity[entityindex] = Model::Box(1, 1, 1); entity[entityindex]->SetColor(0.0, 0.0, 1.0); entity[entityindex]->SetPosition(Math::Random(xoffset-4.5, xoffset+4.5), 0.5, Math::Random(-4.5, 4.5)); // entity[entityindex]->SetPosition(0, 0.5, 0); //Create a shape shape = Shape::Box(0, 0, 0, 0, 0, 0, 1, 1, 1); entity[entityindex]->SetShape(shape); shape->Release(); //Enable navigation obstacle entity[entityindex]->SetNavigationMode(true); entityindex++; } xoffset+=11; } } int main(int argc, const char *argv[]) { Math::SeedRandom((int)Time::Millisecs()); Leadwerks::Window* window = Leadwerks::Window::Create(); Context* context = Context::Create(window); World* world = World::Create(); Camera* camera = Camera::Create(); camera->SetRotation(35, 0, 0); camera->Move(30, 0, -28); Light* light = DirectionalLight::Create(); light->SetRotation(35, 35, 0); camera->SetDebugNavigationMode(true); //Enable navmesh debugging int numberofrooms = 10; createrooms(numberofrooms); long starttime=Time::Millisecs(); world->BuildNavMesh(); //Build the navigation mesh long endtime=Time::Millisecs(); while (true) { if (window->Closed() || window->KeyDown(Key::Escape)) return false; Leadwerks::Time::Update(); world->Update(); world->Render(); context->SetBlendMode(Blend::Alpha); context->DrawText("Navmesh generation time: "+String(endtime-starttime)+" milliseconds", 10, 10); context->DrawText("# of rooms: "+String(numberofrooms), 10, 30); context->Sync(); } return 0; } Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.