Is it possible to inject a component that doesn't have a prefab/GameObject associated with it? - zenject

I have a game object (a cube, let's say) which exists in the scene, and I want it to have an injectable component. I want to be able to say, for example: My cube has an IShotFirer member, which can resolve to either a BoomShotFirer or a BangShotFirer MonoBehavior component, both of which implement IShotFirer. When binding happens, I want this component to be added to the cube object.
public class CubeBehavior : MonoBehaviour
{
[Inject]
private IShotFirer shotFirer;
}
Is it possible to do this without 1) needing an existing prefab which contains one of these Bang/Boom components, or 2) needing an existing scene object which has one of these components attached?
In other words, I want to be able to dynamically add the component to my game object depending on the bindings, and not relying on anything other than the script files which define either BoomShotFirer or BangShotFirer. But the docs seem to imply that I need to find an existing game object or prefab (e.g. using .FromComponentsInChildren(), etc.)

Is it possible to do this without 1) needing an existing prefab which
contains one of these Bang/Boom components, or 2) needing an existing
scene object which has one of these components attached?
Yes, it is.
Zenject provides a host of helpers that create a new components and bind them -- quoting the docs:
FromNewComponentOnRoot - Instantiate the given component on the root of the current context. This is most often used with GameObjectContext.
Container.BindInterfacesTo<BoomShotFirer>().FromNewComponentOnRoot();
FromNewComponentOn - Instantiate a new component of the given type on the given game object
Container.BindInterfacesTo<BoomShotFirer>().FromNewComponentOn(someGameObject);
FromNewComponentOnNewGameObject - Create a new game object at the root of the scene and add the Foo MonoBehaviour to it
Container.BindInterfacesTo<BoomShotFirer>().FromNewComponentOnNewGameObject();
For bindings like this one that create new game objects, there are also extra bind methods you can chain:
WithGameObjectName = The name to give the new Game Object associated with this binding.
UnderTransformGroup(string) = The name of the transform group to place the new game object under.
UnderTransform(Transform) = The actual transform to place the new game object under.
UnderTransform(Method) = A method to provide the transform to use.
That list is not even exhaustive, be sure to check the readme and the cheatsheet (from both of which I have extracted the info above).
Also understand that, as usual, you can append .AsSingle(), .AsTransient() and .AsCached() to achieve the desired result.

Related

Visualization of dynamically created modules

