- Home /
How to exclude code if a certain script is not present in the project.
Hi,
I'm trying to build a tool box with several tools I created and there is some interdependencies between them. I would like to make them fully independant if they are taken seperatly but I would also like to use their full potential if multiples tools are included in the project.
For example, I have a tool A and tool B, they should be able to work seperatly without a problem but if both tools are included in the project, tool B should use some code from A.
It would have been easily fixed if I could add a custom #define but Unity doesn't allow it. I also found about the mcs.rsp file which can be used to add custom defines but it kinda destroys the files organisation, since it must be placed at /Assets/mcs.rsp and I guess there can't be multiple files of this type, so if I have like 10 tools that are interdependent (and should also work seperatly) I don't even know how I could work around with the .rsp files.
Answer by Glurth · Jan 18, 2018 at 03:25 PM
If you compile each module into a DLL, you CAN, in the c# project configuration for the DLL (not a unity project), add your own define symbols. [EDIT:] Keep in mind though, the #if pre-compiler directive, will only be checked when compiling the DLL, NOT when compiling the project that USES the DLLs. This means you might need multiple versions of the dll, which can get ugly.
If you don't want to use DLL's nor change the #define symbols in the Unity project build-settings, you will be forced to do runtme (not complie-time) checks.
Runtime check Options:
You can use reflection to check if a class exists in the current assembly and to invoke it's functions.
Or, without reflection: you can have a single "moduleRegistration" class, (perhaps in it's own dll to avoid .cs file duplication) used by all modules. Each Module can register with this class (probably inside an InitializeOnLoad or a RuntimeInitializeOnLoadMethod, invoked function), or check to see if other modules have been registered with it. This class can also store a set of delegate references, to the various potentially-called functions of each module. These delegates can remain null, in which case they should not be invoked, or be assigned a valid reference when the module registers, in which case they should be invoked. This answer has an example for a similar situation, it conditionally calls some Editor-only functions, but only if running in the editor, not in the final build: https://answers.unity.com/questions/1347169/how-to-conditional-use-of-unityeditor-in-dll.html
Answer by UnityCoach · Jan 18, 2018 at 06:10 PM
Hi,
Unity does allow pre-compiler symbols, you can add them in the Player Settings. This allows you to use either #if define symbols, or code stripping. Although, if your code is pre-compiled into a dll, this won't apply.
That said, I would say that when you decouple modules, making them independent of each other, using an interface is probably the best way to go, although it depends on the context.
Hi Coach, As this is an issue I've been struggling with for a while (with DLL based modules in particular), could I ask you to you go into a little more detail on how one would use an interface to implement something like this? It's probably something obvious, I'm just not seeing it.
Hi, I'm right into the topic actually, hosting a conference on SOLID design and Object Oriented Program$$anonymous$$g at the end of the month.
When you want to "de-couple" modules of a system, you want to make them ignore the existence of each other.
For example, ins$$anonymous$$d of having A know that B exists, you make A know that a "contract" (an interface) exists that can tie the two. And B will commit to that "contract" (implementing the interface).
Codewise, it looks like this :
public interface IGotWheels
{
void ApplyTyreDamage (float amount);
}
public abstract class Vehicle : $$anonymous$$onoBehaviour
{
}
public class Car : Vehicle, IGotWheels
{
public void ApplyTyreDamage (float amount)
{
}
}
public class VehicleController : $$anonymous$$onoBehaviour
{
Vehicle vehicle;
public void ApplyDamage ()
{
if (IGotWheels)vehicle) != null)
((IGotWheels)vehicle).ApplyTyreDamage (damage);
}
}
With the interface and abstract class defined in some "root" module (that all modules use), Car in module one, and VehicleController in module two?
How (other than the inspector) is a "Car" assigned to a VehicleController's vehicle member? That could only be done in module one, where the definition for Car actually exists, right? But that would require module one knows about the VehicleController in module two. Hmmm. What am I missing? Another interface for the vehicle controller, IControlVehicles, in the base module?