#Addressables + Netcode for GameObjects

1 messages · Page 1 of 1 (latest)

sacred solar
#

Hi, I'm making a WebGL game with Unity to embed as a discord activity.

The game is a simple 3D RPG with low-poly areas segmented into designated levels, and travel between these levels are done via an interface. Player locations are client-authoritative while the server handles collision detection and enemy AI.

Since I'm targeting WebGL, performance is a big concern and so it seemed like it was obvious to split areas into different scenes so an interface could be used to load them, but it seems having multiple loaded scenes with NGO is hard or impossible, at least I can't seem to find a straightforward way to do it

I'm instead considering using Addressables to load only one level at a time for players while all scenes remain loaded for the server. I have a few questions about this approach

  1. Is this the right way to go about it?
  2. How should I structure my levels to make it modular to modify and load them?
  3. Is it possible for the clients to run on WebGL and build the game as a standalone application for the server as the server must process a lot of collisions and interactions

Thanks

gilded geyser
#

You can load scenes additively with no issues. But the host/server needs to have all scenes loaded.

If your levels are addressable prefabs then that could work as well. But again the server/host will need to have all spawned objects loaded even if they are hidden from certain clients.

sacred solar
#

The latter is fixable but I couldn't seem to find how multiple scenes can all share the same NetworkManager

gilded geyser
sacred solar
gilded geyser
sacred solar
#

Just want to ensure the system is modular and I'm not unnecesarily duplicating assets incase I change the UI layout for example

gilded geyser
#

Really depends on how your game is set up. I personally wouldn't put any UI elements in scenes

sacred solar
#

I have the default SampleScene rn and my UI is just a canvas called "Main UI"

#

(and that canvas resides inside SampleScene, along with my network manager and relevant singletons)

#

How do I separate the scene independent GameObjects from scenes?

#

Don't wanna take too much of your time explaining so just any pointers to the terminology would be great

gilded geyser
#

You can keep the SampleScene as the main scene with your UI. Then any levels would be loaded with NetworkManager.SceneManager.LoadScene()
I don't know what your levels consist of but once they are loaded it basically acts as one big scene

sacred solar
#

Online it says only the host or server can load scenes though

gilded geyser
#

That is correct

sacred solar
#

If there are 6 areas, how would a client only load area 2 for themselves

#

while still allowing other clients to reside in area 3 for example

#

It'd be intensive on resources for all clients to load all scenes, even if I disable the renderers and colliders

gilded geyser
#

Yes, it will be intensive. Its why most games limit your party to be in one area at a time

#

You can hide certain areas from other players but the server/host always needs to have them all loaded

#

unless no one is in the area. then it can be unloaded

sacred solar
#

but this would still load all the gameobjects

#

So is there a way to selectively load objects

#

Not just render, but load

#

I thought this was what addressables were meant for, so the server could load all addressables at the same time while clients only load the addressable they are currently in

gilded geyser
sacred solar
#

Right, I'll look into this for entities
What about level geometry (meshes, colliders, navmeshes)

gilded geyser
#

Addressables are more for things like DLC or addons

sacred solar
#

Ah right I see

sacred solar
gilded geyser
sacred solar
#

So this way the server is able to handle collisions and enemies for all the geometry at the same time, and the player is only loading meshes/colliders etc that are in their area

gilded geyser
#

Physics is normally handled by the server. disabling the terrain on just the client side might be more trouble than its worth.

sacred solar
#

Bit worried abt memory usage because I'm targeting webgl

#

Even if interarea loading times are better it's gonna take ages to load at the start

gilded geyser
sacred solar
#

Got it
I'll experiment with a few options
Tysm for the help

sacred solar
#

@gilded geyser Hi, I've been looking into other options for my problem

#

Supposedly if you disable Enable Scene Synchronisation it is possible for clients to load their own scenes

#

Is it possible to have a NetworkManager in each scene and NetworkObjects in each scene too?

gilded geyser
#

No, even with custom scene management you should only have only one Network Manager.
If this scenes don't have any network objects in them then it might be doable. Anything that needs to be synced to clients has to be kept loaded on the host/server.

You could also use Custom Messages if you want to handle all syncing manually. It's a lot more work though

If you haven't already read the Using NetworkSceneManager section, it's highly recommended to do so before proceeding.

A brief explanation of Custom Messages use in Netcode for GameObjects (Netcode) covering Named and Unnamed messages.

sacred solar
#