I am building a dynamic multi agent simulation in OMNeT and for this I have to create new modules at runtime. The module creation is working, however, the modules created at runtime are not appearing in the 3D visualization.
module "node" is created sucessfully
Does anyone know how to make the module appear in the visualization? Do I have to update the visualization module?
omnet.ini:
[General]
network = AgentNetwork
*.visualizer.osgVisualizer.typename = "IntegratedOsgVisualizer"
*.visualizer.*.mobilityVisualizer.animationSpeed = 1
*.visualizer.osgVisualizer.sceneVisualizer.typename = "SceneOsgEarthVisualizer"
*.visualizer.osgVisualizer.sceneVisualizer.mapFile = "hamburg.earth"
AgentSpawner:
void AgentSpawner::initialize()
{
cMessage *timer = new cMessage("timer");
scheduleAt(1.0, timer);
}
void AgentSpawner::handleMessage(cMessage *msg)
{
cModuleType *moduleType = cModuleType::get("simulations.Agent");
cModule *module = moduleType->create("node", getParentModule());
// set up parameters and gate sizes before we set up its submodules
module->par("osgModel") = "3d/glider.osgb.(20).scale.0,0,180.rot";
module->getDisplayString().parse("p=200,100;i=misc/aircraft");
module->finalizeParameters();
// create internals, and schedule it
module->buildInside();
module->callInitialize();
module->scheduleStart(simTime()+5.0);
}
The OSG visualization info is maintained totally separately from the actual simulation model module object (that's because the visualization must be ALWAYS optional in the simulation, so make sure your simulation builds fine with OSG totally turned off). This means that an entirely different data structure is built during initialization time from the existing network nodes. As this is done only once during the initialization, dynamically created modules will not have their visualization counterpart data structure.
The code which created the corresponding objects is here.
The solution would be to look up the NetworkNodeOsgVisualizer module in your AgentSpawner code then create and add the corresponding data structures (NetworkNodeOsgVisualization objects). The needed methods (create and add) are there, but sadly they are protected, so you many need to modify the INET code and make them public to be able to call them.

what is a Builder return type in Blackberry10 Cascades

The following is an API reference for a method in "QmlDocument" class(Blackberry10).
Builder create (const QString &qmlAsset, boolautoLoad )
Creates and returns a builder for constructing a QmlDocument instance
with a parent object and an asset name to load the document from.
Parameters qmlAsset The QML asset name load the document from,
specified relative to the assets root. autoLoad if true the document
is automatic loaded, otherwise it is required to call load function
explicitly. The default is true . Since: BlackBerry 10.0.0
Now what is exactly meant by a "Builder" here. What is its purpose? what is the difference of creating an object from QmlDocument class with "new" keyword, and creating the object with the method defined above?
Builders are usually classes defined locally to the associated class (ie QmlDocument::Builder) that allow chaning of methods with operator . () in a way similar to that done with iostreams and operator << (). What it gets you is a more readable way of createing objects (and potentially their childre) in one statment rather than creating with a new operator and a number of function calls. A better example than QmlDocument might be the Container class:
Container *container1 = Container::create()
.preferredSize(200, 200)
.background(Color::Blue);
This creates a new Container, sets the preferred size and background color. The implementations details are hidden. Somewhat simmilar to an opaque type in C.

design pattern for "save"

I'm currently working on a "save" mechanism, which allows a user to save the project his working on on hard disc. The output will be a XML file containing all kinds of data.
Now our project structure is about to change and we need to write a new xml file (create a new save method).
So now here comes the challenge: When saving I want the user to be able to choose which file format he will be creating (version1 (old) or version2 (new)).
Does anyone now how to achieve that? Is there a suitable design pattern around?
Remarks:
- The data we are saving can be seen as unrelated blocks, so it would actually be easy to exchange an old block with a new one.
- The whole goal of the thing is, it should be readable again when loading an old project. (I assume this can be done by tags, and just react on tags when loading?)
This sounds like a good application for the Strategy pattern.
You would create an abstract base class FileFormat (the Strategy interface) with two virtual functions, projectToXml and xmlToProject, which are supposed to turn your internal project representation into XML or vice versa.
Then you create two implementing subclasses FileFormatNew and FileFormatLegacy (these are the concrete strategies).
Your save functions would then additionally require an instance of FileFormat, and call the corresponding method of that object to do the data conversion. Your load function could choose the strategy to use by examining the XML tree for something which tells it which version it is.
And when you ever need to support another file format, you just have to create a new class which is a subclass of FileFormat.
Addendum after the exchange in the comments
When you are going to have a lot of versions with very small differences and you still want to use the Strategy pattern, you could make the FileFormat a composite of multiple strategies: A CircleStragegy, a RectangleStrategy, a LineStrategy etc.. In that case I wouldn't use different classes for different versions of the FileFormat. I would create a static factory function for each version which returns a FileFormat with the Strategy objects used in that version.
FileFormat FileFormat::createVersion1_0() {
return new FileFormat(
new LineStrategyOld(),
new CircleStrategyOld(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_1() {
// the 1.1 version introduced the new way to save lines
return new FileFormat(
new LineStrategyNew(),
new CircleStrategyOld(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_2() {
// 1.2 uses the new format to save circles
return new FileFormat(
new LineStrategyNew(),
new CircleStrategyNew(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_3() {
// 1.3 uses a new format to save rectangles, but we realized that
// the new way to save lines wasn't that good after all, so we
// returned to the old way.
return new FileFormat(
new LineStrategyOld(),
new CircleStrategyNew(),
new RectangleStragegyNew()
);
}
Note: In real code you would of course use more descriptive suffixes than "Old" and "New" for your strategy class names.

loading classes with jodd and using them in drools

I am working on a system that uses drools to evaluate certain objects. However, these objects can be of classes that are loaded at runtime using jodd. I am able to load a file fine using the following function:
public static void loadClassFile(File file) {
try {
// use Jodd ClassLoaderUtil to load class into the current ClassLoader
ClassLoaderUtil.defineClass(getBytesFromFile(file));
} catch (IOException e) {
exceptionLog(LOG_ERROR, getInstance(), e);
}
}
Now lets say I have created a class called Tire and loaded it using the function above. Is there a way I can use the Tire class in my rule file:
rule "Tire Operational"
when
$t: Tire(pressure == 30)
then
end
Right now if i try to add this rule i get an error saying unable to resolve ObjectType Tire. My assumption would be that I would somehow need to import Tire in the rule, but I'm not really sure how to do that.
Haven't use Drools since version 3, but will try to help anyway. When you load class this way (dynamically, in the run-time, no matter if you use e.g. Class.forName() or Jodd), loaded class name is simply not available to be explicitly used in the code. I believe we can simplify your problem with the following sudo-code, where you first load a class and then try to use its name:
defineClass('Tire.class');
Tire tire = new Tire();
This obviously doesn't work since Tire type is not available at compile time: compiler does not know what type you gonna load during the execution.
What would work is to have Tire implementing some interface (e.g. VehiclePart). So then you could use the following sudo-code:
Class tireClass = defineClass('Tire.class');
VehiclePart tire = tireClass.newInstance();
System.out.println(tire.getPartName()); // prints 'tire' for example
Then maybe you can build your Drools rules over the interface VehiclePart and getPartName() property.
Addendum
Above make sense only when interface covers all the properties of dynamically loaded class. In most cases, this is not a valid solution: dynamically loaded classes simply do not share properties. So, here is another approach.
Instead of using explicit class loading, this problem can be solved by 'extending' the classloader class path. Be warn, this is a hack!
In Jodd, there is method: ClassLoaderUtil.addFileToClassPath() that can add a file or a path to the classloader in the runtime. So here are the steps that worked for me:
1) Put all dynamically created classes into some root folder, with the respect of their packages. For example, lets say we want to use a jodd.samples.TestBean class, that has two properties: number (int) and a value (string). We then need to put it this class into the root/jodd/samples folder.
2) After building all dynamic classes, extend the classloaders path:
ClassLoaderUtil.addFileToClassPath("root", ClassLoader.getSystemClassLoader());
3) load class and create it before creating KnowledgeBuilder:
Class testBeanClass = Class.forName("jodd.samples.TestBean");
Object testBean = testBeanClass.newInstance();
4) At this point you can use BeanUtils (from Jodd, for example:) to manipulate properties of the testBean instance
5) Create Drools stuff and add insert testBean into session:
knowledgeSession.insert(testBean);
6) Use it in rule file:
import jodd.samples.TestBean;
rule "xxx"
when
$t: TestBean(number == 173)
then
System.out.println("!!!");
end
This worked for me. Note that on step #2 you can try using different classloader, but you might need it to pass it to the KnowledgeBuilderFactory via KnowledgeBuilderConfiguration (i.e. PackageBuilderConfiguration).
Another solution
Another solution is to simply copy all object properties to a map, and deal with the map in the rules files. So you can use something like this at step #4:
Map map = new HashMap();
BeanTool.copy(testBean, map);
and later (step #5) add a map to Drools context instead of the bean instance. In this case it would be even better to use defineClass() method to explicitly define each class.

Displaying polymorphic classes

I have an existing app with a command-line interface that I'm adding a GUI to. One situation that often comes up is that I have a list of objects that inherit from one class, and need to be displayed in a list, but each subclass has a slightly different way of being displayed.
Not wanting to have giant switch statements everywhere using reflection/RTTI to do the displaying, each class knows how to return its own summary string which then gets displayed in the list:
int position = 0;
for (vector<DisplayableObject>::const_iterator iDisp = listToDisplay.begin(); iDisp != listToDisplay.end(); ++iDisp)
cout << ++position << ". " << iDisp->GetSummary();
Similar functions are there to display different information in different contexts. This was all fine and good until we needed to add a GUI. A string is no longer sufficient - I need to create graphical controls.
I don't want to have to modify every single class to be able to display it in a GUI - especially since there is at least one more GUI platform we will want to move this to.
Is there some kind of technique I can use to separate this GUI code out of the data objects without resorting to RTTI and switch statements? It would be nice to be able to take out the GetSummary functions as well.
Ideally I'd be able to have a heierarchy of display classes that could take a data class and display it based on the runtime type instead of the compile time type:
shared_ptr<Displayer> displayer = new ConsoleDisplayer();
// or new GUIDisplayer()
for (vector<DisplayableObject>::const_iterator iDisp = listToDisplay.begin(); iDisp != listToDisplay.end(); ++iDisp)
displayer->Display(*iDisp);
I don't think this will solve your problem of not needing to write the code, but you should be able to abstract the GUI logic from the data objects.
Look at a Visitor pattern (http://en.wikipedia.org/wiki/Visitor_pattern) it will allow you to add code to an existing object without changing the object itself. You can also change the visitor based on the platform.