Getting going after set-up
I thought I'd start a new thread to ask a few questions that don't seem to be covered in the FAQ. Forgive me if they are.
Do you know of a simple way to create a solution file for the project?
Is there a way for me to clone your git repository across services? (I use GitHub).
How do I compile the games and run them without needing the source code?
While I am prototyping the game, I'd like to be able to share it with friends so they can run it and give me feedback.
Also is there an easier way to run the tools?
It would be nice just to be able to compile the tools as stand-alones to make development easier.
The GUI scripts appear to be in lua, but they are in a custom file format. Is there a reason they do not have the .lua extension?
Are entity hierarchies still available?
While I understand the concept of the component system, it too has it's drawback without class hierarchies. For example, to implement a version of TF2, with it's 9 players classes, I would need to create 9 individual, often complicated, component systems, that are largely the same. Some degree of hierarchy is needed to utilise fully scalability. I may have misunderstood, but as far as I can tell, you have switch to a component only system?
There is currently no team component, while I could in theory (eventually) create something in lua, would this be better implemented in the entity system?
It may not be worth it, although I don't know if lua can effect the entities used in the editor yet (team spawns), I haven't got that far
I am really loving the work you have done, and once I get going properly, I will be excited to see what I can create.
I like to give myself little challenges to spur my development, so I have decided to make a new mod to add to the current tech demo. Again, it will be nice and simple, as this is my first attempt at building a game from the ground up, but it will be an interesting experience. It may also take some time..
Do you know of a simple way to create a solution file for the project?
Is there a way for me to clone your git repository across services? (I use GitHub).
How do I compile the games and run them without needing the source code?
While I am prototyping the game, I'd like to be able to share it with friends so they can run it and give me feedback.
Also is there an easier way to run the tools?
It would be nice just to be able to compile the tools as stand-alones to make development easier.
The GUI scripts appear to be in lua, but they are in a custom file format. Is there a reason they do not have the .lua extension?
Are entity hierarchies still available?
While I understand the concept of the component system, it too has it's drawback without class hierarchies. For example, to implement a version of TF2, with it's 9 players classes, I would need to create 9 individual, often complicated, component systems, that are largely the same. Some degree of hierarchy is needed to utilise fully scalability. I may have misunderstood, but as far as I can tell, you have switch to a component only system?
There is currently no team component, while I could in theory (eventually) create something in lua, would this be better implemented in the entity system?
It may not be worth it, although I don't know if lua can effect the entities used in the editor yet (team spawns), I haven't got that far
I am really loving the work you have done, and once I get going properly, I will be excited to see what I can create.
I like to give myself little challenges to spur my development, so I have decided to make a new mod to add to the current tech demo. Again, it will be nice and simple, as this is my first attempt at building a game from the ground up, but it will be an interesting experience. It may also take some time..
Re: Getting going after set-up
Hi SoulRider,
Nothing else is needed, Cafu is "portable" by design, but the "debug" builds can consume a lot of disk space.
To fight this, you could create release builds only, e.g. clone again into a separate directory, but before the first run of SCons, modify
Yet another option is to use the
(If syntax highlighting is a problem, most editors should be able to be taught which type of highlighting to apply to which file extension...)
More generally, and for completeness, I must add that the human player is certainly the most complex of all entities. Even in the simple DeathMatch game, where a player can pick up weapons and carry several of them, the resulting code is more complex than it initially seems -- and (to the best of my understanding) not very predisposed or even halfway suitable to be easily broken into components (which are normally intended to be largely independent from each other).
For example, whatever weapon the player currently holds, it affects both its 3rd person weapon model (that other players see), its 1st person weapon model (that we ourselves see), it can be reloaded from or restock (when picked up) one of more ammo slots in our inventory (but other weapons may use the same ammo slots as well), and implementing features like "switch to the next 'suitable' or 'similar' weapon" can require a global overview of all of the players inventory and available weapons, there are holster and draw animations to account for, etc. etc.
So the details can be tricky. Therefore, with the DeathMatch MOD, I currently plan to put most of this (the weapon handling) into a single, monolithic component. (But I'm open to and happy to hear suggestions about this!) Btw., both the old and the new DeathMatch code uses a class hierarchy for "carried weapons" (often abbreviated "cw" in the code).
Based on this, in your version of TF2, it looks to me as if this was one of the very few areas where C++ programming would be the right (or in fact, mandatory) tool for making a player component that can handle all the weapons and player classes. You would of course be able to use any C++ technology (especially class hierarchies) that helps achieving this.
New thread for new (set of) questions is always a good idea, !SoulRider wrote:I thought I'd start a new thread
Unfortunately, no. See Where are the Visual Studio project files? and IDEs and Text Editors for some info about this.Do you know of a simple way to create a solution file for the project?
I'm by no means a Git expert, but this should be easy. Just add your (initially empty) GitHub repository as another remote to your local clone of the Cafu repository. You should then be able to push the branches into the GitHub remote repository.Is there a way for me to clone your git repository across services? (I use GitHub).
The by far easiest way is probably to copy the entire Cafu (top-level) directory onto an USB stick.How do I compile the games and run them without needing the source code?
Nothing else is needed, Cafu is "portable" by design, but the "debug" builds can consume a lot of disk space.
To fight this, you could create release builds only, e.g. clone again into a separate directory, but before the first run of SCons, modify
CompilerSetup.py(.tmpl)
regarding the buildVariants
setting.Yet another option is to use the
make_binary.py
script from https://bitbucket.org/cafu/tools, but this too is still tailored to the master
branch, and may or may not work with entity-component-system
as-is.If I understood your question right, please check out my recent reply to Andrey, where I have answered the same question, too.Also is there an easier way to run the tools?
It would be nice just to be able to compile the tools as stand-alones to make development easier.
Just historical: They did not use to be Lua, and have become "true" Lua scripts only later.The GUI scripts appear to be in lua, but they are in a custom file format. Is there a reason they do not have the .lua extension?
(If syntax highlighting is a problem, most editors should be able to be taught which type of highlighting to apply to which file extension...)
The component system will no longer feature "entity (C++) class hierarchies", but that should not be a limiting factor: Components, of which entities are now composed, are normal, plain C++ classes. They themselves can form class hierarchies, and/or they can hold member variables who in turn can belong to class hierarchies.Are entity hierarchies still available?
While I understand the concept of the component system, it too has it's drawback without class hierarchies. For example, to implement a version of TF2, with it's 9 players classes, I would need to create 9 individual, often complicated, component systems, that are largely the same. Some degree of hierarchy is needed to utilise fully scalability. I may have misunderstood, but as far as I can tell, you have switch to a component only system?
More generally, and for completeness, I must add that the human player is certainly the most complex of all entities. Even in the simple DeathMatch game, where a player can pick up weapons and carry several of them, the resulting code is more complex than it initially seems -- and (to the best of my understanding) not very predisposed or even halfway suitable to be easily broken into components (which are normally intended to be largely independent from each other).
For example, whatever weapon the player currently holds, it affects both its 3rd person weapon model (that other players see), its 1st person weapon model (that we ourselves see), it can be reloaded from or restock (when picked up) one of more ammo slots in our inventory (but other weapons may use the same ammo slots as well), and implementing features like "switch to the next 'suitable' or 'similar' weapon" can require a global overview of all of the players inventory and available weapons, there are holster and draw animations to account for, etc. etc.
So the details can be tricky. Therefore, with the DeathMatch MOD, I currently plan to put most of this (the weapon handling) into a single, monolithic component. (But I'm open to and happy to hear suggestions about this!) Btw., both the old and the new DeathMatch code uses a class hierarchy for "carried weapons" (often abbreviated "cw" in the code).
Based on this, in your version of TF2, it looks to me as if this was one of the very few areas where C++ programming would be the right (or in fact, mandatory) tool for making a player component that can handle all the weapons and player classes. You would of course be able to use any C++ technology (especially class hierarchies) that helps achieving this.
In C++, yes.There is currently no team component, while I could in theory (eventually) create something in lua, would this be better implemented in the entity system?
Dynamically, not yet. Later, it is planned and should be possible to launch the game (even if without pre-rendered lightmaps, and possibly at reduced performance) directly in the Map Editor.It may not be worth it, although I don't know if lua can effect the entities used in the editor yet (team spawns), I haven't got that far
It's great to hear that! As I mentioned in my recent reply to Andrey linked above, we're in the midst of the largest changes that Cafu has ever undergone. As long as you can tolerate the occasional frustration resulting from that, it will certainly work out!I like to give myself little challenges to spur my development, so I have decided to make a new mod to add to the current tech demo. Again, it will be nice and simple, as this is my first attempt at building a game from the ground up, but it will be an interesting experience. It may also take some time..
Best regards,
Carsten
Carsten
Re: Getting going after set-up
Thanks for the replies. Here are a couple of clarifications
For me, the ideal solution would be to create the entity as is done currently, then from that entity component data, build a base class in lua. So human player would be as it is, the entity components loaded into the lua script, then the components are created within a class that can be sub classed in lua.
Is this possible currently?
As a complete non-experienced programmer, spending 2.5 years doing that taught me a few things about dealing with ever changing code bases, but the beauty here is I get to go to the next stage. I was modifying ns2 as it was built from this level up, now I am building a game from this level up, that is exciting. I'd rather leave the C++ editing for my 2nd game, as I think mastering lua is going to be the most important part of this challenge
I don't see my question explained there. Normally, when you write an application, you can build it into an executable for release to the general public. It would be easier for development of games if the world editor could be compiled into a standalone tool. This could then be passed out to mappers and texture artists to work on games, without needing all the source code and complicated instructions that go with it. As an example, I just mentioned class hierarchies to my texture guy, and he said 'it sounds like Latin to me'. He certainly wouldn't be able to build the game and run it himself. While I understand the portability is a great benefit, sometimes an exe is easierIf I understood your question right, please check out my recent reply to Andrey, where I have answered the same question, too.
I still am going over this system and re-reading as it is new to me, so it is taking a little while to sink in. The TF2 was a simple example, I should have used NS2, you have Entity>ScriptActor>Player>Alien>AlienClass. While All components behind player can be used as components, all parts after really need a hierarchical system.The component system will no longer feature "entity (C++) class hierarchies", but that should not be a limiting factor: Components, of which entities are now composed, are normal, plain C++ classes. They themselves can form class hierarchies, and/or they can hold member variables who in turn can belong to class hierarchies.
Based on this, in your version of TF2, it looks to me as if this was one of the very few areas where C++ programming would be the right (or in fact, mandatory) tool for making a player component that can handle all the weapons and player classes. You would of course be able to use any C++ technology (especially class hierarchies) that helps achieving this.
For me, the ideal solution would be to create the entity as is done currently, then from that entity component data, build a base class in lua. So human player would be as it is, the entity components loaded into the lua script, then the components are created within a class that can be sub classed in lua.
Is this possible currently?
I started playing NS2, when all they had released was a box with a rifle and some pop-up targets. I have been modding NS2, since before all the playable characters existed in the game, through weekly updates changing the whole content structure, sometimes completely rewriting how a function worked, or indeed even whole classes!As I mentioned in my recent reply to Andrey linked above, we're in the midst of the largest changes that Cafu has ever undergone. As long as you can tolerate the occasional frustration resulting from that, it will certainly work out!
As a complete non-experienced programmer, spending 2.5 years doing that taught me a few things about dealing with ever changing code bases, but the beauty here is I get to go to the next stage. I was modifying ns2 as it was built from this level up, now I am building a game from this level up, that is exciting. I'd rather leave the C++ editing for my 2nd game, as I think mastering lua is going to be the most important part of this challenge
Re: Getting going after set-up
Hi SoulRider,
What can be called a "downside" in all cases is that our programs must load resources (textures, icons, sounds, maps), which are located in files on disk, in directories like
So... I'm still not sure... would it help if I revised the
More specifically, back to the Alien example hierarchy that you outlined above: Does this hierarchy have additional classes, i.e. what other classes derive from Player, Alien, AlienClass? It seems useful to me if we discussed an example that is slightly larger than this, i.e. an example where classes have more child-classes than one?
For example, with the component system, a human player entity will, among others, have a Model component for its body model, a Sound component for footstep sounds, and more components e.g. for physics, collision, etc. You would be able to access these components from Lua script, and deal with them as desired.
The human player would also and unconditionally have a Script component, which is the most important piece for custom Lua scripting. In it, you can do anything: Control the behavior of the player, access or modify all other components, and if desired, store any extra data that you need and that is not yet kept in any of the components.
Well, this all feels quite abstract to me, and I'd certainly be happy if we had something more concrete to discuss it.
Ok, I see, but stand-alone tools is exactly what we have. TheSoulRider wrote:Normally, when you write an application, you can build it into an executable for release to the general public. It would be easier for development of games if the world editor could be compiled into a standalone tool. This could then be passed out to mappers and texture artists to work on games, without needing all the source code and complicated instructions that go with it.
make_binary.py
script that I mentioned above is used for preparing our binary, ready-to-use, stand-alone releases. What is essentially does is this:- compile from source code as you did by hand,
- copy the
exe
files from thebuild/.../release
directories to the top-level directory (so that you can double-click them, and the path is immediately right ), - delete the
build
and source-code directories.
What can be called a "downside" in all cases is that our programs must load resources (textures, icons, sounds, maps), which are located in files on disk, in directories like
Fonts
or Games
below the Cafu "root" or top-level directory. All programs must be able to find these directories, without which they are indeed not stand-alone.So... I'm still not sure... would it help if I revised the
make_binary.py
script, making sure is good for use with the entity-component-system
branch, so that you can use it to built a binary, self-contained release for others?First a general note : Please believe me that I was one of the strongest defenders and proponents of classic C++ class hierarchies, but no longer am. I did not swing into the full opposite though, and certainly can see that class hierarchies in game entity programming can still be useful, but now that I've fully understood the idea and seen the pro's (and also a few smaller con's), it seems to me as if almost anything can be done with components, and in a better way. But in any case, I'm not fixated on anything here, and I'm perfectly sure that we can get things just right.I still am going over this system and re-reading as it is new to me, so it is taking a little while to sink in. The TF2 was a simple example, I should have used NS2, you have Entity>ScriptActor>Player>Alien>AlienClass. While All components behind player can be used as components, all parts after really need a hierarchical system.
More specifically, back to the Alien example hierarchy that you outlined above: Does this hierarchy have additional classes, i.e. what other classes derive from Player, Alien, AlienClass? It seems useful to me if we discussed an example that is slightly larger than this, i.e. an example where classes have more child-classes than one?
I'm not sure what you try to achieve...For me, the ideal solution would be to create the entity as is done currently, then from that entity component data, build a base class in lua. So human player would be as it is, the entity components loaded into the lua script, then the components are created within a class that can be sub classed in lua.
Is this possible currently?
For example, with the component system, a human player entity will, among others, have a Model component for its body model, a Sound component for footstep sounds, and more components e.g. for physics, collision, etc. You would be able to access these components from Lua script, and deal with them as desired.
The human player would also and unconditionally have a Script component, which is the most important piece for custom Lua scripting. In it, you can do anything: Control the behavior of the player, access or modify all other components, and if desired, store any extra data that you need and that is not yet kept in any of the components.
Well, this all feels quite abstract to me, and I'd certainly be happy if we had something more concrete to discuss it.
Wow, thanks for that info, it sounds very good!I started playing NS2, when all they had released was a box with a rifle and some pop-up targets. I have been modding NS2, since before all the playable characters existed in the game, through weekly updates changing the whole content structure, sometimes completely rewriting how a function worked, or indeed even whole classes!
As a complete non-experienced programmer, spending 2.5 years doing that taught me a few things about dealing with ever changing code bases, but the beauty here is I get to go to the next stage. I was modifying ns2 as it was built from this level up, now I am building a game from this level up, that is exciting. I'd rather leave the C++ editing for my 2nd game, as I think mastering lua is going to be the most important part of this challenge
Best regards,
Carsten
Carsten
Re: Getting going after set-up
That would be brilliant. It would make it much easier for me to get things developed and tested. It's good to know these features already exist, it's just getting to know about themCarsten wrote: So... I'm still not sure... would it help if I revised the make_binary.py script, making sure is good for use with the entity-component-system branch, so that you can use it to built a binary, self-contained release for others?
For me, the ideal solution would be individual distributable .exe files for CaWE, Ca3DE. I would be able to then bundle these into an installer, or just share the files in a zip, for people to use. I would just create the following folder structure:
GameName\
Fonts
Games
Misc
CaWE.exe
Cafu.exe
If there are any other files or folders needed, just let me know and I'll add them to the list.
The only thing that is going to be a little difficult is getting the maps compiled. Is there anyway to make map compiling a function of CaWE?
Here is the full class system for Players on NS2. Root > Child - ChildCarsten wrote: More specifically, back to the Alien example hierarchy that you outlined above: Does this hierarchy have additional classes, i.e. what other classes derive from Player, Alien, AlienClass? It seems useful to me if we discussed an example that is slightly larger than this, i.e. an example where classes have more child-classes than one?
Player > Marine - Alien - Spectator - Commander - ReadyRoom Player - Exo
Marine > JetPackMarine
Alien > Skulk - Lerk - Fade - Onos
Spectator > TeamSpectator - FilmSpectator - GUISpectator
Commander > AlienCommander - MarineComander
TeamSpec > AlienSpectator - MarineSpectator
That is the class structure NS2 used from Player down.
In NS2 the full path is Entity>ScriptActor>Player>etc.
Note that only the Entity class is a C++ engine class, all the further code is created entirely openly in lua. This is what is causing me a little confusion, as previously I've not had to touch C++, and now in Cafu HumanPlayer (Marine equivalent), is in C++. It is quite a separation for me, and it will take me a little time to get used to. C++ is much less forgiving than lua
Re: Getting going after set-up
Hi SoulRider,
If you don't mind the extra bandwidth, pick up one of the binary releases from the Downloads page. Each of these essentially is a "minimal binary" / "minimal stand-alone" edition, without source code, but with texture images, sounds, precompiled maps, and other auxiliary files that are needed. These may give you an idea what to expect.
The earlier mentioned command-line call is quasi in the mid between these two approaches, i.e. the hand-made "raw" calls to the individual map compilers, and the convenient method in CaWE.
Originally, when I asked for a larger example, I was hoping to be able to use that example in a step-by-step, tutorial-like manner to demonstrate how you would be able to implement, what the classic class hierarchy achieved, in terms of the Component System. I'm still 100% positive that that is possible, but it looks to me that I don't know enough about the NS2 code to conduct this "tutorial" in a convincing manner at the abstract level that would be necessary at this point.
Just let me try to summarize, very briefly and certainly incomplete / not exhaustive: With the Component System, if the entity is represented by a model, it has a Model component. If it makes a sound, it has a Sound component, and so on. This is true for all types (classes) of entity: monsters, human players, ...
What really distinguishes monster-type "A" from monster-type "B" from human players is their "behavior". And for this, we have Script components, which bring you immediately into Lua, so that from there on, you're free to implement the entity behavior as your heart desires (and also e.g. to configure the Model and Sound components...).
Also, don't get distracted by the fact that you've seen the Human Player code implemented in C++ already. That is (very) old code. It may happen that one of my next steps is nothing more than moving that very code into a component -- where it is C++ as well. But that would only happen to buy me some extra time and freedom to deal with other details first, such as a consideration of the ramifications of the client prediction feature. Eventually, the Human Player behavior code will be implemented in Lua, hopefully sooner rather than later. In fact, the plan is to be able to make new games with Cafu without being required to write new C++ code for it (but you can if you want, as my first Human Player implementation in the Component System may likely prove ). The Script components are the game developer's C++-to-Lua "interface" in that regard.
Btw., I plan to hide the 3rd person player model that can currently wrongly be seen, and I also plan to fast-forward branch
Ok. I started looking into this, and although the existingSoulRider wrote:That would be brilliant. It would make it much easier for me to get things developed and tested. It's good to know these features already exist, it's just getting to know about themCarsten wrote: So... I'm still not sure... would it help if I revised the make_binary.py script, making sure is good for use with the entity-component-system branch, so that you can use it to built a binary, self-contained release for others?
make_binary.py
script works, I still want to make a couple of changes to it (that will also help with future steps towards "continuous integration"), and break it into smaller, individual parts that are more easily reused on their own (e.g. for turning an existing repository checkout that is already built and equipped with textures and world etc. into a binary-only release).Yes, that's essentially what it amounts to. However, as I mentioned earlier, there are still several "dependencies" (images, maps, ...) that we cannot do without, so besides the .exe files, these must all be there as well.For me, the ideal solution would be individual distributable .exe files for CaWE, Ca3DE. I would be able to then bundle these into an installer, or just share the files in a zip, for people to use. I would just create the following folder structure: [...]
If you don't mind the extra bandwidth, pick up one of the binary releases from the Downloads page. Each of these essentially is a "minimal binary" / "minimal stand-alone" edition, without source code, but with texture images, sounds, precompiled maps, and other auxiliary files that are needed. These may give you an idea what to expect.
Yes, please check out where additional info is provided (I've not yet proof-read these texts and functionality with theThe only thing that is going to be a little difficult is getting the maps compiled. Is there anyway to make map compiling a function of CaWE?
entity-component-system
branch, though.)The earlier mentioned command-line call
Code: Select all
python Games\DeathMatch\compileMaps.py BPRockB
Ok, many thanks for the details!Here is the full class system for Players on NS2. [...]Carsten wrote: [...] It seems useful to me if we discussed an example that is slightly larger than this, i.e. an example where classes have more child-classes than one?
Originally, when I asked for a larger example, I was hoping to be able to use that example in a step-by-step, tutorial-like manner to demonstrate how you would be able to implement, what the classic class hierarchy achieved, in terms of the Component System. I'm still 100% positive that that is possible, but it looks to me that I don't know enough about the NS2 code to conduct this "tutorial" in a convincing manner at the abstract level that would be necessary at this point.
Just let me try to summarize, very briefly and certainly incomplete / not exhaustive: With the Component System, if the entity is represented by a model, it has a Model component. If it makes a sound, it has a Sound component, and so on. This is true for all types (classes) of entity: monsters, human players, ...
What really distinguishes monster-type "A" from monster-type "B" from human players is their "behavior". And for this, we have Script components, which bring you immediately into Lua, so that from there on, you're free to implement the entity behavior as your heart desires (and also e.g. to configure the Model and Sound components...).
I don't think that that will be a problem. Right now, I work as quickly as possible to implement the Human Player code in Lua -- that is the gist of the entity Component System, after all. Ideally, if you were to re-make NS2 with Cafu, you would and should be able to implement all of the above in Lua, too.Note that only the Entity class is a C++ engine class, all the further code is created entirely openly in lua. This is what is causing me a little confusion, as previously I've not had to touch C++, and now in Cafu HumanPlayer (Marine equivalent), is in C++. It is quite a separation for me, and it will take me a little time to get used to. C++ is much less forgiving than lua
Also, don't get distracted by the fact that you've seen the Human Player code implemented in C++ already. That is (very) old code. It may happen that one of my next steps is nothing more than moving that very code into a component -- where it is C++ as well. But that would only happen to buy me some extra time and freedom to deal with other details first, such as a consideration of the ramifications of the client prediction feature. Eventually, the Human Player behavior code will be implemented in Lua, hopefully sooner rather than later. In fact, the plan is to be able to make new games with Cafu without being required to write new C++ code for it (but you can if you want, as my first Human Player implementation in the Component System may likely prove ). The Script components are the game developer's C++-to-Lua "interface" in that regard.
Btw., I plan to hide the 3rd person player model that can currently wrongly be seen, and I also plan to fast-forward branch
master
to entity-component-system
soon, then delete branch entity-component-system
. This is because plenty of fixes have accumulated in entity-component-system
that really everyone should get, and it seems better to me if you all don't stick back on previous revisions... I'll let you know explicitly when that's ready.Best regards,
Carsten
Carsten
Re: Getting going after set-up
Thanks for all your replies.
I am just reading things and going backwards and forwards in the code. I now have a much better understanding of the component system, I now understand it to work very much like the mixin system used in NS2, but to a much higher level. I am really excited by this.
The only issue I have currently is not understanding the syntax and rules of C++. My current challenge is to implement a Team component into the engine. It is supposed to be a very basic component which just holds a team number.
I used the CompBasics as a base, and while I understand the majority of it, getting it to work is proving harder than I first thought. I will get there eventually, I am just currently reading through the internet trying to get explanations about the parts of the code I don't understand
I am really excited about this, and I am also learning that a large majority of my issues are coming from my lack of understanding of the finer details of programming, rather than the functionality of the code in the engine, so forgive me if some of my questions seem a bit confusing at times
I am just reading things and going backwards and forwards in the code. I now have a much better understanding of the component system, I now understand it to work very much like the mixin system used in NS2, but to a much higher level. I am really excited by this.
The only issue I have currently is not understanding the syntax and rules of C++. My current challenge is to implement a Team component into the engine. It is supposed to be a very basic component which just holds a team number.
I used the CompBasics as a base, and while I understand the majority of it, getting it to work is proving harder than I first thought. I will get there eventually, I am just currently reading through the internet trying to get explanations about the parts of the code I don't understand
I am really excited about this, and I am also learning that a large majority of my issues are coming from my lack of understanding of the finer details of programming, rather than the functionality of the code in the engine, so forgive me if some of my questions seem a bit confusing at times
Re: Getting going after set-up
To further expand on my new understanding of the component system, I thought I'd post a simple example that highlights both the similarities and differences between the NS2 implementation and the Cafu implementation. This will expand on what I currently understand, and also issues I face between the two engines. In this example I will use the concept of Teams.
In NS2 there is a lua script class called Team.lua. It won't make total sense as it calls global variables etc, but you should be able to get the gist of what it does from the variable names anyway:
I understand this class, and it's sub-classes could all be implemented in scripts in Cafu as well. The class system is as follows:
Team > Playing Team - Spectating Team - Ready Room Team
Playing Team > Marine Team - Alien Team
So that is the team code created, but entities still need to be assigned to a team. In NS2, this is controlled by what they call a 'Mixin'. I know this is not the correct term neccesarily, but it works. This TeamMixin is called by entities that are on a team and sets the teamNumber Network Variable that is defined in the Mixin. As I understand it, this use of a Mixin is equivalent to a component in Cafu.
However, this is where the simlilarities end and the difference begins. NS2 mixins are not written in the engine in C++, they are all written in lua. The engine has an API that hooks into certain elements, but all of what you seem to be defining as components in C++ are defined as mixins in lua. As as example, here is the TeamMixin.lua that I am essentially trying to implement as a CompTeam in Cafu:
The difference being, in Cafu, the only thing implemented in the CompTeam file would be the variable TeamNum and the functions SetTeamNumber() and GetTeamNumber() in the component. The ability to set the number and name of teams etc, in Cafu, would be available in the lua script, it wouldn't be contained in the CompTeam like the NS2 mixin. It is only done in that way there because it is all in lua.
The mixin - component part is where I am currently getting stuck, as I need to learn C++ for these parts, but progress is being made, and my understanding is growing continuously, so I know I will get there eventually
In NS2 there is a lua script class called Team.lua. It won't make total sense as it calls global variables etc, but you should be able to get the gist of what it does from the variable names anyway:
Code: Select all
// ======= Copyright (c) 2003-2012, Unknown Worlds Entertainment, Inc. All rights reserved. =====
//
// lua\Team.lua
//
// Created by: Charlie Cleveland (charlie@unknownworlds.com) and
// Max McGuire (max@unknownworlds.com)
//
// Tracks players on a team.
//
// ========= For more information, visit us at http://www.unknownworlds.com =====================
class 'Team'
function Team:Initialize(teamName, teamNumber)
self.teamName = teamName
self.teamNumber = teamNumber
self.playerIds = table.array(16)
self.respawnQueue = table.array(16)
// This is a special queue to place players in if the
// teams become unbalanced.
self.respawnQueueTeamBalance = table.array(16)
self.kills = 0
end
function Team:Uninitialize()
end
function Team:OnCreate()
end
function Team:OnInitialized()
end
function Team:OnEntityKilled(targetEntity, killer, doer, point, direction)
local killerOnTeam = HasMixin(killer, "Team") and killer:GetTeamNumber() == self.teamNumber
if killer and targetEntity and killerOnTeam and GetAreEnemies(killer, targetEntity) and killer:isa("Player") and targetEntity:isa("Player") then
self:AddKills(1)
end
end
/**
* If a team doesn't support orders then any player changing to the team will have it's
* orders cleared.
*/
function Team:GetSupportsOrders()
return true
end
/**
* Called only by Gamerules.
*/
function Team:AddPlayer(player)
if player ~= nil and player:isa("Player") then
// Update scores when switching teams.
player:SetRequestsScores(true)
local id = player:GetId()
return table.insertunique(self.playerIds, id)
else
Print("Team:AddPlayer(): Entity must be player (was %s)", SafeClassName(player))
end
return false
end
local function UpdateRespawnQueueTeamBalance(self)
// Check if a player needs to be removed from the holding area.
while #self.respawnQueueTeamBalance > (self.autoTeamBalanceAmount or 0) do
local spawnPlayer = Shared.GetEntity(self.respawnQueueTeamBalance[1])
table.remove(self.respawnQueueTeamBalance, 1)
spawnPlayer:SetRespawnQueueEntryTime(Shared.GetTime())
table.insertunique(self.respawnQueue, spawnPlayer:GetId())
spawnPlayer:SetWaitingForTeamBalance(false)
TEST_EVENT("Auto-team balance, out of queue")
end
end
function Team:OnEntityChange(oldId, newId)
// Replace any entities in the respawn queue
if oldId and table.removevalue(self.respawnQueue, oldId) then
// Keep queue entry time the same
if newId then
table.insertunique(self.respawnQueue, newId)
end
end
if oldId and table.removevalue(self.respawnQueueTeamBalance, oldId) then
if newId then
table.insertunique(self.respawnQueue, newId)
Shared.GetEntity(newId):SetWaitingForTeamBalance(true)
end
end
UpdateRespawnQueueTeamBalance(self)
end
function Team:GetPlayer(playerIndex)
if (playerIndex >= 1 and playerIndex <= table.count(self.playerIds)) then
return Shared.GetEntity( self.playerIds[playerIndex] )
end
Print("Team:GetPlayer(%d): Invalid index specified (1 to %d)", playerIndex, table.count(self.playerIds))
return nil
end
/**
* Called only by Gamerules.
*/
function Team:RemovePlayer(player)
assert(player)
if not table.removevalue(self.playerIds, player:GetId()) then
Print("Player %s with Id %d not in playerId list.", player:GetClassName(), player:GetId())
end
self:RemovePlayerFromRespawnQueue(player)
player:SetTeamNumber(kTeamInvalid)
end
function Team:GetNumPlayers()
local numPlayers = 0
local numRookies = 0
// Player may have been deleted this tick, so check id to make sure player count is correct)
for index, playerId in ipairs(self.playerIds) do
local player = Shared.GetEntity(playerId)
// Verify the player has a Client attached to it (we don't want to count ragdolls as team players for example.
if player ~= nil and player:GetId() ~= Entity.invalidId and Server.GetOwner(player) ~= nil then
numPlayers = numPlayers + 1
if player:GetIsRookie() then
numRookies = numRookies + 1
end
end
end
return numPlayers, numRookies
end
function Team:GetNumPlayersInQueue()
return #self.respawnQueue
end
function Team:GetNumDeadPlayers()
local numPlayers = 0
// Player may have been deleted this tick, so check id to make sure player count is correct)
for index, playerId in ipairs(self.playerIds) do
local player = Shared.GetEntity(playerId)
if player ~= nil and player:GetId() ~= Entity.invalidId and player:GetIsAlive() == false then
numPlayers = numPlayers + 1
end
end
return numPlayers
end
function Team:GetPlayers()
local playerList = {}
for index, playerId in ipairs(self.playerIds) do
local player = Shared.GetEntity(playerId)
if player ~= nil and player:GetId() ~= Entity.invalidId then
table.insert(playerList, player)
end
end
return playerList
end
function Team:GetTeamNumber()
return self.teamNumber
end
// Called on game start or end. Reset everything but teamNumber and teamName.
function Team:Reset()
self.kills = 0
self:ClearRespawnQueue()
// Clear players
self.playerIds = { }
end
function Team:ResetPreservePlayers(techPoint)
local playersOnTeam = {}
table.copy(self.playerIds, playersOnTeam)
if Shared.GetCheatsEnabled() and techPoint ~= nil then
Print("Setting team %d team location: %s", self:GetTeamNumber(), techPoint:GetLocationName())
end
if techPoint then
self.initialTechPointId = techPoint:GetId()
end
self:Reset()
table.copy(playersOnTeam, self.playerIds)
end
/**
* Play sound for every player on the team.
*/
function Team:PlayPrivateTeamSound(soundName, origin, commandersOnly, excludePlayer, ignoreDistance, triggeringPlayer)
ignoreDistance = ignoreDistance or false
local function PlayPrivateSound(player)
if ( not commandersOnly or player:isa("Commander") ) and (not triggeringPlayer or not triggeringPlayer:isa("Player") or GetGamerules():GetCanPlayerHearPlayer(player, triggeringPlayer)) then
if excludePlayer ~= player then
// Play alerts for commander at commander origin, so they always hear them
if not origin or player:isa("Commander") then
Server.PlayPrivateSound(player, soundName, player, 1.0, Vector(0, 0, 0), ignoreDistance)
else
Server.PlayPrivateSound(player, soundName, nil, 1.0, origin, ignoreDistance)
end
end
end
end
self:ForEachPlayer(PlayPrivateSound)
end
function Team:TriggerEffects(eventName)
local function TriggerEffects(player)
player:TriggerEffects(eventName)
end
self:ForEachPlayer(TriggerEffects)
end
function Team:SetFrozenState(state)
local function SetFrozen(player)
player.frozen = state
end
self:ForEachPlayer(SetFrozen)
end
function Team:SetAutoTeamBalanceEnabled(enabled, unbalanceAmount)
self.autoTeamBalanceEnabled = enabled
self.autoTeamBalanceAmount = enabled and unbalanceAmount or nil
UpdateRespawnQueueTeamBalance(self)
end
/**
* Queues a player to be spawned.
*/
function Team:PutPlayerInRespawnQueue(player)
assert(player)
// Place player in a "holding area" if auto-team balance is enabled.
if self.autoTeamBalanceEnabled then
// Place this new player into the holding area.
table.insert(self.respawnQueueTeamBalance, player:GetId())
player:SetWaitingForTeamBalance(true)
UpdateRespawnQueueTeamBalance(self)
TEST_EVENT("Auto-team balance, in queue")
else
local extraTime = 0
if player.spawnBlockTime then
extraTime = math.max(0, player.spawnBlockTime - Shared.GetTime())
end
if player.spawnReductionTime then
extraTime = extraTime - player.spawnReductionTime
player.spawnReductionTime = nil
end
player:SetRespawnQueueEntryTime(Shared.GetTime() + extraTime)
table.insertunique(self.respawnQueue, player:GetId())
if self.OnRespawnQueueChanged then
self:OnRespawnQueueChanged()
end
end
end
function Team:GetPlayerPositionInRespawnQueue(player)
local queueSize = #self.respawnQueue
for i = 1, queueSize do
if player:GetId() == self.respawnQueue[i] then
return i
end
end
return -1
end
/**
* Removes the player from the team's spawn queue (if he's in it, otherwise has
* no effect).
*/
function Team:RemovePlayerFromRespawnQueue(player)
table.removevalue(self.respawnQueueTeamBalance, player:GetId())
table.removevalue(self.respawnQueue, player:GetId())
UpdateRespawnQueueTeamBalance(self)
player:SetWaitingForTeamBalance(false)
end
function Team:ClearRespawnQueue()
for p = 1, #self.respawnQueueTeamBalance do
local player = Shared.GetEntity(self.respawnQueueTeamBalance[p])
player:SetWaitingForTeamBalance(false)
end
table.clear(self.respawnQueueTeamBalance)
table.clear(self.respawnQueue)
end
// Find player that's been dead and waiting the longest. Return nil if there are none.
function Team:GetOldestQueuedPlayer()
local playerToSpawn = nil
local earliestTime = -1
for i, playerId in ipairs(self.respawnQueue) do
local player = Shared.GetEntity(playerId)
if player ~= nil and player.GetRespawnQueueEntryTime then
local currentPlayerTime = player:GetRespawnQueueEntryTime()
if currentPlayerTime ~= nil and (earliestTime == -1 or currentPlayerTime < earliestTime) then
playerToSpawn = player
earliestTime = currentPlayerTime
end
end
end
if playerToSpawn and ( not playerToSpawn.spawnBlockTime or playerToSpawn.spawnBlockTime <= Shared.GetTime() ) then
return playerToSpawn
end
end
function Team:GetSortedRespawnQueue()
local sortedQueue = {}
for i = 1, #self.respawnQueue do
local player = Shared.GetEntity(self.respawnQueue[i])
if player then
table.insertunique(sortedQueue, player)
end
end
local function SortByEntryTime(player1, player2)
local time1 = player1.GetRespawnQueueEntryTime and player1:GetRespawnQueueEntryTime() or 0
local time2 = player2.GetRespawnQueueEntryTime and player2:GetRespawnQueueEntryTime() or 0
return time1 < time2
end
table.sort(sortedQueue, SortByEntryTime)
return sortedQueue
end
function Team:GetKills()
return self.kills
end
function Team:AddKills(num)
self.kills = self.kills + num
end
// Structure was created. May or may not be built or active.
function Team:StructureCreated(entity)
end
// Entity that supports the tech tree was just added (it's built/active).
function Team:TechAdded(entity)
end
// Entity that supports the tech tree was just removed (no longer built/active).
function Team:TechRemoved(entity)
end
function Team:GetIsPlayerOnTeam(player)
return table.find(self.playerIds, player:GetId()) ~= nil
end
function Team:ReplaceRespawnAllPlayers()
local playerIds = table.duplicate(self.playerIds)
for i, playerIndex in ipairs(playerIds) do
local player = Shared.GetEntity(playerIndex)
self:ReplaceRespawnPlayer(player, nil, nil)
end
end
// For every player on team, call functor(player)
function Team:ForEachPlayer(functor)
for i, playerIndex in ipairs(self.playerIds) do
local player = Shared.GetEntity(playerIndex)
if player ~= nil and player:isa("Player") then
functor(player)
else
Print("Team:ForEachPlayer(): Couldn't find player for index %d", playerIndex)
end
end
end
function Team:SendCommand(command)
local function PlayerSendCommand(player)
Server.SendCommand(player, command)
end
self:ForEachPlayer(PlayerSendCommand)
end
function Team:GetHasActivePlayers()
local hasActivePlayers = false
local currentTeam = self
local function HasActivePlayers(player)
if(player:GetIsAlive() and (player:GetTeam() == currentTeam)) then
hasActivePlayers = true
end
end
self:ForEachPlayer(HasActivePlayers)
return hasActivePlayers
end
function Team:GetHasAbilityToRespawn()
return true
end
function Team:Update(timePassed)
end
function Team:GetNumCommandStructures()
local commandStructures = GetEntitiesForTeam("CommandStructure", self:GetTeamNumber())
return table.maxn(commandStructures)
end
function Team:GetNumAliveCommandStructures()
local commandStructures = GetEntitiesForTeam("CommandStructure", self:GetTeamNumber())
local numAlive = 0
for c = 1, #commandStructures do
numAlive = commandStructures[c]:GetIsAlive() and (numAlive + 1) or numAlive
end
return numAlive
end
function Team:GetHasTeamLost()
return false
end
function Team:GetHasTeamWon()
return false
end
function Team:RespawnPlayer(player, origin, angles)
assert(self:GetIsPlayerOnTeam(player), "Player isn't on team!")
if origin == nil or angles == nil then
// Randomly choose unobstructed spawn points to respawn the player
local spawnPoint = nil
local spawnPoints = Server.readyRoomSpawnList
local numSpawnPoints = table.maxn(spawnPoints)
if numSpawnPoints > 0 then
local spawnPoint = GetRandomClearSpawnPoint(player, spawnPoints)
if spawnPoint ~= nil then
origin = spawnPoint:GetOrigin()
angles = spawnPoint:GetAngles()
end
end
end
// Move origin up and drop it to floor to prevent stuck issues with floating errors or slightly misplaced spawns
if origin ~= nil then
SpawnPlayerAtPoint(player, origin, angles)
player:ClearEffects()
return true
else
Print("Team:RespawnPlayer(player, %s, %s) - Must specify origin.", ToString(origin), ToString(angles))
end
return false
end
function Team:BroadcastMessage(message)
function sendMessage(player)
Server.Broadcast(player, message)
end
self:ForEachPlayer( sendMessage )
end
function Team:GetSpectatorMapName()
return Spectator.kMapName
end
Team > Playing Team - Spectating Team - Ready Room Team
Playing Team > Marine Team - Alien Team
So that is the team code created, but entities still need to be assigned to a team. In NS2, this is controlled by what they call a 'Mixin'. I know this is not the correct term neccesarily, but it works. This TeamMixin is called by entities that are on a team and sets the teamNumber Network Variable that is defined in the Mixin. As I understand it, this use of a Mixin is equivalent to a component in Cafu.
However, this is where the simlilarities end and the difference begins. NS2 mixins are not written in the engine in C++, they are all written in lua. The engine has an API that hooks into certain elements, but all of what you seem to be defining as components in C++ are defined as mixins in lua. As as example, here is the TeamMixin.lua that I am essentially trying to implement as a CompTeam in Cafu:
Code: Select all
// ======= Copyright (c) 2003-2011, Unknown Worlds Entertainment, Inc. All rights reserved. =======
//
// lua\TeamMixin.lua
//
// Created by: Brian Cronin (brianc@unknownworlds.com)
//
// ========= For more information, visit us at http://www.unknownworlds.com =====================
/**
* TeamMixin has functionality for an Entity to be on a team.
*/
TeamMixin = CreateMixin(TeamMixin)
TeamMixin.type = "Team"
TeamMixin.networkVars =
{
// Never set this directly, call SetTeamNumber()
teamNumber = string.format("integer (-1 to %d)", kSpectatorIndex)
}
function TeamMixin:__initmixin()
self.teamNumber = -1
end
if Client then
function TeamMixin:OnGetIsVisible(visibleTable, viewerTeamNumber)
local player = Client.GetLocalPlayer()
if player and player:isa("Commander") and viewerTeamNumber == GetEnemyTeamNumber(self:GetTeamNumber()) and HasMixin(self, "LOS") and not self:GetIsSighted() then
visibleTable.Visible = false
end
end
end
local kTeamIndexToType = { }
kTeamIndexToType[kTeamInvalid] = kNeutralTeamType
kTeamIndexToType[kTeamReadyRoom] = kNeutralTeamType
kTeamIndexToType[kTeam1Index] = kTeam1Type
kTeamIndexToType[kTeam2Index] = kTeam2Type
kTeamIndexToType[kSpectatorIndex] = kNeutralTeamType
function TeamMixin:GetTeamType()
return kTeamIndexToType[self.teamNumber]
end
function TeamMixin:GetTeamNumber()
return self.teamNumber
end
function TeamMixin:SetTeamNumber(teamNumber)
self.teamNumber = teamNumber
if self.OnTeamChange then
self:OnTeamChange()
end
end
function TeamMixin:OnInitialized()
local teamNumber = GetAndCheckValue(self.teamNumber, 0, 3, "teamNumber", 0, true)
self:SetTeamNumber(teamNumber)
end
/**
* The team object only exists on the Server.
*/
function TeamMixin:GetTeam()
assert(Server)
if not GetHasGameRules() then
return nil
end
return GetGamerules():GetTeam(self:GetTeamNumber())
end
function TeamMixin:GetEffectParams(tableParams)
if not tableParams[kEffectFilterIsMarine] then
tableParams[kEffectFilterIsMarine] = (self:GetTeamType() == kMarineTeamType)
end
if not tableParams[kEffectFilterIsAlien] then
tableParams[kEffectFilterIsAlien] = (self:GetTeamType() == kAlienTeamType)
end
end
/**
* This function is called from OwnerMixin when ownership of this
* object changes.
*/
function TeamMixin:OnOwnerChanged(oldOwner, newOwner)
if newOwner and HasMixin(newOwner, "Team") then
// Only allow team members to own this object.
if newOwner:GetTeamNumber() ~= self:GetTeamNumber() then
self:SetOwner(nil)
end
end
end
function TeamMixin:GetCanBeUsed(player, useSuccessTable)
if GetAreEnemies(player, self) then
useSuccessTable.useSuccess = false
end
end
The mixin - component part is where I am currently getting stuck, as I need to learn C++ for these parts, but progress is being made, and my understanding is growing continuously, so I know I will get there eventually
Re: Getting going after set-up
Hi,
from what you have posted, it looks like you're on the right track, and creating a new component by copying e.g.
Also check out the
In any case, don't hesitate to post any questions you may have, I'm happy to help! (Pure C++ questions may yield better replies when posted to more C++ specific places, though.)
Regarding the Team Mixin code that you posted, I seem to understand it at a detail level, as the methods are simple enough, and I also agree that there is a suggestive analogy to components. (What I'm lacking is a higher-level understanding of that code, e.g. who calls these methods when in which context, but then this is probably not needed for our purposes.)
I think that your experience with NS2 can be a great help both for yourself when developing with Cafu, and also I would be very happy to learn if you ever hit a point where NS2 did allow you to do something that seems difficult or not possible in Cafu.
That being said, I would recommend that, when developing with Cafu, not to cling to NS2 too closely. Concepts are different, at least at a certain level, and things may work better if you not try to do things in Cafu like they're done in NS2. Starting the NS2 way may be a very good point for getting started, but eventually it is probably better to smoothly switch to the way things are done in Cafu. I'm sure that things are at least as easy and straightforward to implement in Cafu than they are in NS2, and if you ever hit a limit, I'm sure that we can overcome it.
Regarding C++ and Lua: In "pro C++" speak, all components are indeed C++ code.
However, by inherent default, all components have a representation as a Lua object, all component variables (of type
Script components can do anything that any other component can do, and act as a kind of "adapters": They forward their functionality to Lua scripts, that's their main job.
That feature can the most obviously be seen in the quasi trivial implementation of
With that, also consider the
This feature of course needs a little more code, because we have to let the implementations of
from what you have posted, it looks like you're on the right track, and creating a new component by copying e.g.
ComponentBasicsT
is definitively a good idea (I do it, too. )Also check out the
AllComponents.cpp
file: new components must be included in the list in this file.In any case, don't hesitate to post any questions you may have, I'm happy to help! (Pure C++ questions may yield better replies when posted to more C++ specific places, though.)
Regarding the Team Mixin code that you posted, I seem to understand it at a detail level, as the methods are simple enough, and I also agree that there is a suggestive analogy to components. (What I'm lacking is a higher-level understanding of that code, e.g. who calls these methods when in which context, but then this is probably not needed for our purposes.)
I think that your experience with NS2 can be a great help both for yourself when developing with Cafu, and also I would be very happy to learn if you ever hit a point where NS2 did allow you to do something that seems difficult or not possible in Cafu.
That being said, I would recommend that, when developing with Cafu, not to cling to NS2 too closely. Concepts are different, at least at a certain level, and things may work better if you not try to do things in Cafu like they're done in NS2. Starting the NS2 way may be a very good point for getting started, but eventually it is probably better to smoothly switch to the way things are done in Cafu. I'm sure that things are at least as easy and straightforward to implement in Cafu than they are in NS2, and if you ever hit a limit, I'm sure that we can overcome it.
Regarding C++ and Lua: In "pro C++" speak, all components are indeed C++ code.
However, by inherent default, all components have a representation as a Lua object, all component variables (of type
TypeSys::VarT<...>
) are automatically available to Lua scripts, many components call callbacks in Lua, almost all provide methods to be called from Lua, and most importantly, all components can "forward" their functionality to Lua, most prominently the Script component.Script components can do anything that any other component can do, and act as a kind of "adapters": They forward their functionality to Lua scripts, that's their main job.
That feature can the most obviously be seen in the quasi trivial implementation of
ComponentScriptT::DoServerFrame()
:Code: Select all
void ComponentScriptT::DoServerFrame(float t)
{
CallLuaMethod("Think", 0, "f", t);
}
ComponentScriptT
's DoSerialize()
and DoDeserialize()
methods: At this time, they only implement some auxiliary functionality (albeit an important one). But it is perfectly thinkable to expand this to serialize and deserialize variables that only exist in the Lua script that the component is reponsible for as well!This feature of course needs a little more code, because we have to let the implementations of
Do[De]Serialize()
know which variables to act on, or alternatively have them call something like CallLuaMethod("Serialize", 0);
and CallLuaMethod("Deserialize", 0);
, which Lua scripts in turn had to implement if they wanted their variables to be (de-)serialized. Given all that, it seems to me that there is quasi no functionality that cannot be implemented in Lua. Being able to serialize and deserialize data that exists in Lua scripts but not in C++ seems to make it possible to implement arbitrary classes in Lua. Best regards,
Carsten
Carsten
Re: Getting going after set-up
Thanks for that. There is still a lot for me to learn about programming and languages, so my questions will probably be a mixture of not understanding engine, or not understanding the language. I probably won't know which is the issue, eitherCarsten wrote: Also check out theAllComponents.cpp
file: new components must be included in the list in this file.
In any case, don't hesitate to post any questions you may have, I'm happy to help! (Pure C++ questions may yield better replies when posted to more C++ specific places, though.)
Absolutely. I will try and use what I understand from NS2, and when that doesn't work, I will look at why and try to learn a new way to solve it. NS2 code is all in LUA, the engine isn't open source. To this end, I can make an entire game in Lua, and using the NS2 method wouldn't be an issue, except for performance overhead of course.Carsten wrote:That being said, I would recommend that, when developing with Cafu, not to cling to NS2 too closely. Concepts are different, at least at a certain level, and things may work better if you not try to do things in Cafu like they're done in NS2. Starting the NS2 way may be a very good point for getting started, but eventually it is probably better to smoothly switch to the way things are done in Cafu. I'm sure that things are at least as easy and straightforward to implement in Cafu than they are in NS2, and if you ever hit a limit, I'm sure that we can overcome it.
Totally, as per my last answer, the ability to run everything in lua gives me complete freedom. Most of my earlier questions were based around my confusion as to what a component was. Now I have figured it out, I have been able to feel more confident with the ideas I have Also, if you do at any point wish to understand a bit more of the NS2 code, I can always fill you in with my knowledge at any time.Carsten wrote:However, by inherent default, all components have a representation as a Lua object, all component variables (of typeTypeSys::VarT<...>
) are automatically available to Lua scripts, many components call callbacks in Lua, almost all provide methods to be called from Lua, and most importantly, all components can "forward" their functionality to Lua, most prominently the Script component.
Script components can do anything that any other component can do, and act as a kind of "adapters": They forward their functionality to Lua scripts, that's their main job.
That feature can the most obviously be seen in the quasi trivial implementation ofComponentScriptT::DoServerFrame()
:Code: Select all
void ComponentScriptT::DoServerFrame(float t) { CallLuaMethod("Think", 0, "f", t); }
This concept of serializing and deserializing is something which is new to me, and as yet, I must admit, I haven't tried to work out what it relates to. I will definitely need some guidance on this in the futureCarsten wrote:With that, also consider theComponentScriptT
'sDoSerialize()
andDoDeserialize()
methods: At this time, they only implement some auxiliary functionality (albeit an important one). But it is perfectly thinkable to expand this to serialize and deserialize variables that only exist in the Lua script that the component is reponsible for as well!
This feature of course needs a little more code, because we have to let the implementations ofDo[De]Serialize()
know which variables to act on, or alternatively have them call something likeCallLuaMethod("Serialize", 0);
andCallLuaMethod("Deserialize", 0);
, which Lua scripts in turn had to implement if they wanted their variables to be (de-)serialized. Given all that, it seems to me that there is quasi no functionality that cannot be implemented in Lua. Being able to serialize and deserialize data that exists in Lua scripts but not in C++ seems to make it possible to implement arbitrary classes in Lua.
Re: Getting going after set-up
Hi SoulRider,
thanks for your update, it all sounds very well!
FYI, to get back to one of your earlier questions, I just started a new thread Creating a "binary release" from a compiled source code repo.
This is not yet the ultimate answer to everything, because it lacks, for example, zipping the created directory, FTP-uploading it, and several other features that the
thanks for your update, it all sounds very well!
FYI, to get back to one of your earlier questions, I just started a new thread Creating a "binary release" from a compiled source code repo.
This is not yet the ultimate answer to everything, because it lacks, for example, zipping the created directory, FTP-uploading it, and several other features that the
make_binary.py
script has (which however is also quite inflexible), but I guess it's a quite useful first step with which you can relatively easily create redistributable packages (e.g. for other people to test and review) that don't contain any redundant files and whose programs start on double-click in Windows Explorer. Best regards,
Carsten
Carsten
Re: Getting going after set-up
I've just read the thread, that is great It will be very helpful when trying to get testing done and content made
Who is online
Users browsing this forum: No registered users and 37 guests