Re: Reflection in game engine (c++)
Adrian Stephens <[email protected]> Tue, 19 Mar 2013 12:43:48 -0700
| Newsgroups | gmane.games.devel.sweng |
|---|---|
| Message-ID | <[email protected]> |
--===============0808720945== Content-Type: multipart/alternative; boundary="Apple-Mail=_F4199CB3-D11E-4BD8-9E5D-72C8DEFCD9CB" --Apple-Mail=_F4199CB3-D11E-4BD8-9E5D-72C8DEFCD9CB Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=windows-1252 Yes, sorry - the first part of my response was addressing keeping C = header files with the assets. When I re-read what you wrote I realized = you were talking about keeping the metadata as part of each asset, and I = agree with that. My second point was that external tools need to allow = people to create new entities based on some list of templates, and for = that the tools still need access to those definitions. If all you need = to do is 'process' existing assets, the embedded data would be enough.=20= If I add a new variable to my textures, old textures will still load and = be given the default value for that field. I think we agree on why and = how that's a good thing! I do use the same reflection system for all the data - there really are = no special cases - but the the language you use to specify a type = definition is always going to be turned into some internal = representation at some point; how you express those types is not as = important as the ability to treat the data in a uniform way in code. So = - in the interest of full disclosure - some of my reflection data *is* = generated using templates and macros in C++ files! Perhaps that's = cheating, but a platform-specific texture, say, is meaningless outside = the code that generates it and the code that uses it. There's nothing = to be gained by deferring to an external language for that. Perhaps the 'system' part of 'reflection system' needs more = consideration. The important part to me is the ability to treat all = data uniformly and automatically, and empower artists and designers to = create, browse and combine assets arbitrarily. I don't really care = where the types or the data come from as long they can be uniformly = interpreted by tools and game code. You shouldn't need to stab a = reflection system whose only goal is this. If you want to create some = types in code, or javascript or embedded in flash it's no problem as = long as the end result is interpretable by everyone else. Adrian On Mar 19, 2013, at 11:26 AM, Jarkko Lempiainen wrote: > If you plan to interpret data, you need to parse those class = definitions anyway, regardless how you define & store them. Furthermore, = you *have to* embed the definitions in asset files if you don=92t want = to do mass asset conversions every time you change definitions + you = can=92t guarantee access to all the data using specific definition = anyway. These asset files also need to store only definitions for = objects that are stored within that given asset file, not all your = definitions (wasn=92t sure if this was what you actually meant, but = wanted to clear that up). > =20 > So, if you add a new variable to your textures (e.g. color space = variable to define how to interpret the texture), you have to rebuild = all your texture assets? I don=92t see why you wouldn=92t just use the = same reflection system for all the data. Another example is container = classes, which I have seen requiring special treatment by reflection = systems. I think reflection system needs to be powerful enough to be = usable for all type of data and that you shouldn=92t need to add special = cases for handing different types anywhere outside the type definition. = Otherwise I end up stabbing the reflection system every time I have a = special case. > =20 > =20 > Cheers, Jarkko > =20 > =20 > From: [email protected] = [mailto:[email protected]] On Behalf Of = Adrian Stephens > Sent: Monday, March 18, 2013 10:44 PM > To: [email protected] > Subject: Re: [Sweng-Gamedev] Reflection in game engine (c++) > =20 > Yes, you *can* keep your class definitions with the assets, and have = external tools read them - but my point is that if you're going to be = writing something that parses these definitions, you don't gain much by = defining them using contrived macros and templates. I am proposing = defining them in a simpler, clearer way that can be easily parsed and = spat out as headers, or whatever else you need. > =20 > Assets can embed their structure definitions within themselves - = they're trivially small binary packets - and since tools contain their = own sense of how a 3d scene, say should be stored, the metadata system = can modify the data on the fly, rather than require everything to be = re-exported because you added a 'flags' field (a rule of game = development is that *everything* needs a flags field sooner or later!) > =20 > Actually, I just re-read your first paragraph and I think I = misunderstood what you were saying. So I'll amend my response to say = that unless you store *all* your definitions in *all* your assets, you = still won't be able to embed data in a MAX file, for instance. For that = sort of thing, we define 'entities' in a (not-C) header file, which is = used by our plugin to create a UI for whatever trigger/sound = effect/whatever the artist wants to embed. > =20 > Ultimately, most exported assets are kept in a platform-neutral state = and are turned into platform-specific forms during the build. The = platform-specific format definitions don't need to be specified using = the metadata script - anything that didn't know about the internals of a = PS3, say, wouldn't be able to do anything with a PS3 texture anyway, = which I store as a bunch of register values and an offset into a big = VRAM block. > =20 > Adrian > =20 > On Mar 18, 2013, at 5:33 PM, Jarkko Lempiainen wrote: >=20 >=20 > If you define your reflection in C++, you can still have external = tools for asset processing, because class definitions must be stored = along with assets. This is something you have to do regardless how you = implement your reflection (assuming you don=92t have cumbersome =93convert= all asset to new version whenever the class definition changes=94), = because different assets may use different versions of class definition = and you must be able to read & convert the old data to new version when = reading it. > =20 > Beyond basic class reflection, the reflection system must also be able = to handle special cases. For example when dealing with textures, you = reflection system must support =93custom reflection=94 definitions where = textures are read straight to the video memory without intermediate data = store. Or some classes may expose different set of members depending on = the instance of the class (think of exposing variants for example). I=92m = not sure how you would implement these with reflection defined in script = without special hacks in the reflection system. > =20 > =20 > Cheers, Jarkko > =20 > =20 > From: [email protected] = [mailto:[email protected]] On Behalf Of = Adrian Stephens > Sent: Monday, March 18, 2013 7:31 PM > To: [email protected] > Subject: Re: [Sweng-Gamedev] Reflection in game engine (c++) > =20 > =20 > I'm glad we're still talking about this - I think it's important and I = wanted to add my own observations: > =20 > The macro/template approach to reflection only applies to one side of = the data/code interface. If all you need to do is serialize runtime = data to be read back in by runtime code, then you're ok; but if you want = to access that metadata from an external tool, you either have to = recompile the tool or plugin when anything changes, or write something = that parses that code. > =20 > If you're going to have to write a parser anyway, it seems to me you = might as well use it for both code and data views. Which means you can = use a more natural syntax for your structure definitions that even = non-programmers can use. > =20 > To map this back into your C++ code, you can pretty trivially write = out header files containing typedefs that correspond to the metadata, = and generate whatever you need to allow the runtime to interpret = serialized data. This also address the separation of code and assets: = we don't want artists having to sync the code, and this keeps the data = definitions with the assets that they define. > =20 > This is what I do, anyway. I have a data language, which defines = types, and which can also be used to define data, and all data is stored = using these definitions. This includes bitmaps, sounds, models, etc. = The data language is separated from the data representation so this = doesn't imply that bitmaps are stored in a script-like array of colors - = but it does mean that tools can use the reflection system on more = classes of data than just small gameplay entities. And when = distinctions like that are removed, and all things are treated the same = way, lots of clever things just fall out. > =20 > Some other random thoughts: > As far as I can see, all C++ needs to allow full reflection is some = sort of fieldsof(T) operator that enumerates the fields of a structure. = e.g. (typed straight into email, so probably bollocks - and not = representative of my actual system!) > =20 > struct metadata { > enum TYPE {INT, PTR, ARRAY, STRUCT} type; > metadata(TYPE &_type) : type(_type) {} > }; > template<typename A, typename... B> struct md_fields : md<A>, = md_fields<B> {}; > template<typename T> struct md : metadata, md_fields<fieldsof(T)> { = md() : metadata(STRUCT) {} }; > template<typename T> struct md<T*> : metadata { md<T> t; md() : = metadata(PTR) {} }; > template<typename T, int N> struct md<T[N]> : metadata { int n; md<T> = t; md() : metadata(ARRAY), n(N) {} }; > template<> struct md<int> : metadata { md() : metadata(INT) {} }; > =20 > template<typename T> metadata *get_md(const T &t) { static md<T> m; = return &m; } > =20 > =20 > =20 > Adrian Stephens > =20 > On Mar 18, 2013, at 10:45 AM, Douglas Cox wrote: >=20 >=20 >=20 > That sounds pretty similar to the goals of the engine that we're = working on -- basically faster iteration times for everyone (this = includes engine programmers as well). > =20 > All of our code (including the compiler) is written in a C#-like = language, so we have perfect reflection from that. Attributes are = pretty much required for providing additional information to property = editors for things like valid ranges of a field or notifications of a = property change (most of which can go away in Final builds). > =20 > Another thing to consider may be allowing for data derivation. This = can save quite a bit of work when the need for copies of objects come up = that only need one or two properties changed. If you pick a = serialization format for the editable data that knows about the data = (fieldtype + fieldname + value), it makes it a lot easier to get this = working. > =20 > In the past, we've used Macros and they worked fine. They're a bit = more annoying to extend with optional parameters and you have to repeat = the field/property name, but that's not terrible since you can generally = get it down to compile-time errors if you get something wrong (other = than forgetting to add a new field). > =20 > -Doug > =20 > =20 >=20 > On Fri, Mar 15, 2013 at 3:45 AM, Tinco Andringa <[email protected]> wrote: > I think the point of the discussion is to not just assume C++ isn't > going to do it. As far as I understand the goal is to have the ability > to develop tools that aid programmers and artist in iterating rapidly. > This means for artists that they can swap artwork in at runtime or > quickly boot the game from a serialized state with new artwork, not > just on his/her own computer but also over a network to perhaps a > console. For programmers this may mean that they can view the game > state easily, launch the game in various states easily, swap in/out > scripts easily, maybe even change code without fully recompiling or > even restarting the game. >=20 > Am I missing something important? >=20 > On Fri, Mar 15, 2013 at 8:33 AM, Massimo Del Zotto = <[email protected]> wrote: > > I have limited experience but I have been very impressed by the = separation > > provided by scripting languages. > > Considering the goals: > > > > My goal is to have fast iteration times, both artists and = programmers > > > > It appears to me C++ isn't going to do it. Especially on the artist = side of > > the thing. > > > > By the way, I would like to have an insight on how this reflection > > information is to be used. If it is used to simulate duck typing I'd = use a > > tool which supports duck typing natively. > > > > Massimo > > > > _______________________________________________ > > Sweng-Gamedev mailing list > > [email protected] > > = http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.co= m > > > _______________________________________________ > Sweng-Gamedev mailing list > [email protected] > = http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.co= m > =20 > _______________________________________________ > Sweng-Gamedev mailing list > [email protected] > = http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.co= m > =20 > _______________________________________________ > Sweng-Gamedev mailing list > [email protected] > = http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.co= m > =20 > _______________________________________________ > Sweng-Gamedev mailing list > [email protected] > = http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.co= m --Apple-Mail=_F4199CB3-D11E-4BD8-9E5D-72C8DEFCD9CB Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=windows-1252 <html><head><base href=3D"x-msg://1219/"></head><body style=3D"word-wrap: = break-word; -webkit-nbsp-mode: space; -webkit-line-break: = after-white-space; "><div><br></div><div>Yes, sorry - the first part of = my response was addressing keeping C header files with the assets. = When I re-read what you wrote I realized you were talking about = keeping the metadata as part of each asset, and I agree with that. = My second point was that external tools need to allow people to = create new entities based on some list of templates, and for that the = tools still need access to those definitions. If all you need to = do is 'process' existing assets, the embedded data would be = enough. </div><div><br></div><div>If I add a new variable to my = textures, old textures will still load and be given the default value = for that field. I think we agree on why and how that's a good = thing!</div><div><br></div><div>I do use the same reflection system for = all the data - there really are no special cases - but the the language = you use to specify a type definition is always going to be turned into = some internal representation at some point; how you express those types = is not as important as the ability to treat the data in a uniform way in = code. So - in the interest of full disclosure - some of my = reflection data *is* generated using templates and macros in C++ files! = Perhaps that's cheating, but a platform-specific texture, say, is = meaningless outside the code that generates it and the code that uses = it. There's nothing to be gained by deferring to an external = language for that.</div><div><br></div><div>Perhaps the 'system' part of = 'reflection system' needs more consideration. The important part = to me is the ability to treat all data uniformly and automatically, and = empower artists and designers to create, browse and combine assets = arbitrarily. I don't really care where the types or the data come = from as long they can be uniformly interpreted by tools and game code. = You shouldn't need to stab a reflection system whose only goal is = this. If you want to create some types in code, or javascript or = embedded in flash it's no problem as long as the end result is = interpretable by everyone = else.</div><div><br></div><div>Adrian</div><div><br></div><div><br></div><= div><div>On Mar 19, 2013, at 11:26 AM, Jarkko Lempiainen wrote:</div><br = class=3D"Apple-interchange-newline"><blockquote type=3D"cite"><span = class=3D"Apple-style-span" style=3D"border-collapse: separate; = font-family: Helvetica; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; line-height: normal; = orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: = none; white-space: normal; widows: 2; word-spacing: 0px; = -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: = 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: = auto; -webkit-text-stroke-width: 0px; font-size: medium; "><div = lang=3D"EN-US" link=3D"blue" vlink=3D"purple"><div class=3D"WordSection1" = style=3D"page: WordSection1; "><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><span style=3D"font-size: = 11pt; font-family: Calibri, sans-serif; color: rgb(31, 73, 125); ">If = you plan to interpret data, you need to parse those class definitions = anyway, regardless how you define & store them. Furthermore, you = *have to* embed the definitions in asset files if you don=92t want to do = mass asset conversions every time you change definitions + you can=92t = guarantee access to all the data using specific definition anyway. These = asset files also need to store only definitions for objects that are = stored within that given asset file, not all your definitions (wasn=92t = sure if this was what you actually meant, but wanted to clear that = up).<o:p></o:p></span></div><div style=3D"margin-top: 0in; margin-right: = 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: 12pt; = font-family: 'Times New Roman', serif; "><span style=3D"font-size: 11pt; = font-family: Calibri, sans-serif; color: rgb(31, 73, 125); = "><o:p> </o:p></span></div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><span style=3D"font-size: = 11pt; font-family: Calibri, sans-serif; color: rgb(31, 73, 125); ">So, = if you add a new variable to your textures (e.g. color space variable to = define how to interpret the texture), you have to rebuild all your = texture assets? I don=92t see why you wouldn=92t just use the same = reflection system for all the data. Another example is container = classes, which I have seen requiring special treatment by reflection = systems. I think reflection system needs to be powerful enough to be = usable for all type of data and that you shouldn=92t need to add special = cases for handing different types anywhere outside the type definition. = Otherwise I end up stabbing the reflection system every time I have a = special case.<o:p></o:p></span></div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><span style=3D"font-size: = 11pt; font-family: Calibri, sans-serif; color: rgb(31, 73, 125); = "><o:p> </o:p></span></div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><span style=3D"font-size: = 11pt; font-family: Calibri, sans-serif; color: rgb(31, 73, 125); = "><o:p> </o:p></span></div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><span style=3D"font-size: = 11pt; font-family: Calibri, sans-serif; color: rgb(31, 73, 125); = ">Cheers, Jarkko<o:p></o:p></span></div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><span style=3D"font-size: = 11pt; font-family: Calibri, sans-serif; color: rgb(31, 73, 125); = "><o:p> </o:p></span></div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><span style=3D"font-size: = 11pt; font-family: Calibri, sans-serif; color: rgb(31, 73, 125); = "><o:p> </o:p></span></div><div><div style=3D"border-right-style: = none; border-bottom-style: none; border-left-style: none; border-width: = initial; border-color: initial; border-top-style: solid; = border-top-color: rgb(181, 196, 223); border-top-width: 1pt; = padding-top: 3pt; padding-right: 0in; padding-bottom: 0in; padding-left: = 0in; "><div style=3D"margin-top: 0in; margin-right: 0in; margin-left: = 0in; margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "><b><span style=3D"font-size: 10pt; font-family: Tahoma, = sans-serif; ">From:</span></b><span style=3D"font-size: 10pt; = font-family: Tahoma, sans-serif; "><span = class=3D"Apple-converted-space"> </span><a = href=3D"mailto:[email protected]" = style=3D"color: blue; text-decoration: underline; = ">[email protected]</a><span = class=3D"Apple-converted-space"> </span>[<a = href=3D"mailto:[email protected]" = style=3D"color: blue; text-decoration: underline; = ">mailto:[email protected]</a>]<span = class=3D"Apple-converted-space"> </span><b>On Behalf Of<span = class=3D"Apple-converted-space"> </span></b>Adrian = Stephens<br><b>Sent:</b><span = class=3D"Apple-converted-space"> </span>Monday, March 18, 2013 = 10:44 PM<br><b>To:</b><span = class=3D"Apple-converted-space"> </span><a = href=3D"mailto:[email protected]" style=3D"color: blue; = text-decoration: underline; = ">[email protected]</a><br><b>Subject:</b><span = class=3D"Apple-converted-space"> </span>Re: [Sweng-Gamedev] = Reflection in game engine (c++)<o:p></o:p></span></div></div></div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "><o:p> </o:p></div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; ">Yes, you *can* keep your = class definitions with the assets, and have external tools read them - = but my point is that if you're going to be writing something that parses = these definitions, you don't gain much by defining them using contrived = macros and templates. I am proposing defining them in a simpler, = clearer way that can be easily parsed and spat out as headers, or = whatever else you need.<o:p></o:p></div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; = "><o:p> </o:p></div></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; ">Assets can embed their = structure definitions within themselves - they're trivially small binary = packets - and since tools contain their own sense of how a 3d scene, say = should be stored, the metadata system can modify the data on the fly, = rather than require everything to be re-exported because you added a = 'flags' field (a rule of game development is that *everything* needs a = flags field sooner or later!)<o:p></o:p></div></div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "><o:p> </o:p></div></div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">Actually, I just re-read your first paragraph and I = think I misunderstood what you were saying. So I'll amend my = response to say that unless you store *all* your definitions in *all* = your assets, you still won't be able to embed data in a MAX file, for = instance. For that sort of thing, we define 'entities' in a = (not-C) header file, which is used by our plugin to create a UI for = whatever trigger/sound effect/whatever the artist wants to = embed.<o:p></o:p></div></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; = "><o:p> </o:p></div></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; ">Ultimately, most exported = assets are kept in a platform-neutral state and are turned into = platform-specific forms during the build. The platform-specific = format definitions don't need to be specified using the metadata script = - anything that didn't know about the internals of a PS3, say, wouldn't = be able to do anything with a PS3 texture anyway, which I store as a = bunch of register values and an offset into a big VRAM = block.<o:p></o:p></div></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; = "><o:p> </o:p></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; = ">Adrian<o:p></o:p></div></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; = "><o:p> </o:p></div><div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; ">On Mar 18, 2013, at 5:33 = PM, Jarkko Lempiainen wrote:<o:p></o:p></div></div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "><br><br><o:p></o:p></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "><span style=3D"font-size: 11pt; font-family: Calibri, = sans-serif; color: rgb(31, 73, 125); ">If you define your reflection in = C++, you can still have external tools for asset processing, because = class definitions must be stored along with assets. This is something = you have to do regardless how you implement your reflection (assuming = you don=92t have cumbersome =93convert all asset to new version whenever = the class definition changes=94), because different assets may use = different versions of class definition and you must be able to read = & convert the old data to new version when reading = it.</span><o:p></o:p></div></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><span style=3D"font-size: = 11pt; font-family: Calibri, sans-serif; color: rgb(31, 73, 125); = "> </span><o:p></o:p></div></div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; "><span = style=3D"font-size: 11pt; font-family: Calibri, sans-serif; color: = rgb(31, 73, 125); ">Beyond basic class reflection, the reflection system = must also be able to handle special cases. For example when dealing with = textures, you reflection system must support =93custom reflection=94 = definitions where textures are read straight to the video memory without = intermediate data store. Or some classes may expose different set of = members depending on the instance of the class (think of exposing = variants for example). I=92m not sure how you would implement these with = reflection defined in script without special hacks in the reflection = system.</span><o:p></o:p></div></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><span style=3D"font-size: = 11pt; font-family: Calibri, sans-serif; color: rgb(31, 73, 125); = "> </span><o:p></o:p></div></div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; "><span = style=3D"font-size: 11pt; font-family: Calibri, sans-serif; color: = rgb(31, 73, 125); "> </span><o:p></o:p></div></div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "><span style=3D"font-size: 11pt; font-family: Calibri, = sans-serif; color: rgb(31, 73, 125); ">Cheers, = Jarkko</span><o:p></o:p></div></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><span style=3D"font-size: = 11pt; font-family: Calibri, sans-serif; color: rgb(31, 73, 125); = "> </span><o:p></o:p></div></div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; "><span = style=3D"font-size: 11pt; font-family: Calibri, sans-serif; color: = rgb(31, 73, 125); "> </span><o:p></o:p></div></div><div><div = style=3D"border-right-style: none; border-bottom-style: none; = border-left-style: none; border-width: initial; border-color: initial; = border-top-style: solid; padding-top: 3pt; padding-right: 0in; = padding-bottom: 0in; padding-left: 0in; border-width: initial; = border-color: initial; "><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><b><span = style=3D"font-size: 10pt; font-family: Tahoma, sans-serif; = ">From:</span></b><span class=3D"apple-converted-space"><span = style=3D"font-size: 10pt; font-family: Tahoma, sans-serif; = "> </span></span><a = href=3D"mailto:[email protected]" = style=3D"color: blue; text-decoration: underline; "><span = style=3D"font-size: 10pt; font-family: Tahoma, sans-serif; = ">[email protected]</span></a><span = style=3D"font-size: 10pt; font-family: Tahoma, sans-serif; "><span = class=3D"Apple-converted-space"> </span>[</span><a = href=3D"mailto:[email protected]" = style=3D"color: blue; text-decoration: underline; "><span = style=3D"font-size: 10pt; font-family: Tahoma, sans-serif; = ">mailto:[email protected]</span></a><span = style=3D"font-size: 10pt; font-family: Tahoma, sans-serif; ">]<span = class=3D"apple-converted-space"> </span><b>On Behalf Of<span = class=3D"apple-converted-space"> </span></b>Adrian = Stephens<br><b>Sent:</b><span = class=3D"apple-converted-space"> </span>Monday, March 18, 2013 7:31 = PM<br><b>To:</b><span = class=3D"apple-converted-space"> </span></span><a = href=3D"mailto:[email protected]" style=3D"color: blue; = text-decoration: underline; "><span style=3D"font-size: 10pt; = font-family: Tahoma, sans-serif; = ">[email protected]</span></a><span style=3D"font-size: = 10pt; font-family: Tahoma, sans-serif; "><br><b>Subject:</b><span = class=3D"apple-converted-space"> </span>Re: [Sweng-Gamedev] = Reflection in game engine = (c++)</span><o:p></o:p></div></div></div></div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "> <o:p></o:p></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "> <o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">I'm glad we're still talking about this - I think it's = important and I wanted to add my own = observations:<o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "> <o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">The macro/template approach to reflection only applies = to one side of the data/code interface. If all you need to do is = serialize runtime data to be read back in by runtime code, then you're = ok; but if you want to access that metadata from an external tool, you = either have to recompile the tool or plugin when anything changes, or = write something that parses that = code.<o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; = "> <o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; ">If you're = going to have to write a parser anyway, it seems to me you might = as well use it for both code and data views. Which means you can = use a more natural syntax for your structure definitions that even = non-programmers can use.<o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "> <o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">To map this back into your C++ code, you can pretty = trivially write out header files containing typedefs that correspond to = the metadata, and generate whatever you need to allow the runtime to = interpret serialized data. This also address the separation = of code and assets: we don't want artists having to sync the code, and = this keeps the data definitions with the assets that they = define.<o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; = "> <o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; ">This is what I = do, anyway. I have a data language, which defines types, and which = can also be used to define data, and all data is stored using these = definitions. This includes bitmaps, sounds, models, etc. The = data language is separated from the data representation so this doesn't = imply that bitmaps are stored in a script-like array of colors - but it = does mean that tools can use the reflection system on more classes of = data than just small gameplay entities. And when distinctions like = that are removed, and all things are treated the same way, lots of = clever things just fall out.<o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "> <o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">Some other random = thoughts:<o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; ">As far as I = can see, all C++ needs to allow full reflection is some sort of = fieldsof(T) operator that enumerates the fields of a structure. = e.g. (typed straight into email, so probably bollocks - and not = representative of my actual = system!)<o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; = "> <o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; ">struct = metadata {<o:p></o:p></div></div></div><div><div><div style=3D"margin-top:= 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; "><span = class=3D"apple-tab-span"> &= nbsp; </span><span = class=3D"apple-converted-space"> </span>enum TYPE {INT, PTR, ARRAY, = STRUCT} type;<o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "><span = class=3D"apple-tab-span"> &= nbsp; </span><span = class=3D"apple-converted-space"> </span>metadata(TYPE &_type) : = type(_type) {}<o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">};<o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">template<typename A, typename... B> struct = md_fields : md<A>, md_fields<B> = {};<o:p></o:p></div></div></div><div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; ">template<typename = T> struct md : metadata, md_fields<fieldsof(T)> { = md() : metadata(STRUCT) {} };<o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">template<typename T> struct md<T*> : = metadata { md<T> t; md() : metadata(PTR) {} = };<o:p></o:p></div></div></div><div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; ">template<typename T, = int N> struct md<T[N]> : metadata { int n; md<T> t; md() = : metadata(ARRAY), n(N) {} };<o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">template<> struct md<int> : metadata { md() = : metadata(INT) {} };<o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "> <o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">template<typename T> metadata *get_md(const T = &t) { static md<T> m; return &m; = }<o:p></o:p></div></div></div><div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; = "> <o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; = "> <o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; = "> <o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; ">Adrian = Stephens<o:p></o:p></div></div></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; = "> <o:p></o:p></div></div><div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; ">On Mar 18, = 2013, at 10:45 AM, Douglas Cox = wrote:<o:p></o:p></div></div></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; = "><br><br><br><o:p></o:p></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; ">That sounds = pretty similar to the goals of the engine that we're working on -- = basically faster iteration times for everyone (this includes engine = programmers as well).<o:p></o:p></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "> <o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">All of our code (including the compiler) is written in = a C#-like language, so we have perfect reflection from that. = Attributes are pretty much required for providing additional = information to property editors for things like valid ranges of a field = or notifications of a property change (most of which can go away in = Final builds).<o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "> <o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">Another thing to consider may be allowing for data = derivation. This can save quite a bit of work when the need for = copies of objects come up that only need one or two properties changed. = If you pick a serialization format for the editable data that = knows about the data (fieldtype + fieldname + value), it makes it a lot = easier to get this working.<o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "> <o:p></o:p></div></div></div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">In the past, we've used Macros and they worked fine. = They're a bit more annoying to extend with optional parameters and = you have to repeat the field/property name, but that's not terrible = since you can generally get it down to compile-time errors if you get = something wrong (other than forgetting to add a new = field).<o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; = "> <o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; = ">-Doug<o:p></o:p></div></div></div><div><div><div style=3D"margin-top: = 0in; margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; = font-size: 12pt; font-family: 'Times New Roman', serif; = "> <o:p></o:p></div></div></div></div><div><p class=3D"MsoNormal" = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 12pt; font-size: 12pt; font-family: 'Times New Roman', = serif; "> <o:p></o:p></p><div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; ">On Fri, Mar 15, 2013 at = 3:45 AM, Tinco Andringa <<a href=3D"mailto:[email protected]" = target=3D"_blank" style=3D"color: blue; text-decoration: underline; = ">[email protected]</a>> wrote:<o:p></o:p></div></div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">I think the point of the discussion is to not just = assume C++ isn't<br>going to do it. As far as I understand the goal is = to have the ability<br>to develop tools that aid programmers and artist = in iterating rapidly.<br>This means for artists that they can swap = artwork in at runtime or<br>quickly boot the game from a serialized = state with new artwork, not<br>just on his/her own computer but also = over a network to perhaps a<br>console. For programmers this may mean = that they can view the game<br>state easily, launch the game in various = states easily, swap in/out<br>scripts easily, maybe even change code = without fully recompiling or<br>even restarting the game.<br><br>Am I = missing something important?<o:p></o:p></div></div><div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "><br>On Fri, Mar 15, 2013 at 8:33 AM, Massimo Del Zotto = <<a href=3D"mailto:[email protected]" style=3D"color: blue; = text-decoration: underline; ">[email protected]</a>> = wrote:<br>> I have limited experience but I have been very impressed = by the separation<br>> provided by scripting languages.<br>> = Considering the goals:<br>><br>> My goal is to have fast iteration = times, both artists and programmers<br>><br>> It appears to me C++ = isn't going to do it. Especially on the artist side of<br>> the = thing.<br>><br>> By the way, I would like to have an insight on = how this reflection<br>> information is to be used. If it is used to = simulate duck typing I'd use a<br>> tool which supports duck typing = natively.<br>><br>> = Massimo<br>><o:p></o:p></div></div></div></div><div><div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; ">> = _______________________________________________<br>> Sweng-Gamedev = mailing list<br>><span class=3D"apple-converted-space"> </span><a = href=3D"mailto:[email protected]" style=3D"color: = blue; text-decoration: underline; = ">[email protected]</a><br>><span = class=3D"apple-converted-space"> </span><a = href=3D"http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnight= ryder.com" target=3D"_blank" style=3D"color: blue; text-decoration: = underline; = ">http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.= com</a><br>><br>_______________________________________________<br>Swen= g-Gamedev mailing list<br><a = href=3D"mailto:[email protected]" style=3D"color: = blue; text-decoration: underline; = ">[email protected]</a><br><a = href=3D"http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnight= ryder.com" target=3D"_blank" style=3D"color: blue; text-decoration: = underline; = ">http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.= com</a><o:p></o:p></div></div></div></div></div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; "> <o:p></o:p></div></div></div><div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; = ">_______________________________________________<br>Sweng-Gamedev = mailing list<br><a href=3D"mailto:[email protected]" = style=3D"color: blue; text-decoration: underline; = ">[email protected]</a><br><a = href=3D"http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnight= ryder.com" style=3D"color: blue; text-decoration: underline; = ">http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.= com</a><o:p></o:p></div></div></div><div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; = "> <o:p></o:p></div></div><div style=3D"margin-top: 0in; = margin-right: 0in; margin-left: 0in; margin-bottom: 0.0001pt; font-size: = 12pt; font-family: 'Times New Roman', serif; "><span style=3D"font-size: = 13.5pt; font-family: Helvetica, sans-serif; = ">_______________________________________________<br>Sweng-Gamedev = mailing list<br></span><a = href=3D"mailto:[email protected]" style=3D"color: = blue; text-decoration: underline; "><span style=3D"font-size: 13.5pt; = font-family: Helvetica, sans-serif; = ">[email protected]</span></a><span = style=3D"font-size: 13.5pt; font-family: Helvetica, sans-serif; = "><br></span><a = href=3D"http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnight= ryder.com" style=3D"color: blue; text-decoration: underline; "><span = style=3D"font-size: 13.5pt; font-family: Helvetica, sans-serif; = ">http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.= com</span></a><span style=3D"font-size: 13.5pt; font-family: Helvetica, = sans-serif; "><o:p></o:p></span></div></div></div><div = style=3D"margin-top: 0in; margin-right: 0in; margin-left: 0in; = margin-bottom: 0.0001pt; font-size: 12pt; font-family: 'Times New = Roman', serif; = "><o:p> </o:p></div></div></div></div>_______________________________= ________________<br>Sweng-Gamedev mailing list<br><a = href=3D"mailto:[email protected]" style=3D"color: = blue; text-decoration: underline; = ">[email protected]</a><br><a = href=3D"http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnight= ryder.com" style=3D"color: blue; text-decoration: underline; = ">http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.= com</a></div></span></blockquote></div><br></body></html>= --Apple-Mail=_F4199CB3-D11E-4BD8-9E5D-72C8DEFCD9CB-- --===============0808720945== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Sweng-Gamedev mailing list [email protected] http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.com --===============0808720945==--