Rusky
|
|
Reply #45 Posted on: May 11, 2010, 01:52:15 pm |
|
|
Joined: Feb 2008
Posts: 954
|
How you do deal with runtime changes in behavior? Inheriting from Character doesn't help that unless you write it as one enormous object with a bunch of switches and ifs, which is barely usable. In other games, you might want NPCs or enemies to inherit the power-up parts of Character, which leads to multiple inheritance when you split Character, which completely confuses your tier system (x and y come from which parent? PlayerCharacter or PlatformCharacter?). What about the multiplayer example where control can come from the keyboard, the network or an AI for any given ship? There's no way you can do that with just templates and inheritance without huge amounts of copy-paste.
Why does it matter if you're relying on the parser when EDL is so close to C++? If the user never encounters the core components, they can think of built-ins as normal locals, which means there'd be no problem trying to use C++. Also, since EDL is so close to C++, why would you have to remove the parser when developing your own C++ functions? They could easily write EDL in Whitespace or run it through the parser as part of the build process if it's part of Enigma. There's no reason to avoid the parser when working with the system it's designed for, so there would be no annoyances.
When I asked "Why would you decide to add a component pointer?" I assumed components like Path would either always be in Object or only be included in OBJ_*s. Neither would force a recompile. Instantiating components inline goes back to the problem of changing tier sizes. Changing a component in such a system would have the same results as in your pre-tier system. Components would store pointers in Object (i.e. at the beginning of the layout) that point to the different members of the child object precisely to avoid this. While you may be in control of object layout, you are not in control of which subtype of Object you might need to operate on.
You haven't really given any points against using components for core systems other than "it's too complicated," which is a stupid reason, and "it's ugly," which is completely subjective at this point. You haven't shown how you would accomplish the debugging features I suggested without components. You haven't shown how tiers are any less ugly than components.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #46 Posted on: May 11, 2010, 02:19:30 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
"(x and y come from which parent? PlayerCharacter or PlatformCharacter?)" Neither; a parent of both. GM doesn't have multiple inheritance anyway. Most of what you're describing otherwise is achievable with scripts. ai_avoid_bullet(), ai_seek_powerup()... much of those will lead to conflict in either system.
Nonetheless, that is outside the scope of this debate.
Just because the language looks close doesn't mean it behaves close. The parts of EDL that require a parser to use shouldn't be employed in C++ functions. If you want with() and case "string", use a script.
"When I asked "Why would you decide to add a component pointer?" I assumed components like Path would either always be in Object or only be included in OBJ_*s. Neither would force a recompile." The latter is impossible without a global due to inability to assume position of that pointer, which is, for the fourth time, a problem shared between components and my old system. And no, I don't want those damn pointers to always be included.
"Instantiating components inline goes back to the problem of changing tier sizes. Changing a component in such a system would have the same results as in your pre-tier system." Hence I mentioned the (Object::*). I neglected to mention that it would be at the global scope. All the Path component's source would need to know is the location of its structure inside Object, which would be represented by extern Object::* ::component_location::path;.
"You haven't really given any points against using components for core systems other than "it's too complicated," which is a stupid reason, and "it's ugly," which is completely subjective at this point. You haven't shown how you would accomplish the debugging features I suggested without components. You haven't shown how tiers are any less ugly than components." Debugging has always been done with preprocessors. To initiate debug mode, one flag would have to be set, and the sources could be compiled in a separate objects folder called ".eobjs_debug" instead of just ".eobjs". Tracking variable changes can be done by adding "debug_proxy<>" around all the types; something I have complete control over. I know I've mentioned that, maybe I didn't stress it. And although I wasn't going to mention it until plans were laid, I was considering hooking up GDB to the debug window when the time comes to allow stepping through code one expression at a time, like Code::Blocks and other IDEs do. And I said that the code produced is uglier. Saying "x" is prettier than saying "x()". Every benefit you've suggested to using components on the lower system, I gave how it would be accomplished with the current system instead. Feel free to enumerate more, and I'll respond to them as well. And the argument isn't that it's too complicated, it's that it is -more- complicated. And all else being the same, the simpler method wins.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
Rusky
|
|
Reply #47 Posted on: May 11, 2010, 05:03:38 pm |
|
|
Joined: Feb 2008
Posts: 954
|
And all else being the same, the simpler method wins. All else is not the same, which is the point: For core systems (e.g. graphics, collisions), the main benefits of components are 1) complete separation of debug code- normal code has no idea the debug system exists even before the preprocessor, and 2) fine-grained, runtime control of debug systems- you can switch them on and off at runtime (in debug build only of course) for individual objects and systems. You have not explained how you would accomplish these in the current system; variable tracking and interactive debugging do not come into the picture here. Non-core GM systems (e.g. paths) may be better candidates for the tier system- they're GM-specific and I don't really see a need for alternate implementations. However, the debug benefits for the core systems still apply here. With the paths example, you could have a (runtime) switch in the debugger to draw paths being followed. You could do this with tiers, but it would require extra runtime checks for the switch and preprocessor checks for debug mode. That kind of system is far more ugly than a few parsed-in parentheses- it affects code you actually have to work with and you can't fix it in five seconds with a text editor. When extending GM (e.g. reusable behaviors), components address organization issues much better than GM's single inheritance. They're much better than scripts, which are really just components organized in the most horrible way imaginable. Components do code reuse far better than templates and wizards, which are just fancy copy-paste (and so somehow different from the "real" code?) That's why they're a good way to extend GM- its existing inheritance model and paradigms are irrelevant.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #48 Posted on: May 11, 2010, 05:46:27 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
extern void vague_debug_event_that_somehow_applies_to_everything(); extern void (*vague_debug_event_that_somehow_applies_to_everything_and_can_be_disabled_at_runtime)(); #ifndef ENIGMAdebug #define vague_debug_event_that_somehow_applies_to_everything() #define vague_debug_event_that_somehow_applies_to_everything_and_can_be_disabled_at_runtime() #endif
Now, as far as calling that in systems that aren't designed to have special debug information; why would you need to, number one? What would you call for every function called by every system? What would be the point? To get what last executed before fail? That's where stepping through comes in.
At this second paragraph, I believe you're just trolling. The entire fucking point of the tier system is to allow files that make use of common elements to only include pieces parts of the elements, leaving the rest to mystery. Using the tier system for something as worthless as paths--that exactly one source file depends on--is about the most ridiculous thing I've heard this whole debate.
"When extending GM (e.g. reusable behaviors), components address organization issues much better than GM's single inheritance." Obviously. "They're much better than scripts, which are really just components organized in the most horrible way imaginable." In your opinion, I'll grant that. But I'd like to point out that scripts require special passes over to get to function correctly; mostly to tell the system what other locals need included in the objects that call each script. This isn't an option for hard-coded components. "Components do code reuse far better than templates and wizards, which are just fancy copy-paste (and so somehow different from the "real" code?)" In your opinion, close (yes, they're different in that code is being modified dynamically by the compiler/wizard) "That's why they're a good way to extend GM- its existing inheritance model and paradigms are irrelevant." Yes, I agreed with this two posts ago. What does this have to do with the underlying system about which this debate is concerned?
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
Rusky
|
|
Reply #49 Posted on: May 11, 2010, 06:33:11 pm |
|
|
Joined: Feb 2008
Posts: 954
|
I'm not being vague, you're just not reading my posts. These aren't even debug events- they're modifications to existing systems. You could add a debug wrapper (i.e. a new component that forwards calls to the original one, doing something else as well) that draws the path an object is following. You could add one that draws and deals with build mode controls, letting you modify objects when the game is paused. You could add one that turns off specific sounds to help debug audio. You could add one that pauses for build mode on a certain event (okay, this one's an event, whatever). These are not the same level of debugging that uses proxy<> and an interactive debugger- it's higher level and more specific to Enigma games.
You were the one who suggested using a tiered system for paths: "Paths...are a good reason to add a component pointer" and "If I decide to add a tier pointer, your ass will be recompiling everything that uses a single local, just like my system before tiers." What I got out of those quotes was that you wanted to put the path pointer in a tier so it could be removed completely due to paths' rarity. I acknowledged that tiers would be a good way to get rid of paths completely, but you could just tier a component rather than the whole class.
Why do you have to do special passes over scripts? Couldn't you just pass an Object reference to them as a hidden argument? You can't know what members will exist at compile time anyway- even with "treat uninitialized variables as 0" turned off you can still insert new members at any time. However you get that to work, reusable behaviors could work exactly the same way. They're just as possible as scripts.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #50 Posted on: May 11, 2010, 06:56:59 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
"You could add a debug wrapper (i.e. a new component that forwards calls to the original one, doing something else as well) that draws the path an object is following." Where would I put the code for that? Personally, I think it'd be a good idea to put it in with, say, the rest of the code. Otherwise it's just a pain in the ass to find the corresponding debug code. "You could add one that draws and deals with build mode controls, letting you modify objects when the game is paused." Yes, as the supreme lord and master of all code that goes through ENIGMA, I can do that without a component system by inserting the code myself at compile time. I mentioned that before. "You could add one that turns off specific sounds to help debug audio." Sounds have to be queued anyway for sound_stop_all. Practically all of ENIGMA needs queued in some way, shape, or form. This could be done with a simple global-scope function. How does your system help me? "You could add one that pauses for build mode on a certain event (okay, this one's an event, whatever)." I don't follow the parenthetical statement. Build mode is presently handled with an #if around an if-else pair in the event loop. The #if checks that it's in build mode, the if() checks if build mode has the game paused. This has worked for over a year. How does your system help me? "These are not the same level of debugging that uses proxy<> and an interactive debugger- it's higher level and more specific to Enigma games." If it's that specific, it should be included in or by the concerned source. It doesn't make sense to put the debug code anywhere else just because I can. "You were the one who suggested using a tiered system for paths: "Paths...are a good reason to add a component pointer"" What? How is "Paths...are a good reason to add a component pointer" suggestive of tiers? Now, in "If I decide to add a tier pointer, your ass will be recompiling everything that uses a single local, just like my system before tiers," I meant "component pointer" rather than "tier pointer." And no, this would be handled using all your fancy semantic proposals; the paths would be a component in your domain as described by the better of your previous proposals and a few methods of my own. The path system would be the first to justify using your component idea as I see it. Even with it, though, I would build on your idea to prevent fuck-ugly path_index() calls (Ironically, path_index() is probably a better idea though, since it's a read-only variable). These ideas that I would use to build on components would be inlining them then taking a member pointer to them instead of a component pointer. This could be achieved thanks to the not-"real"-code semantics you started down earlier. Again, paths are worth it to me, the underlying important systems are not. "Couldn't you just pass an Object reference to them as a hidden argument?" Sure, but then I would have to scope the locals the script uses into everything derived from Object, so scripts designed especially for a certain object using fifty variables would inflict those fifty variables on every other instance as well. Imagine a controller object with its own script folder, each script using some 12 variables, 25 unique among them all. That would be 200 bytes for each instance for no reason at all. "You can't know what members will exist at compile time anyway" Omigosh, I wonder how ENIGMA's been compiling all this time. "Even with "treat uninitialized variables as 0" turned off you can still insert new members at any time" How is that? ENIGMA has no variable_local_set(). When it does, that will simply access a map of references to locals, and if its not in the map, it will allocate a new one. If I didn't know every single variable at compile time, then GCC wouldn't, and the game wouldn't compile. We have no execute_string and no variable_local_set at this time. R3 dealt with "a.b" access somewhat badly, implementing a dynamic cast between instances instead of an integer-taking accessor like R4 will use. All variables "b" accessed as "a.b" are added to an instance of Object called "Global" and identified with "global". If "b" didn't exist in "a.b", the global instance of it was returned. Some behavior is dropped that way, which is why Luda proposed a hash map. I didn't like the idea, but it will be implemented optionally down the road. And yes, usable behaviors could work just that way. But not for the key motherfucking systems. I'm not having my parser go around picking apart and gluing back together the single most fundamental pieces of this system.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
Rusky
|
|
Reply #51 Posted on: May 11, 2010, 07:45:15 pm |
|
|
Joined: Feb 2008
Posts: 954
|
Components give you much more control than global queues. They're object specific and operate in the context of their owner. You could, for example, mute, make invisible, highlight or otherwise affect a specific object from within that object. In build mode, components would go along with or even make unnecessary your #if by handling build mode-specific behavior from within each object. Anyway- you don't have to use components. Tiers will just be another part of Enigma that makes me not want to contribute.
You can organize files however you want, but mixing debug and normal code just makes things less readable and workable. Put them in a debug folder mirroring the main tree or something- debug code does not belong with release code, it's not for the same purpose. Sticking it in at compile time is a little better, but you don't do this everywhere and swapping a pointer is still much simpler than recompiling and inserting new blocks of code.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #52 Posted on: May 11, 2010, 07:53:46 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
"They're object specific and operate in the context of their owner." Then they should be coded in the context of the owner, including the file.
"You could, for example, mute, make invisible, highlight or otherwise affect a specific object from within that object." Like what visible = 0; does. Ingenious.
"In build mode, components would go along with or even make unnecessary your #if by handling build mode-specific behavior from within each object." Yes, but the #if takes up less space and requires only the changing of a single flag. Besides, the option to include Build and Debug mode when compiling a game is not a feature that can be turned off, and is of the few things the system is absolutely designed around the idea of including an option for.
"Anyway- you don't have to use components. Tiers will just be another part of Enigma that makes me not want to contribute." Your only contribution before you cared about how the rest of the system looked was too incomplete to use... Is that a veiled threat?
"You can organize files however you want, but mixing debug and normal code just makes things less readable and workable." Most of us can learn to ignore a single line reading debug_call(), the rest should sleep before/instead of developing for a large project.
"Put them in a debug folder mirroring the main tree or something- debug code does not belong with release code, it's not for the same purpose." Sure, it's not for the same purpose, but it should be designed to integrate with that purpose. As for the separate tree, that's fine, if a bit extreme--I was thinking a separate source--, but the declaration and call of the function is still being included in the main system.
"Sticking it in at compile time is a little better, but you don't do this everywhere and swapping a pointer is still much simpler than recompiling and inserting new blocks of code." Better for someone who can't juggle the purpose of the code and a single-line debug call, certainly.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
|
Josh @ Dreamland
|
|
Reply #54 Posted on: May 11, 2010, 08:17:15 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
"What's wrong with splitting a shared behavior into a different file, especially when it's for debugging purposes only?" Nothing; I've split pieces of a single parser into separate files. What's wrong with relying on the features of a language to handle that?
"Just because you can handle extra #if blocks and debug lines littering your code doesn't mean it's ideal." I believe the same about components for everything.
"I'm sure you could handle writing Enigma in C, why use C++? Because C++ implements polymorphism which I would otherwise have to handle myself, which would take a phenomenal amount of effort.
"But it is a suggestion as to why you have so few developers." As if we needed a reason for that. Ism's on her own now, too. Where did she go wrong? Hell, a lot of open source projects are. That's a pretty trashy reason.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
freezway
|
|
Reply #55 Posted on: May 11, 2010, 09:11:51 pm |
|
|
Joined: Dec 2009
Posts: 220
|
frankly, i dont care for backwards compatibility... I just want to be able to make games on my linux comp.... my windows comp is a) uber-sucky or b) uber sucky AND 10 years old (hooray for PIII and RAMBUS)
|
|
|
Logged
|
if you drop a cat with buttered toast strapped to its back, which side lands down? joshdreamland: our languages are based on the idea that it's going to end up FUBAR /kick retep998
|
|
|
Rusky
|
|
Reply #56 Posted on: May 12, 2010, 07:51:17 am |
|
|
Joined: Feb 2008
Posts: 954
|
You've split the parser, but you haven't split the debug code, which is somehow different and should stay in the same file. Classes, and thus the ways you can use them, are a feature of C++, so splitting debug code out would be relying on a feature of the language. Components make things more readable and separate different purposes better, which has somewhat more weight than putting debug code with what it's debugging with most programmers. Polymorphism is a nice feature that makes code more readable, putting debug code in a separate file does the same thing.
I at least know my own reason for not contributing to LGM- I don't use it. I would use Enigma, were it functional. So where Ism "went wrong" is making a clone for the GM IDE. Most people just use it for a converter, so it doesn't really get used enough for people to run into problems they need to fix. I generally work on projects that I use and that need work, and that probably applies to others. I don't see you writing patches for FreeBSD.
flexaplex: This is not an attack on Josh or Enigma, whatever you may want to think. This has nothing to do with recognizing Enigma's potential. It has to do with Enigma being extensible, the first part of its name, and this particular proposal has nothing to do with extending it towards other languages.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #57 Posted on: May 12, 2010, 08:11:43 am |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
"You've split the parser, but you haven't split the debug code, which is somehow different and should stay in the same file." No, it would operate the same way. There would be one declaration from the split files in the main file, and a function call in concerned functions.
"Classes, and thus the ways you can use them, are a feature of C++, so splitting debug code out would be relying on a feature of the language." On one too many features of the language. I could put it all in a namespace, too. Doesn't really mean I'm going to.
"Components make things more readable" For you "and separate different purposes better," In your opinion "which has somewhat more weight than putting debug code with what it's debugging with most programmers." Have a poll? Hell, if I didn't print debug information inline, I'd double my line count trying to separate it. The actual debug code would be lost in all the hackish attempts to get at all the information I could have had immediately otherwise.
"Polymorphism is a nice feature that makes code more readable, putting debug code in a separate file does the same thing." "Makes code more readable"? I'll give you, "can make code more readable." Regardless, the debug code can and sometimes will be in a separate file, but there will still be a call to it in the main file. The call will be about a line long, maybe two if I include a comment or three if it requires a real lot of parameters. You can't really debug a loop without having some inline debug code for it. Unless you want to have your debug code make a separate iteration, which I'm sure you'd have no problem with.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
|
Josh @ Dreamland
|
|
Reply #59 Posted on: May 12, 2010, 12:52:50 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
Does that benefit the user? Because it sure as hell doesn't benefit me. And, as stated, any benefits it would offer the user can be emulated otherwise thanks to how ENIGMA is set up.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
|