Facepunch / sbox-issues

176 stars 12 forks source link

GameObjectSystem load priority #6470

Closed Coomzy closed 1 month ago

Coomzy commented 1 month ago

For?

S&Box

What can't you do?

I can't decide what order GameObjectSystem's load in

How would you like it to work?

Add an attribute or something for GameObjectSystem priority and load them in that order

What have you tried?

Written my code in a way that didn't rely on order

Additional context

No response

garrynewman commented 1 month ago

This needs more explanation/justification

Coomzy commented 1 month ago

If I want a GameObjectSystem to be able to use another, I currently have no control what order they load, so I can't rely one being loaded before another.

I wanted to make a GameObjectSystem that reset static variables, but I can't gaurntee that it loads before other GameObjectSystems, so I just had to ditch the approach.

Here is arbitrary example, where I have a system for putting the clothing into a dictionary, and a different system for dumping all the entries. I don't know if ClothingSystem will actually be loaded before DumpClothingSystem so I'd have to write this in a different way for it to work.

public class ClothingSystem : GameObjectSystem
{
    public static Dictionary<int, Clothing> clothingIdToResource = new Dictionary<int, Clothing>();
    public ClothingSystem(Scene scene) : base(scene)
    {
        foreach (var clothes in ResourceLibrary.GetAll<Clothing>())
        {
            clothingIdToResource[clothes.ResourceId] = clothes;
        }
    }
}

public class DumpClothingSystem : GameObjectSystem
{
    public DumpClothingSystem(Scene scene) : base(scene)
    {
        foreach (var kvp in ClothingSystem.clothingIdToResource)
        {
            Log.Info($"{kvp.Value.ResourceName}: {kvp.Value}");
        }
    }
}

Whereas what I'd like to be able to do is:

[GameObjectSystemPriority(-1)] // Ensures it loads before DumpClothingSystem
public class ClothingSystem : GameObjectSystem
{
    public static Dictionary<int, Clothing> clothingIdToResource = new Dictionary<int, Clothing>();
    public ClothingSystem(Scene scene) : base(scene)
    {
        foreach (var clothes in ResourceLibrary.GetAll<Clothing>())
        {
            clothingIdToResource[clothes.ResourceId] = clothes;
        }
    }
}
MD485 commented 1 month ago

Can you not just:

public class ClothingSystem : GameObjectSystem
{
    public static Dictionary<int, Clothing> clothingIdToResource = new Dictionary<int, Clothing>();
    public ClothingSystem(Scene scene) : base(scene)
    {
        Listen( Stage.SceneLoaded, 10, ClothingSystemInit, "Loading Clothes" );
        Listen( Stage.SceneLoaded, 11, DumpClothingSystem, "Logging Clothes" );
    }
    public void ClothingSystemInit()
    {
        foreach (var clothes in ResourceLibrary.GetAll<Clothing>())
        {
            clothingIdToResource[clothes.ResourceId] = clothes;
        }
    }
    public void DumpClothingSystem()
    {
        foreach (var clothes in ResourceLibrary.GetAll<Clothing>())
        {
            Log.Info($"{kvp.Value.ResourceName}: {kvp.Value}");
        }
    }
}

You can do this even if the methods are in other GameObjectSystems, although I'm not sure I understand why you would have a GameObjectSystem without locally mutable data/an update loop.

I imagine your DumpClothingSystem example doesn't really make sense to make in any context, other than purely rhetorically, but it raises the concern of using that you're trying to shoehorn functionality that's not serviced well by the systems.

Coomzy commented 1 month ago

Listen( Stage.SceneLoaded, 11, DumpClothingSystem, "Logging Clothes" ); seems to do what I'd want and I'll just stop using GameObjectSystem constructors for anything other than Listen events