Spawn certain type from string - c++

Class World is designed to spawn Actors.
Actors can be different types: it's can be Cat, can be Dog, can be Tree, everything, the only similar thing is that they all derived from Actor.
And there is also command line, it gives World a string where written next things:
what_to_do string_leftover. There if what_to_do equals "Spawn" then first word of string_leftover must be type name, second - Actor name.
The problem is that number of Actors can be indefinite - I don't really sure about their count and I'am really scared of forget to write their Spawn overload manually.
If very simple:
I entered in console: "SelectWorld World1" then "Spawn PhysicalPendulum OneMorePendulum". This will select world named World1 (this is working perfectly) and spawn Actor of type PhysicalPendulum with name OneMorePendulum.
Problem: I can't elegantly determine what type I should spawn from string.
Why:
All solutions I know requires to create "string to type determiners" not in actor-derived class header/object file.
I mean I can use switch (pointer-to-function map), but each time I create new Actor type I need to return to that Spawn function and write down new type to spawnables, there is a slight chance that I can totally forget about it and looooooong time of debugging will be awaiting me.
I can create static class instance with macro, but there is no guarantee that Spawner will be created before this instance initializes.
I thought about tricks with macros, but they can't be extended, like if certain define had "definition_body" I can't add "another_definition_body" to it and get "definition_body another_definition_body".
How can I elegantly spawn type from string?

Declare a global function/macros that will 'register' newly create class to the list of known e.g.
//SpawnActor.h
#pragma once
using std::string;
using std::map;
using std::function;
class Actor;
class ActorSpawner
{
public:
typedef function<Actor()> SpawnFunction;
static void RegisterActorClass(const string& name, const SpawnFunction& function)
{
s_spawnClasses[name] = function;
}
void SpawnClass(const string& name)
{
// You'll need to validate name
Actor* a = s_spawnClasses[name]();
//...
}
private:
static map<string, function<Actor()> s_spawnClasses
};
//SpawnActor.cpp
#include "SpawnActor.h"
map<string, function<Actor()> SpawnFunction::s_spawnClasses();
//TreeActor.h
class TreeActor : public Actor
{
...
};
//TreeActor.cpp
#include "TreeActor.h"
ActorSpawner::RegisterActorClass("TreeActor", [](){return new TreeActor();})

For your code to create an object, you must know the type of the object you are creating. At some point you must say thing* = new Thing()
You can have a factory that knows all the types of objects allowed to be created. If you use a standardised naming convention you can use token pasting. thing* = new Thing ## string_name. i.e. string = "Robot". #define ABC(name) return new Thing ## name. class ThingRobot {}; etc...

Related

(UE4 C++) Converting a data-table row name to a class name to spawn actors

