Search Unity

Large Project Architecture Concerns

Discussion in 'General Discussion' started by TheGabelle, Aug 14, 2019.

  1. TheGabelle

    TheGabelle

    Joined:
    Aug 23, 2013
    Posts:
    242
    Hey everyone!

    I come from a web dev background. I'm used to working with small dev teams on massive projects with complex deployments. Point is, I'm used to massive project scopes and codebases where the points of concern listed below are very clear and well defined.

    When it comes to Unity I've always found it difficult to move past simple projects. I've identified a few of my primary pain-points, listed below. Under each pain-point is a bit about my understanding and any running concepts I'm planning on using. If you think there's room for improvement / troubles ahead please let me know. Thanks!

    1. Point of Entry
    Sometimes I create an empty GameObject and throw all my singletons on it, modifying the script execution order when needed, and just using slow searches when needed.

    Other times I create a static God class and add a using statement in every MonoBehavior to reference it. This is fine for really small things, but I really don't think I should go that route with this project. I've suggesting doing this in #3 because I don't really know how to separate myself from it. This might be a problem when trying to register systems within packages, described in #2.​

    2. Asset Organization and Version Control
    From what I have gathered, creating custom Unity packages and utilizing the Unity Package Manager is a good way to go. To keep my codebase modular and reusable, each system will be created as a separate package.

    Versioning would be handled via GitHub and the package manifest file. Would using packages lead to additional issues with #5?​

    3. Dependency Management
    I've looked at Zenject and the like, but haven't found a solution with an appealing implementation. In the past I created factories that injected what I needed through a self-enforced Init() method. Now I'm wondering if I should take a page from Laravel, sort of: a static Facade class to which systems register themselves and dependents pull from in Awake(). Definitely open to suggestions.​

    4. Database
    Using ScriptableObjects to store default values is nice because I can use the Unity Inspector to modify them, but I'm guessing they'll make #5 more difficult to implement. Furthermore, when you load a ScriptableObject, I'm pretty sure you load up anything related to it So, I'd use a single SO per 'item' or whatever.

    Using XML / JSON files is okay and would likely make #5 easier, but become a pain to modify outside the Unity Inspector. Any better way?​

    5. Mod Support
    Assets like textures, audio, and models shouldn't be hard to import from file. But, how do I support scripts? How do I keep the project source secure, or servers / clients secure? I'd prefer mods to be written in C# rather than in something like Lua, if I can help it anyway. I'm pretty green when it comes to this category. I'd likely I'll definitely need to account for mod support from the very beginning.
    6. Deployment / Updates
    I've never even come close to this point in any of my Unity projects. I plan on using Steam. Updating games via Steam is supposedly pretty painless. If you got any tips when it comes to Unity and Steam I'm all ears.
    Additional Info
    I am focusing on standard Unity while DOTS matures. Eventually I'd like to start replacing systems with production-ready ECS implementations. Ideally everything will become data-oriented. If there's any pain-points to be wary of I'd like to hear them now. Keeping the future ECS implementations in mind while developing the standard implementations might prove beneficial in the long run.

    I'd like to refrain from using paid assets, and would like to learn how to implement things myself when reasonable.

    Thanks for reading!
     
  2. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    I would absolutely not use the package manager for game specific code. It's also very important to note that I would also not recommend writing much non-game specific code.

    I'm a believer in the idea that your coding practices should realistically be matched against your actual process. That something like a solo effort, and especially a solo hobbyist should not be using enterprise techniques unless they're so deeply seeded and habitual that you're really inefficient any other way.

    In terms of mod support, you don't generally want to include script directly, and if you do allow direct scripting this is generally done via an interpreter (like embedding a lua interpreter or whatnot). Targeting PC, you could also opt for just c# dlls and an API to bootstrap plugins, or c# scripts with runtime compilation and bootstrap (although I think both approaches are rare for game modding).

    Generally modding support is driven by data driven content with hooks to load in new content. Scriptable objects can still be used to support this by treating the SO as a thin 'host' for editor support, more so than directly embedding the data in the SO.

    Example:
    Code (csharp):
    1.  
    2. [Serializable]
    3. class Character{ public string Name; public int HP; }
    4.  
    5. public class CharacterScriptableObject : ScriptableObject{ public Character Character; }
    6.  
    That basically just uses the SO to expose stuff to editor if you really want that. But I think that in general, if you want modability, you look really more towards just raw serialized data (json or whatever else).

    You can also look to a hybrid of scripting and serialization by looking at basically serializing a bunch of commands with various parameters that can be used to do whatever.

    Modding is a really wide subject and not a one size fits all kind of thing. There's a lot of different degrees of modability (can the modder edit UI elements, game logic, content, all of the above?). I think the basic rule of thumb is that once you are reaching for a high degree of moddability, you're probably also dogfooding, and using your own mod system to build the game systems you're using.
     
  3. JohnnyA

    JohnnyA

    Joined:
    Apr 9, 2010
    Posts:
    5,041
    Given you have the background I'd suggest working on a range of projects using a range of options, gradually increasing complexity and being willing to make mistakes along the way.

    Try different approaches and suggestions and add in your own insight.

    A key already mentioned by @frosted is that you need to right-size your processes, if you aren't building projects as big as the ones at work then you can likely get away with simpler processes.
     
    NotaNaN, RecursiveFrog and Ryiah like this.
  4. TheGabelle

    TheGabelle

    Joined:
    Aug 23, 2013
    Posts:
    242
    In web development breaking systems into packages is a good idea. Why would the case be different with Unity? I guess it wouldn't make much difference if I just created repositories per 'package' and simply copy the contents into a current project. Still though, I'm curious why creating actual packages isn't a good idea.

    I've been thinking about giving Roslyn C# - Runtime Compiler a try. Hopefully I can whitelist namespaces I create for scripts serving as 'middlemen' between external scripts and Unity / my framework.
     
  5. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    In practice it nets you very little unless you're actually using those packages as reusable elements across multiple projects. Otherwise you need to add complexity to the code to generalize the functionality. If you do actually use these in multiple projects, then you need to balance the odds for regression against the gains from improvement.

    That said, in general, I'm an advocate for less abstracted code. So feel free to take this with a grain of salt.
     
  6. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    There's development overhead into organizing your project into independent packages, but what are you actually gaining from it? Probably not much at all unless you're talking about a system like a custom network API you plan to use on a variety of projects. So it is probably wasted effort, slowing down your actual game development.
     
  7. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847

    For run time scripting provided by your users you will have to include an interpreter. In theory you could write or find a C# interpreter to include in your game. I wouldn't recommend writing that yourself though, just because it probably isn't worth the effort.


    It is pretty painless. You just upload another build using the tools provided in the SDK just the same as you uploaded the first build. Then in Steam's web interface you set it to use the new build.

    The biggest issue I have is the upload process is a bit annoying to set up. It is just editing a few files with the right ID's and folder names, but the problem is Steam uses several ID's for different things sometimes uses the same names for them in the documentation, making it confusing as to which to use. Once you get that figured out though all you do is copy your new build to the content folder and run a batch file.

    Secondarily setting your new build live is annoying because the place to do so is nested under several menus in a not so obvious spot. I ended up just bookmarking the page directly because it is annoying to find if you forget where it is.
    If you're planning to use DOTS, why not start your game with it right now? It will be a lot easier to make changes to your project as DOTS changes than it will be to take a game pretty far along using the classic approach and redesign it to use the DOTS approach. I'd choose one or the other right now and stick to it.
     
    RecursiveFrog likes this.
  8. RecursiveFrog

    RecursiveFrog

    Joined:
    Mar 7, 2011
    Posts:
    350
    Agree, I’m not entirely sure how Unity’s DOTS and ECS implementations will look in the end, but ECS is a wildly different paradigm from the OOP that Unity has been based on this whole time, and from what you’d find in web development. Swapping one out for another mid to late project feels like a huge pain.

    Packages might make this even worse if the APIs are different enough or the responsibilities overlapping or don’t feed well into each other.

    Like for example, if your apis are highly reliant on asynchronous callbacks then you’re possibly in a very bad spot when your ECS code can’t use those callbacks because the whole point is to use “systems” and avoid virtualized calls
     
    Joe-Censored likes this.