Is it not popular to have multiple scenes with network objects exlcusivie to those scenes?

#

Will look into messages if I want to pass things like indicating which scenes players are in

gilded geyser
sacred solar
#

Can I make the server do this?

gilded geyser
#

the server is the one that has to do the additive loading. by default it will get loaded to all clients as well

sacred solar
#

Can I make its o when the server starts it additively loads the 3 levels

#

without forcing the clients to load them too?

#

So the server is processing all 4 but the clients only have the hub loaded by default

sacred solar
#

Perfect, thanks

#

That works the best for me

#

I'll look into this

sacred solar
#

@gilded geyser Hi sorry, quick question but I'm still confused as to what function to use to load a scene for only the server without forcing clients to load it

Should I use NetworkManager.SceneManager.LoadScene or SceneManager.LoadSceneAsync(scene, LoadSceneMode.Additive);?

#

For the sake of explanation assume thers a Hub (defualt scene), Level A and Level B

My goal is for the server to load the Hub by default, then 2 players connect: They both load the Hub and can see each other, etc

1. Player 1 goes to Level A
- The server loads level A, keeps the Hub loaded
- Player 1 unloads hub, loads level A
- Player 2 does not load level A

2. Player 2 then goes to level B
- The server loads level B, keeps level A loaded, unloads the hub
- Player 1 does not unload level A nor load level B
- Player 2 unloads hub, loads level B
#

Markdown bullet point sare annoying let me just put that in code block

#

Hope the behaviour I'm trying to achieve is clear, but I'm still a bit confuseed on how SceneManager.LoadSceneAsync(scene, LoadSceneMode.Additive); behaves when considering NGO

sacred solar
gilded geyser
#

It looks like NetworkManager.SceneManager.VerifySceneBeforeLoading is all or nothing. Its really meant for server only scenes. And seems like you can't specify certain clients be allowed to load.

#

The workaround would be to not use scenes. Your levels would be network objects spawned with no observers at first. then you can show them to clients as needed

sacred solar
#

Oh right, so when Player 1 goes to Level A unfortunately Player 2 will have to load Level A, too

sacred solar
#

I'm a bit concerned about WebGL memory limits

#

Ultimately I'll have to profile the game eventually but I'm trying to future proof it beforehand

sacred solar
gilded geyser
#

No, the objects are not instantiated at all when hidden

sacred solar
#

Got it, thank you so much

#

So final question, would you recommend I keep levels as in-scene placed?

#

What's the advantage of spawning them

gilded geyser
sacred solar
#

I only really have enemies that are handled by their own NetworkBehaviour components

#

and players who are client auth

#

Nothing else needs to be synchronised

#

So would it be better to use in-scene placed NetworkObjects that invoke NetworkShow and NetworkHide when the player changes their scene?

gilded geyser
#

technically wouldn't matter in either way in that case

sacred solar
#

Right

#

Prefabs sprobably help with modularity so I'll go for that

#

Small final q but how do I make it so that the level is hidden by default

#

I'm worried if I invoke NetworkHide in OnNetworkSpawn or Awake that it'll be too late and the client would've already loaded the level leading to high memory usage

gilded geyser
#

there is a check box on Network Object to Spawn with Observers

sacred solar
gilded geyser
#

for network objects anyway. you can always just disable the renderer/colliders

sacred solar
#

Got it, tysm
🙏 Can finally get to doing some work lol

#

Ty for all the help

sacred solar
#

@gilded geyser I'm sorry I keep pinging u but I promise I genuinely just have one final question
I'm gonna keep the levels as dynamically spawned NetworkObjects and show/hide them to clients, it seems like the best solution

Just wondering finally if there's any way to wait for the Object to correctly show since these could be big levels and I don't want them to be half-loaded and potentially have issues
So essentially how'd I create a loading screen with this approach

gilded geyser
#

That should not be an issue. Objects do not Instantiate asynchronously so you will never see a partially loaded level. If it's large enough to cause a pause in gameplay then it need to be broken up into smaller prefabs. But OnNetworkSpawn() will run after the object is loaded. So you can use it to hide your loading screen

sacred solar
# gilded geyser That should not be an issue. Objects do not Instantiate asynchronously so you wi...

Hm right, I'm also kind of ok with the game becoming unresponsive for the client while they wait for loading. I'm a bit worried about modularity if I split up levels since then when I'd have to call NetworkShow on a lot of objects. Alternatively I could have the prefab have

