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. =
&nbsp;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. =
&nbsp;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. &nbsp;If all you need to =
do is 'process' existing assets, the embedded data would be =
enough.&nbsp;</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. &nbsp;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. &nbsp;So - &nbsp;in the interest of full disclosure - some of my =
reflection data *is* generated using templates and macros in C++ files! =
&nbsp;Perhaps that's cheating, but a platform-specific texture, say, is =
meaningless outside the code that generates it and the code that uses =
it. &nbsp;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. &nbsp;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. &nbsp;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. =
&nbsp;You shouldn't need to stab a reflection system whose only goal is =
this. &nbsp;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 &amp; 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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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">&nbsp;</span><a =
href=3D"mailto:[email protected]" =
style=3D"color: blue; text-decoration: underline; =
">[email protected]</a><span =
class=3D"Apple-converted-space">&nbsp;</span>[<a =
href=3D"mailto:[email protected]" =
style=3D"color: blue; text-decoration: underline; =
">mailto:[email protected]</a>]<span =
class=3D"Apple-converted-space">&nbsp;</span><b>On Behalf Of<span =
class=3D"Apple-converted-space">&nbsp;</span></b>Adrian =
Stephens<br><b>Sent:</b><span =
class=3D"Apple-converted-space">&nbsp;</span>Monday, March 18, 2013 =
10:44 PM<br><b>To:</b><span =
class=3D"Apple-converted-space">&nbsp;</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">&nbsp;</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>&nbsp;</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. &nbsp;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>&nbsp;</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>&nbsp;</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. &nbsp;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. &nbsp;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>&nbsp;</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. &nbsp;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>&nbsp;</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>&nbsp;</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 =
&amp; 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); =
">&nbsp;</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); =
">&nbsp;</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); ">&nbsp;</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); =
">&nbsp;</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); ">&nbsp;</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; =
">&nbsp;</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">&nbsp;</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">&nbsp;</span><b>On Behalf Of<span =
class=3D"apple-converted-space">&nbsp;</span></b>Adrian =
Stephens<br><b>Sent:</b><span =
class=3D"apple-converted-space">&nbsp;</span>Monday, March 18, 2013 7:31 =
PM<br><b>To:</b><span =
class=3D"apple-converted-space">&nbsp;</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">&nbsp;</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; ">&nbsp;<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; ">&nbsp;<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; ">&nbsp;<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. &nbsp;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; =
">&nbsp;<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, &nbsp;it seems to me you might =
as well use it for both code and data views. &nbsp;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; ">&nbsp;<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. &nbsp;This also address the&nbsp;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; =
">&nbsp;<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. &nbsp;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. &nbsp;This includes bitmaps, sounds, models, etc. &nbsp;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. &nbsp;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; ">&nbsp;<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. =
&nbsp;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; =
">&nbsp;<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;</span><span =
class=3D"apple-converted-space">&nbsp;</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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;</span><span =
class=3D"apple-converted-space">&nbsp;</span>metadata(TYPE &amp;_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&lt;typename A, typename... B&gt; struct =
md_fields : md&lt;A&gt;, md_fields&lt;B&gt; =
{};<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&lt;typename =
T&gt; struct md :&nbsp;metadata,&nbsp;md_fields&lt;fieldsof(T)&gt; { =
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&lt;typename T&gt; struct md&lt;T*&gt; : =
metadata {&nbsp;md&lt;T&gt; t;&nbsp;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&lt;typename T, =
int N&gt; struct md&lt;T[N]&gt; : metadata { int n; md&lt;T&gt; 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&lt;&gt; struct md&lt;int&gt; : 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; ">&nbsp;<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&lt;typename T&gt; metadata *get_md(const T =
&amp;t) { static md&lt;T&gt; m; return &amp;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; =
">&nbsp;<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; =
">&nbsp;<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; =
">&nbsp;<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; =
">&nbsp;<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; ">&nbsp;<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. =
&nbsp;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; ">&nbsp;<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. &nbsp;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. =
&nbsp;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; ">&nbsp;<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. =
&nbsp;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; =
">&nbsp;<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; =
">&nbsp;<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; ">&nbsp;<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 &lt;<a href=3D"mailto:[email protected]" =
target=3D"_blank" style=3D"color: blue; text-decoration: underline; =
">[email protected]</a>&gt; 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 =
&lt;<a href=3D"mailto:[email protected]" style=3D"color: blue; =
text-decoration: underline; ">[email protected]</a>&gt; =
wrote:<br>&gt; I have limited experience but I have been very impressed =
by the separation<br>&gt; provided by scripting languages.<br>&gt; =
Considering the goals:<br>&gt;<br>&gt; My goal is to have fast iteration =
times, both artists and programmers<br>&gt;<br>&gt; It appears to me C++ =
isn't going to do it. Especially on the artist side of<br>&gt; the =
thing.<br>&gt;<br>&gt; By the way, I would like to have an insight on =
how this reflection<br>&gt; information is to be used. If it is used to =
simulate duck typing I'd use a<br>&gt; tool which supports duck typing =
natively.<br>&gt;<br>&gt; =
Massimo<br>&gt;<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; ">&gt; =
_______________________________________________<br>&gt; Sweng-Gamedev =
mailing list<br>&gt;<span class=3D"apple-converted-space">&nbsp;</span><a =
href=3D"mailto:[email protected]" style=3D"color: =
blue; text-decoration: underline; =
">[email protected]</a><br>&gt;<span =
class=3D"apple-converted-space">&nbsp;</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>&gt;<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; ">&nbsp;<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; =
">&nbsp;<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>&nbsp;</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==--