-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] nyan specification #239
Conversation
add nyan interface definition and remove dynamic attributes
Very nice, it's actually understandable now. Another thing that might be useful understanding the upcoming deep integration of nyan: The nyanspec is relevant at compiletime, because it will specify all static types and structs for running and reading nyan files later. That means: The nyan spec is the single source of format specification. The specification is used to generate code:
And we even push this further:
(oh gawd we really have to write these plans down, i guess if i get run over by a bus nobody would ever remember) (whee i just wrote them down) (if you like you can just copy-paste my explanations, but feel free to optimize the understandability 😁) tl;dr: jj just tried to explain the nyan master plan for storing data without any redundancy |
I updated the documentation and tried to keep it simple. I am not sure I was able to optimize the understandability though. Oh and please do not die! : ) |
@inakoll Although I appreciate, that you are trying to improve the nyan documentation, it would be nice, if you keep the sections I have written or ask before removing them. The interfaces that you describe are not part of nyan and can't replace the dynamic attributes, because with interfaces you are still limited to a fixed predefined set of types at compile time, while dynamic attributes make it possible to add objects of a type with completely new attributes within nyan data files. |
I've asked on IRC before proposing this here. I'm not trying to impose anything but rather write my understanding of what JJ said : "the compiler can optimize everything better as there are no string-names as there would be with yaml or json" The benefits of static types are better performance and better compiler diagnosis. Dynamic attributes reduce the advantages of nyanspec, static types and c++ code generation. I don't have any clue of what is really needed but I just can see that there is a real development effort here and that nyanspec and dynamic attributes doesn't seem to fit well together. I thought nyan interfaces could be a solution but if I were wrong I have absolutely no problem with putting everything back the way it was. :) |
@inakoll no problem, at least our ideas no longer exist just in some of these brains 😉. The The libnyan will also probably never exist (my misunderstanding) because just defining entry functions that call to generated code is pretty useless. So the whole nyan-framework usable by the game engine is generated from the format specification. Mods must adhere this format, otherwise they can't load. Static typing ftw! |
If types containing dynamic attributes are partially know by the game engine, type checking is partially irrelevant for types containing one of those "...". For example an ability defined as
would be generated as (something like) : class Ability {
public:
std::string name();
std::map <std::string, util::variant<int, bool, double, std::string, util::set>> dynamic_ attributes();
}; The "dynamic_attributes()" content just can't be statically checked at all or am I missing something? As long as there is no dynamic attributes everywhere or as long as they are not accessed from performance critical code it should be OK. What is bothering me is that if for example we define the MOVE ability like this :
at some point in the C++ code we really need to know that there is a MOVE ability with a speed attribute so at some point we would have to write something like : if (some_ability->is_move_ability()) { // or some other test
do_something(some_ability->dynamic_attributes()["speed"]); // virtual function call + map access
}
} catch (...) // oops is_move_ability implementation is buggy or throw or there is no "speed" attribute in some_ability This could be done once at startup or maybe somewhere in the game loop and is really error-prone. The real problem is that the MOVE ability type is not known at compile time. One solution could be to provide the code generator with both a nyanspec file and a nyan file containing some base game properties. Thus the MOVE ability defined above would be generated in C++ code as : class MOVE_ABILITY { // The MOVE ability has its own implicit type!
public:
std::string name();
double speed() noexcept; // Great!
}; If everything i wrote here is obvious to you then I've just understood something. Anyway, what do you think about it? As long as the user/modder does not extend from ABILITY but overrides existing abilities, it should be OK. |
A mod must be able to extend the abilities dynamically. Imagine: You have a japanese tentacle monster mod, which adds the ability If mods need to go deeper (he-he), then the engine actually needs to be extended, the nyanspec updated and we have to merge the change upstream i'd say. But @Fr3akout will surely know more about that. |
Can someone explain what differentiates this format from other formats like JSON, YAML, TOML or S-Expressions? In my eyes, introducing a new format always introduces a greater contributing barrier. New contributors need to learn a new format first. And parsers need to be written and optimized. Does nyan have a unique property that makes it exceptionally fit for this task? :) (The USP, in marketing speech.) |
Lemme try:
|
Basically what @TheJJ said. In addition, well, nyan tries to be a general language, but it was designed with openage in mind, so it has facilities to easily represent some of the more complex information, especially how a definition from one datapack updates the definition from an other one, and how a technology will modify the attributes of a unit. |
OK, so you have a special patching syntax? Or inheritance? |
@dbrgn: Unfortunately, the doc seems to lack any larger example code, which I'd find far more useful than theoretical discussions about model-view controllers. IIRC, the syntax would look something like this:
A mod that would increase the hp for light cav and increase the effectiveness of bloodlines to 30% would look like this:
Regarding the execution order of the changes: All enabled datapacks are read first; after reading base, SCOUT has Once all the datapacks have been read, inheritance is resolved: SCOUT has Now when the player researches bloodlines in-game, that player's SCOUT and LIGHTCAVALRY unit types get modified to have 59hp and 85hp. If the player researches the light cavalry tech, all the player's units that have unit type SCOUT get changed to unit type LIGHTCAVALRY. Disclaimer: I did have a large part in designing this, but the final responsible guy/authority is @Fr3akout. |
@mic-e thanks, looks very interesting :) |
@inakoll: Maybe you could include my example as well? |
Restore dynamic attributes Add some examples from mic_e Impove some explanations
@mic-e Done! I think there is still room for some improvements |
ABILITY { | ||
name : string | ||
name : string # Regular attribute specification | ||
... # Dynamic attributes are allowed for this type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ...
is driving me nuts, we have to come up with a better alternative. Nobody will understand that, everybody will asume that the example will just go on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even Python has it :D
>>> ...
Ellipsis
>>> type(...)
<class 'ellipsis'>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why don't we allow dynamic attributes everywhere?
Regarding dynamic attributes and modules/abilities: The reason why we might or might not need dynamic attributes is because different units have different abilities. For example, a Militia doesn't have a ranged attack and thus doesn't need a Now there are several approaches to this issue:
nyanspec:
nyanspec:
nyanspec:
disclaimer: all the nyanspec code was written without having looked at the nyanspec docs for several months. Note: Whatever syntax we decide to go with, we need to make sure that the corresponding C++ code will be reasonable; for example, it shouldn't have to call into python code every single time a unit needs to move. |
i like this! for example, putting aside damage weakness/resistance, a militia isn't too far from a cavalry, or a camel, or an elephant: all of them are melee combat units that can move and do melee attacks |
To start an other discussion, I'd actually prefer a braceless syntax:
|
I'd strongly support that. |
What's a simple parser compared to an awesome-to-use language... I think making python parse the nyanfiles is a bad idea; there's too much that could go wrong, it's a turing-complete language, etc |
Yep, I'd create a custom parser. This shouldn't be too hard. An indentation starts a new scope. De-indentation resets it. A simple state machine should suffice. Is there already some kind of implementation? Are you going to use a parser generator? |
OK so following the "historical module" approach presented above by @mic-e, I tried to simplify the type system and reinforce the syntax consistency.
The nyan parser/generator would generate C++ code for leaf types defined in the nyanspec. Other types would simply be a dynamic composition of leaf types (e.g. std::vector<nyantype*>). The C++ should then handle the copy/reference relation between objects. A '+' char in the nyanspec suppose a copy semantic in the C++ code. An '@' char in the nyanspec suppose a reference semantic in the C++ code. |
@inakoll So basically you want to use traits for composing nyan types? |
@Fr3akout Yes, that sums up everything. I knew the C++ traits class technique but traits are a more general concept. So, this proposal is about traits for nyan. |
Are traits something similar to mixins? |
Since nyan mixins define data (or state) they are mixins not traits, good point! :) |
To answer @mic-e IRC concerns. The SCOUT and LIGHTCAVALERY units would be defined as follows :
|
what about
|
A few points:
|
Current version (nr. 8), non final of course but very interesting ideas in it: |
also very valuable ideas in here, although the previous link has the latest proposal. |
Can we start writing some kind of printer/parser/lexer/formalgrammar for the nyan format? |
No, even the grammar is not fix yet because the languate is far from being specified. See the latest pad for design information, @mic-e and I need to gather some motivation to continue designing this, but it's very complicated :) |
Ow, I've seen a similar language of one big RTS: don't even think about the hierarchy for the units. Make them out of independent bricks. Funny observation about the attribute/dynamic attribute system: it's like a straight Qt QObject with its properties and additional dynamic properties that can appear at the runtime. |
Soooo, we may have a specification: https://github.com/SFTtech/nyan/blob/master/doc/nyan.md head over there and improve it if things are missing :) |
Thanks for all the contributions, I think we can safely close this now. Once the implementation is more or less working, we need to write the openage nyan library to provide all the NyanObjects the engine can handle. This will turn out totally awesome I hope! 👯 |
Before I forget, I am committed to write down what @TheJJ explained to me in #228 about nyan.
So here it is, an introduction to nyan (for newbies). At least this is my understanding.
This is a work in progress and I will see if I am able to do more specifications.
In the meantime I'll accept comments, corrections, suggestions..