#Where should I put my utility methods?

1 messages · Page 1 of 1 (latest)

timber lagoon
#

I'm working on a DOTS project where the team has developed a bunch of static utility classes, which provide static methods used to query or manipulate the world entities from the UI, from systems or from MonoBehaviours.

However I don't like the design of these utility classes, since they need a lot of information to be passed as parameter:

  1. The world (often the default one is statically referenced from the method itself and I don't like it)
  2. The entityManager
  3. The commandBuffers (if the method needs to manipulate stuff)
    And many overload the same method are created to support parallel buffers or lookups... it is chaos.

I've found a cleaner way but I'm not sure it is the intended way to do this. I found that having these utility methods in Systems (that can be easly retrieved through from anywhere through world.GetExistingSystem) is way cleaner, since I can use SystemAPI. It works very well but now I have a bunch of systems without the OnUpdate method, just staying there. Is this a performance problem? Is it a good idea?

grizzled glen
#

None of this really fits ECS. You're supposed to have one system doing specific logic and that's it. No static methods unless it's some generic stuff or pure helper for some math

#

Accessing other systems is only meant for debugging

#

So if you use it for actual game logic - you are on the very wrong path

#

also, using any system api outside of system callbacks is just unsafe

novel sable
#

if you do that i guess you do everything on mainthread finally.

fallen lodge
#

I totally agree with @grizzled glen but from perspective of code there is no difference between static helper method and static gamelogic method.

The difference is really is where I as a developer expect to see the two. I often struggle with where I should put my helper methods, how I should give access to shared often accessed data.

For example in my case I have a grid and I've implemented component which contains bunch of native collections and implements bunch of common methods to simplify access to cell entity by some data. So in Job it looks like one field GridDataAccessor.

timber lagoon
#

I understand that this is not the proper way to use systems BUT our problem remains: where should I put helper methods? Copy-pasting code around is just way worse, we need systems to call shared methods. How?

timber lagoon
novel sable
timber lagoon
novel sable
#

Is these offline game?

timber lagoon
#

Our project is not 100% pure ECS, we have many MonoBehaviours to control UI, timelines, animations etc. That's why it is important for us to send/receive data to/from the entities world, which holds the game logic

timber lagoon
novel sable
#

That is ok

#

But you do not have to put function in systembase

#

Just using entityquery and entitymanager to query entity

timber lagoon
#

That is our current approach but I personally dislike it. Not being in a system means no SystemAPI and no SystemState, so everything has to be passed as parameter to these static helper methods... 😦

novel sable
#

In my case I never need systemstate outside ecs

#

And systemapi too

#

Do know why helper need systemapi as a parameter

timber lagoon
#

SystemAPI cannot be passed as parameter. We pass as parameter the world, the entity manager, the command buffers etc

#

Asking a system to perform queries and operations through SystemAPI looks very much cleaner

novel sable
#

These stuff could be static

timber lagoon
#

The helper methods would work only on a specific world then

#

We actually use only one world (World.DefaultGameObjectInjectionWorld) but helper methods should not assume that

grizzled glen
#

With ECS DRY (don't repeat yourself) pattern is practically squared and absolute. Not only you are supposed to not repeat yourself, but also the only caller of DRY code is supposed to be just one and only system.

#

Unless ofc your whole project is OOP and you want to use ECS only for limited specific stuff (practically as VFX graph or as Particle System) , in which case you should approach what you are doing very different as well and never expose internals of ECS outside of World (and it's manager).
(But I'm not sure if your project is like that, allthough it does sound like it)

timber lagoon
grizzled glen
#

basically: your UI is View which is isolated from ECS, it only knows how to set view properly based of data.
Each View that needs game data (Model) needs a ViewModel, which is a system.
System gets reference to your View and based of View requests (which are exposed either via property or via callback events on View class) calls method of View with game data in parameters.
So something like:
public class PlayerNameView with method SetPlayerName(string name).
And associated ViewModel:
public partial class PlayerNameViewModel : SystemBase with
protected override void OnUpdate() {
var playerName = SystemAPI.ManagedAPI.GetSingleton<PlayerName>();
_playerNameView.SetPlayerName(playerName.value);
}