so I'm working on a squad-based strategy game like Company of Heroes. I am currently still building a squad framework that the player will interface with and give orders to. I have decided to use data tables to define the contents of squads and units and have run into trouble figuring out how my CreateUnit function will work (which will handle spawning soldiers on the squad actor’s request). I pass two parameters to it, namely the requested class name in the form of an FName taken from the row name of the data table and the amount of that type that must be spawned. I have run into trouble trying to feed that class name variable into the SpawnActor function. This is a slimmed-down version of the relevant code:
TArray<FName> ClassNames = ContainerDataTable->GetRowNames();
// Call CreateUnit function for every request until squad is full
for (auto& RequestedUnitClass : ClassNames)
{
// Select Row
FUnitContainerData* SelectedRow = ContainerDataTable->FindRow<FUnitContainerData>(RequestedUnitClass, "");
// Find number requested
int AmountToSpawn = SelectedRow->NumberOfUnits;
CreateUnit(RequestedUnitClass, AmountToSpawn);
}
void AUnitContainer::CreateUnit(FName Classname, int Amount)
{
// Determine class from row name
FName RequestedUnitClass = Classname;
// Spawn unit from Class
FActorSpawnParameters SpawnInfo;
RequestedUnitClass* Unit = GetWorld()->SpawnActor<RequestedUnitClass>(RequestedUnitClass::StaticClass(), SpawnLocation, SpawnRotation, SpawnInfo);
The Issue I’m having is that the variable RequestedUnitClass is not accepted as part of the arguments of the SpawnActor function. I'm still learning C++ and it seems to me that I am simply passing on the wrong data. I would like to use Row names as variables for class names but is that even possible? Like a row named SoldierType1 would spawn the class named SoldierType1 when parsed, with corresponding data (in this case, how many need to be spawned).
Looking at the function definition for UWorld::SpawnActor from the documentation,
template<class T>
T * SpawnActor
(
UClass * Class,
FVector const & Location,
FRotator const & Rotation,
const FActorSpawnParameters & SpawnParameters
)
the function does not take a parameter of type FName so you will have to replace that since the other three parameters seem to be correct. Also, your template parameter has to be an actual class and the first function parameter has to be of type UClass*. Right now, you have a variable of type FName for both which is incorrect. Therefore, you should replace your TArray<FName> ClassNames variable with a TArray<TSubclassOf<AActor>> Classes variable so that RequestedUnitClass is of type UClass*. You would have to modify your ContainerDataTable->GetRowNames() function to return a variable of type TArray<TSubclassOf<AActor>> as well for this to work.
When calling SpawnActor, you would use AActor for the template parameter. Note that I am only using AActor for the template parameter for both TSubclassOf and SpawnActor because I'm assuming that your array can refer to a variety of actor classes so I wanted to be as general as possible. Then for the UClass* parameter that the SpawnActor function takes, RequestedUnitClass should now work. Since I'm assuming that you don't want each actor spawned to be a general AActor all the time, you can cast the result to a a specific class after spawning the actor, but I will leave that up to you.
AActor* Unit = GetWorld()->SpawnActor<AActor>(RequestedUnitClass, SpawnLocation, SpawnRotation, SpawnInfo);
...
// do some IsA class checks to figure out which class to cast the actor to

Create class instance based on a string input

Background:
In my game engine I have a generic 'script parser' which is used to create game entities by parsing a script file. So in code you would have something like MyEntity* entity = MyScriptParer::Parse("filename.scr");
Any class which is to be scriptable inherits from a generic base class. Internally in the game engine there are some specific classes that use this - particles, fonts etc and this all works nicely in the parser - see extract below
std::string line;
std::getline(ifs, line);
if (line == "[FONT]") {
CFont* f = new CFont();
f->readObject(ifs);
}
else if (line == "[PARTICLE]") {
CParticle* p = new CParticle();
p->readObject(ifs);
}
...
My problem comes with how to handle user defined classes i.e classes in the games that use the game engine. The base class has an abstract method readObject so anything which inherits must implement this method.
The issue is how would the parser know about the new class? E.g say I have a CVehicle class the parser would now need to know to recognise "[VEHICLE]" and also be able to create a new CVehicle
Is there any way to store a class type or something in an array/map so maybe I could have a function to register a list of class types with strings to provide a lookup for creating the new instances?
Bit of a long shot and may not be possible so if anyone has other suggestions on how to approach the parsing they will be welcomed
You can store a class type in an array/map via std::type_info
However, you cannot create a type from this, as it would require more RTTI than is available in C++. (like reflection in .NET).
However, you could store a function pointer to a class factory in such a map.
I.e.
typedef CBaseClass* (*pfnCreateClass)();
std::map<std::string, pfnCreateClass> mapCreate;
// Registering
// CMyCustomClass::GetClass() is a static method that creates a CMyCustomClass
mapCreate.insert(std::pair<std::string, pfnCreateClass>("[CUSTOM_CLASS]", CMyCustomClass::GetClass));
// Get class
std::map<std::string, pfnCreateClass>::const_iterator it = mapCreate.find(line);
if(mapCreate.end() != it)
{
CBaseClass *p = it->second();
p->readObject(ifs);
}
Just have the function to register a new type take in the name of the type and a function for creating the type.
Something like so:
void RegisterType( std::string name, std::function< BaseType() > createFunc );
When registering a new type you do it like so:
RegisterType( "Vehicle", [](){ return new CVehicle; } );
That way the parser can create all the derived types.

Hash table of "classes" (not objects) in C++

I need to make, for my college homework, an interpreter in C++ for a language based on functions (or commands). The interpreter has got to read an input file, extract the words (strings), generate the commands and execute them. All commands are classes which inherit from a common super-class (Command, for example), which's got a virtual method called execute. For each word read from the input file, a command is created and stored in a vector<Command>.
So, I'm thinking of using a hashtable, whose keys are the names of the commands (strings) and whose values are some kind of objects which allow me to create an specific class (or give me access to the constructor of an specific class), to easily create the classes for each word instead of using a chain of if-else-if's.
By now, I'm planning to create a CommandGenerator class with a virtual method called generate which returns a new Command object. The values of my commands hash table will be objects of theCommandGenerator class. So I derive from it many other subclasses for all commands, which return specific new objects derived from Command.
But, does anything like that already exist? Or is there any more elegant way to do that? Is there any kind of object that can be extracted from a class to represent it?
If each command is a subclass of Command, why don't you use a std::vector<Command*> and push pointers to instances of each subclass? Then you can iterate over the vector and call your virtual execute function.
The closest thing you can get about placing classes in a vector is boost::fusion::vector. But can't be filled at runtime, no use on your specific case.
Assuming you can use C++11. If you can define commands as just a execute function, you can do something like:
map<string, function<void()>> cmds = {
make_pair("print1", [](){
cout << "1" << end;
}),
make_pair("print2", [](){
cout << "2" << end;
}),
make_pair("print3", [](){
cout << "3" << end;
})
};
And then put the command on a vector with:
vector<function<void()>> list;
list.push_back(cmds["print1"]);
list.push_back(cmds["print1"]);
list.push_back(cmds["print2"]);
Then just execute with a loop:
for (function<void()>& cmd : list)
cmd();
This should print 112 to screen. But if you care a lot with speed, do a lot of ifs instead.
The basic problem you have is: You have the name of the class as a string and want to create a class with that name. This translation you have to do somehow manually, like you mentioned. This has been discussed here several times, like in Instantiating classes by name with factory pattern or in Looking for a better C++ class factory. The only addition I would make here: use good old macros, because they have a stringize-operator. E.g.:
#include <stdio.h>
#define CREATEOBJ(clss,command) if (strcmp (#clss, command)==0) return new clss;
class Base {
public:
virtual const char *name()=0;
};
class A : public Base {
public:
const char *name() {return "I am an A";}
};
class B : public Base {
public:
const char *name() {return "I am an B";}
};
Base *makeInstance (const char *nm) {
CREATEOBJ(A,nm);
CREATEOBJ(B,nm);
}
int main () {
printf ("%s\n", makeInstance ("A")->name());
printf ("%s\n", makeInstance ("B")->name());
}
of course you can make it nicer by using a hash-table containing the strings and some function-pointer or generator-class pointer, but the idea remains the same: to add a new class, just add one more CREATEOBJ-thingy.

Efficient way to generate id unique to class?

Is there any efficient way in C++ of generating an ID unique to the class, not to the instance? I'm looking for something of this level of simplicity (this generates an ID for every instance, not for every class type):
MyClass::MyClass()
{
static unsigned int i = 0;
id_ = i++;
}
Edit: Why I want unique IDs.
I'm writing a game. All entities in my game will have different states they can be in (walking left, jumping, standing, etc); these states are defined in classes. Each state needs to have its own ID so I can identify it.
You can try this, but it's not-deterministic.
int id_count = 0;
template <typename T>
int get_id()
{
static int id = id_count++;
return id;
}
Then just use:
get_id<int>(); // etc.
Of course, this isn't thread safe.
Again, it's not deterministic: the IDs are generated the first time you call the function for each type. So, if on one run you call get_id<int>() before get_id<float>() then on another run you call them the other way round then they'll have different IDs. However, they will always be unique for each type in a single run.
Basically you are asking for a custom rolled RTTI solution, that you can selectively apply to classes.
This can start from very crude preprocessor stuff like :
#define DECLARE_RTTI_CLASS(a) class a { \
inline const char * class_id() { return #a };
.. to a more sophisticated solutions that track inheritance etc, essentially partially duplicating compiler RTTI functionality. For an example, see Game Programming Gems #2, Dynamic Type Information
Previous discussions on gamedev on the same subject are also worth reading
Use your MyClass as a primitive, and incorporate a static instance of one into each class you want to ID.
class MyOtherClass1 {
static MyClass id;
};
class MyOtherClass2 {
static MyClass id;
};
[etc.]

Dynamic creating of typedef

I'm creating event system. It's based under boost::signals. To make the work easier I'm using typedef for the function signatures.
Everything is okey until I need creating of some new event trought event's system method. I have to create the typedef dynamically on given type to the template function. The problem is the name of typedef.
Some pseudocode I would have:
template<typename EventType>
void create(const string &signalName)
{
typedef EventType signalName;
// ...
}
Is it possible to make such typedef (their names) with some passed string or data or something else? I don't want to make user care about of this.
UPD: So, I have some typedefs list of function signatures - events. I have some templated function for connecting slots, for example. I don't want to force user to input signature by his hands again every time (user is programmer which will use the event system). So I just use my typedefs from special namespace into template argument.
typedefs only matter during compilation. As far as I know it's just an alias for a type.
Template parameters are, by definition, compile time entities. You can not dynamically create template classes on the fly during program execution as far as I am aware.
In this case, I wouldn't go for typedef's. If you want to have several types of events and create them dynamically, you can use a simple class containing the information about the event type. When you have an event, you link it to the event type created before.
Something like this:
class EventType
{
private:
string type;
EventType(string type);
};
class Event
{
private:
string event_name;
EventType *event_type;
Event(string event_name, EventType event_type);
};
...
void create(const string &signalName)
{
EventType *event_type = new EventType("type_x");
Event *event = new Event("event_x", event_type);
}