Announcement

Collapse
No announcement yet.

How do I add a module? Looking for a thorough, systematic and in-depth explanation. Long post

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

    How do I add a module? Looking for a thorough, systematic and in-depth explanation. Long post

    Hi, I've just been into UE for a little over two months with self-taught c++ and not much programming experience. The questions I'm about to ask here might seem trivial for experienced people but I hope you guys can bear with me and give me some insights on this topic.

    My goal is simple: a general way to add a module. Now this goal is also somewhat vague since I don't yet have the enough knowledge on this topic to make a very precise demand.

    I've googled a lot on this and have come up with a rough system about how this works, which I will explain below with the sources. This rough understanding raises lots of questions, which I hope will get an answer from you.

    Now from all the sources I've read so far, they both share a common thing on how to add a module: You play with several files and that's it. So my system so far is in the perspective of what files you play with and how you play with it.

    From https://www.sandordaemen.nl/blog/cre...real-engine-4/ and https://wiki.unrealengine.com/Creating_an_Editor_Module (which are surprisingly similar in content), it seems that there are five files you need to play with in order to add a module:
    1. .uproject file
    2. .target.cs file for the module to add
    3. .build.cs file for the module to add
    4. .h file for the module to add
    5. .cpp file for the module to add
    For the .uproject file, the way you play with it is that you add a module entry in this file for the module you are adding or creating. This entry involves some fields such as Name, Type, Loading Phase. These names are fairly self-explanatory. However, my question is what does adding this module entry do? How does it fit in the big picture of the whole process? By whole process I mean maybe a flow chart explaining roughly how modules are connected and loaded to your project.

    For the .target.cs file, you need to put a command like ExtraModuleName with your module name as the argument. However, it seems that this step is somewhat deprecated in later UE versions. See https://www.sandordaemen.nl/blog/cre...real-engine-4/ and https://wiki.unrealengine.com/Creati...ting_Target.cs. Or even unnecessary. See http://kantandev.com/articles/ue4-code-modules

    My question is what does step do? I thought playing with .uproject file is enough to hook the module with the project. Then what does that ExtraModuleName command does and how this step fits in the whole picture?

    For the .build.cs file, .h file and .cpp file, it seems that they are a bit easier to understand since they are isolated very good and are only related to creating and building the module itself without involving projects or whatsoever. But there are also some questions.

    The first question about this section is how you use code from one module in another module. Let's say we have module A and module B. In the header files of module A, I have included Module B in its dependency module names. Is this enough for me to use code from module B in module A?
    I also came across that Module API stuff which you have to put in front of your code in one module to expose it to others. What's the relationship of this Module API stuff with DependancyModuleNames? Do I have to have both of them to be able to use code from B in A? I'm confused

    The second question is about the IMPLEMENT_PRIMARY_GAME_MODULE(<Modulename>, "<GameName>") and IMPLEMENT_GAME_MODULE(FDefaultModuleImpl, YourModuleName
    ) See: https://docs.unrealengine.com/en-US/...lay/index.html and http://kantandev.com/articles/ue4-code-modules

    These two seems very similar to me and yet their argument differs a lot. In the first one, you put the module in the first and game in the second. However, in the second one, you put some class in your module in the first and your module in the second. My questions are why in the second command you have to put a class in when you are trying to implement a module, which is sort of a collection of classes as a whole. Why single out that class? What purpose does it serve?

    In the official document https://docs.unrealengine.com/en-US/...lay/index.html, it also talks about playing with the DefautEngine.ini file, which is never mentioned in other sources. What does playing with this file does when you are adding a module? Is it playing with it deprecated already?

    This is a long post with many questions. I'm sorry for that and hope you guys can help me out.
    Last edited by Nastymonk; 08-02-2019, 12:40 AM.

    #2
    The difference is one of runtime vs compile time.

    uproject/uplugin entries are used by the engine to determine if and when to load modules, at runtime.

    ExtraModuleNames in the target file tells UBT that it needs to compile the module. As I noted in my article you linked, if you have a dependency chain to your module from another that is already specified here, then adding it explicitly won't do anything.

    Essentially yes, to use code you need to specify the module dependency, but also will need the symbol that you want to use to have been exported via the MODULENAME_API. Under the hood though, it's complex.

    Virtual method calls, for example, don't require anything to have been exported. It's also platform dependent - the UE4 build system is attempting to wrap multiple platforms that behave differently in this respect a one consistent way. If you want to know more details, search outside of the UE4 context, for things like dllimport/dllexport.

    The module class derives from IModuleInterface, which has some virtual methods you can override to do things when the module is loaded/unloaded. FDefaultModuleImpl is just the one you can use if you don't have any need to define your own module class with specific behaviour. Here's an example of a non-default module class.

    Comment


      #3
      Thank you!
      Didn't expect the writer from the source to reply! This helps a lot!

      Comment


        #4
        Originally posted by kamrann View Post
        The difference is one of runtime vs compile time.

        uproject/uplugin entries are used by the engine to determine if and when to load modules, at runtime.

        ExtraModuleNames in the target file tells UBT that it needs to compile the module. As I noted in my article you linked, if you have a dependency chain to your module from another that is already specified here, then adding it explicitly won't do anything.

        Essentially yes, to use code you need to specify the module dependency, but also will need the symbol that you want to use to have been exported via the MODULENAME_API. Under the hood though, it's complex.

        Virtual method calls, for example, don't require anything to have been exported. It's also platform dependent - the UE4 build system is attempting to wrap multiple platforms that behave differently in this respect a one consistent way. If you want to know more details, search outside of the UE4 context, for things like dllimport/dllexport.

        The module class derives from IModuleInterface, which has some virtual methods you can override to do things when the module is loaded/unloaded. FDefaultModuleImpl is just the one you can use if you don't have any need to define your own module class with specific behaviour. Here's an example of a non-default module class.
        Hey kamrann,

        I want to ask more about the last point where you want to include stuff in Module B in Module A. After looking around, I have an idea about the requirement for this:
        1. Module B has to be in the dependency name list in Module A's .build.cs file
        2. The stuff in Module B you want to include in Module A has to have the API prefix.
        3. The stuff in Module B has to be in the public folder inside Module B.

        Is that right?

        Comment


          #5
          Originally posted by Nastymonk View Post
          1. Module B has to be in the dependency name list in Module A's .build.cs file
          2. The stuff in Module B you want to include in Module A has to have the API prefix.
          3. The stuff in Module B has to be in the public folder inside Module B.

          Is that right?
          Yep, correct. With the exception that if all you need to do is access member variables, call inline methods that only access member variables, or make virtual method calls, then (2) is not required and (1) can be replaced with a dynamic module dependency. Reason being that the above cases don't require to know specific addresses of code/data inside the module.

          Comment


            #6
            Originally posted by kamrann View Post

            Yep, correct. With the exception that if all you need to do is access member variables, call inline methods that only access member variables, or make virtual method calls, then (2) is not required and (1) can be replaced with a dynamic module dependency. Reason being that the above cases don't require to know specific addresses of code/data inside the module.
            Thanks kamrann, I have another question to ask.

            It seems that there are two ways to expose functionalities across DLL boundaries. The first one is Module API, which is dllimport/dllexport under the hood. However, in the last several sentences in Unreal Module API, it states that "The API macros are mostly used on older code to allow newer modules to access it from their DLL. In newer bits of code, the API macros are used far less, instead setting up nice interface layers to expose functionality across DLL boundaries."

            How does this setting up nice interface layers work? Can you provide me with an example? Thank you very much!

            Comment


              #7
              Thank you !



              ________________________________________________
              Sarkari Result Pnr Status 192.168.l.l
              Last edited by blackiytso; 08-12-2019, 06:58 PM.

              Comment


                #8
                Originally posted by Nastymonk View Post

                Thanks kamrann, I have another question to ask.

                It seems that there are two ways to expose functionalities across DLL boundaries. The first one is Module API, which is dllimport/dllexport under the hood. However, in the last several sentences in Unreal Module API router API settings, it states that "The API macros are mostly used on older code to allow newer modules to access it from their DLL. In newer bits of code, the API macros are used far less, instead setting up nice interface layers to expose functionality across DLL boundaries."

                How does this setting up nice interface layers work? Can you provide me with an example? Thank you very much!
                Thank you
                Last edited by jakiror; 08-19-2019, 06:18 PM.

                Comment


                  #9
                  Originally posted by Nastymonk View Post
                  It seems that there are two ways to expose functionalities across DLL boundaries. The first one is Module API, which is dllimport/dllexport under the hood. However, in the last several sentences in Unreal Module API, it states that "The API macros are mostly used on older code to allow newer modules to access it from their DLL. In newer bits of code, the API macros are used far less, instead setting up nice interface layers to expose functionality across DLL boundaries."

                  How does this setting up nice interface layers work? Can you provide me with an example? Thank you very much!

                  That's a bit misleading really. It's true they've begun to use the latter approach more, but the bulk of the engine is still reliant on exporting symbols. The interface approach is definitely better where feasible (since you can then use a dynamic dependency making your modules less tightly coupled), but it's far more restrictive. It should be used whenever you have some self contained piece of functionality, service or whatever, that naturally can be exposed through one or more interfaces.

                  In the engine, you can look at the asset registry and asset tools modules as examples. One of my plugins does it here, though it might be a bit convoluted since it was tacked on afterwards.

                  Also be aware that UE4's reflection system doesn't always play nice with this approach. If you have public reflected types, you may find cases where you need a full dependency, when with regular types a dynamic dependency would have worked.

                  Comment

                  Working...
                  X