level1 (no components)
- level1_1 (NetworkObject)
 - enemyspawner in level1_1
- level1_2 (NetworkObject)
 - enemyspawner in level1_2

Then I can spawn all the children of level1 in Awake, and NetworkShow/Hide the children when desired for clients
Does this seem like a decent way to go about it?

#

However, if instantiation (upon NetworkShow) is synchronous I'm not sure if this would just cause the exact same issue

sacred solar
#

Since I can't register level1_1 as a network prefab then

#

Man

#

Not sure what I can do except make level1 a networkobject and iinstantiate the whole level, so it will cause a pause in gameplay

#

I'm ok with that I guess, I'll just fade to black upon loading

#

Wish there was some way to keep the application responsivie and have some sort of indication the game is loading, and safely unfade once loadiing is done

#

But if prefab instantiation is synchronous I assume that isn't possible?

gilded geyser
#

Only the parent level object would need to be a network object. The child level objects can be regular game objects and Instantiated by the parent. There is no real reason for them to be child objects at all honestly.

sacred solar
#

Well I'm ok with slow

#

but unresponsive, rather

#

Right now I have a dictionary of strings to NetworkObjects

#

each NetworkObject is a level, spawned by the server in a singleton's OnNetworkSpawn
Then I have a ServerRPC to hide and show levels so the player can load/unload levels on their end

gilded geyser
#

You could space out the spawning of the sublevels over time if needed

sacred solar
#

It works perfectly, but that's because my level is just a plane with some boxes

sacred solar
#

Or you mean that I have multiple NetworkPrefabs corresponding to one "Level"

gilded geyser
#

The parent level object would all Instantiate locally on the client

#

Could also Spawn() them if they are network objects

sacred solar
#

That's what I'm doing currently yeah

#

Or rather, they get Spawn()ed at the very start of the server's lifetime

#

And are synchronised for late joiners

#

Still, when I invoke NetworkShow() iti checks the NetworkPrefab registry and instnatiates the level for the client

#

So I'm just wondering how I can make that more responsive since you said instantiation is synchronous

gilded geyser
#

Yea, NetworkShow() is just spawning for the individual client

sacred solar
#

Loading screens, subdividing, etc

sacred solar
#

But is there still really no way in unity to await instantiation?

#

so basically async NetworkShow?

gilded geyser
sacred solar
#

but on the other hand I'm guessing its probably impossible to use this method for NetworkShow?

#

I mean, I'm guessing NetworkShow uses the synchronous instantiation in its implementation

#

i.e. there's no real way to implement it and have a loading screen

#

MPPM is really buggy

gilded geyser
sacred solar
#

for example letes say my level is split as

#
level1
  - room1
    - enemy (server owned NetworkObject)

#

So I instantiate level1 for the client, then call InstantiateAsync on room1

#

The enemy won't be synced since I didn't instantiate it with the NGO intended method of NetworkShow, right?

gilded geyser
#

You would need to change how you are spawning enemies. The root level network object could track when the room is loaded then can Spawn the enemies.

sacred solar
#

so like

#

when NetworkShown

level1
  - enemySpawner
  - roomSpawner
#

level will have its OnNetworkSpawn invoked, meaning it can tell roomSpawner to call InstantiateAsync on the room geomerty

#

Since the server owns the enemies there's no risk of the enemy falling through the map

#

Does this approach make sense?

#

So all network related components like doors, enemies and enemy spawners will be shown immediately and synchronously

#

but the geometry can be asynchronously loaded to the client via InstantiateAsync, allowing for responsive loading

gilded geyser
#

Sure. but i would wait for the asyncronous load to complete before spawning any network objects.

sacred solar
#

So the server sees

#
level1
  - room1 (not a NetworkObject)
  - enemy (NetworkObject)
#

The prefab is

#
level1
  - room1Spawner
  - enemySpawner
#

If I call NetworkShow on level1, will the client be able to see enemy?

#

Since it'd instantaite level1 and invoke OnNetworkSpawn()

#

Man I'm surprised there's no elegant solution to this isort of level subdivision, I guess NGO was intended for games where players stick together

gilded geyser
#

Everything outside of an MMO is designed for players to stick together

sacred solar
#

I guess thats somehwere between a conventional game and MMO, with regions and whatnot

#

I think (since this is just for my friends and for fun), I'm just goiing to keep the level as 1 gigantic NetworkPrefab

#

I guess it'll just make the engine unresponsive for a bit, and I'll fade to black before