Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (491)
Games in Android Showcase (112)
games submitted by our members
Games in WIP (556)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2
  ignore  |  Print  
  Using code generation in your game.  (Read 8916 times)
0 Members and 1 Guest are viewing this topic.
Online actual

JGO Coder


Medals: 23



« Posted 2012-03-31 13:16:19 »

I was curious if anyone used code generation (writing code that writes code) in their projects. I haven't seen the technique described in the context of java game development but I have dabbled in it a bit and have liked what it gives me and may look for opportunities to do more. I want two things which seem to work against one another. I want to be able to specify things in config/data files because it is often the most convenient and least error prone way to do so. I also want what I specify to be used as if it were hard coded and to take advantage of Java's built in type checking. For instance, if I describe my ExplosionEvent message in a data file:

1  
2  
3  
+ Explosion
  position mygame.util.Vector3
  strength float


I want to be able to say things like:

1  
System.out.println("BOOM " + explosion.strength);


instead of

1  
System.out.println("BOOM " + (float)explosion.getParam("strength"));


So I have code (in a separate project) that reads in the message config file, and generates a java file for each message definition in the appropriate directory in my game project code. (I suppose i could change the build so that it automatically creates a jar that I import instead).

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
public class ExplosionMessage extends Message {
   
   public final mygame.util.Vector3 position;
   public final float strength;


   public ExplosionMessage(Entity sender, Entity recipient, mygame.util.Vector3 position, float strength) {
      super(sender,recipient);
      this.position = position;
      this.strength = strength;
   }
}




Pros
  • More efficient. Properties are fields not entries in a hashmap.
  • lds not property maps. Message types are classes not a generic message type with a name parameter.
    Compile time safety. If, in my game code, I misspell a property I will get a compile time error, not a run time error.
    Because the fields are explicitly typed, I don't have to do a lot of casting.
Cons

  • Extra project/code necessary to do the conversion of config file to java classes
  • An extra build step
For me, the cons are hardly a bother (if you are using external config files, you need to write some code to read it into your game engine anyhow and running the CodeGen code takes seconds). Event messages are the simplest application of this because they are simple data containers but I could see the potential for trying to do more.

Does anyone else do anything like this? What has your experience been?


Offline Danny02
« Reply #1 - Posted 2012-03-31 13:37:37 »

mm,
I don't quite understand why you want to generate a java source file from a config file.

The other way around makes propably more sense, generating some config data from a source file.

Besides, in Java one can use the annotations processing functionality of the java compiler for code generation. Just google it, its quite usefull. Take a look at project Lombock for example. In Netbeans you also get the benefit of support of this processors in your coding environment.  http://netbeans.org/kb/docs/java/annotations-lombok.html

I for example wrote an own processor to automatically create the config files needed for the java util ServiceLoader: my processor
Offline 65K
« Reply #2 - Posted 2012-03-31 13:44:21 »

Why not set up a simple GameRules by yourself class which reads all properties at startup (early failure in case of mispelling) with methods like getExplosionStrength() ?
That way, you wont duplicate the essential information.

Code generation is mostly a bad approach, IMHO. Quite popular in Java business development, though. Unfortunately.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline 65K
« Reply #3 - Posted 2012-03-31 13:48:51 »

Add-On: If I want to experiment with different game paramters, I just want to edit plain text files. No build hassle. Could even be re-read while the game is running.

Offline Danny02
« Reply #4 - Posted 2012-03-31 13:55:48 »

so how do you think of compiling your generated source code at runtime?

I know that you can do it with a custom classlaoder and so on, but remember that only developers have the javac installed
Online actual

JGO Coder


Medals: 23



« Reply #5 - Posted 2012-03-31 14:04:01 »

Quote from: Danny02
I don't quite understand why you want to generate a java source file from a config file.
The motivation is that I need a set of Java source files that all look very similar except for some minor differences. The config file allows me to express those differences succinctly. Thanks for the annotation processing links, I will check them out.

 
Quote from: 65k
Why not set up a simple GameRules by yourself class which reads all properties at startup (early failure in case of mispelling) with methods like getExplosionStrength() ?
That way, you wont duplicate the essential information.

I guess I am not quite following what you mean here. I have a set of messages each with their own set of properties. I am not using the config files to determine the content of the messages, only their structure. Or maybe I am confused by what you are saying.

Quote from: 65k
Code generation is mostly a bad approach, IMHO. Quite popular in Java business development, though. Unfortunately.
Funny you should say this given my background Smiley.  But yes, I agree that the code generation code can quickly get brittle and hard to understand. That's why I picked doing it for messages, as the classes are very simple.
Online actual

JGO Coder


Medals: 23



« Reply #6 - Posted 2012-03-31 14:06:33 »

so how do you think of compiling your generated source code at runtime?

Compiling the source at run time isn't a big deal to me. If I need to create a new set of messages:

1. Add it to the config
2. Run the CodeGen project
3. The source files are now injected in my game project

The only thing players will see is the final, compiled game.
Offline 65K
« Reply #7 - Posted 2012-03-31 14:10:37 »

I have a set of messages each with their own set of properties. I am not using the config files to determine the content of the messages, only their structure. Or maybe I am confused by what you are saying.
Now I am confused...

Quote from: 65k
Code generation is mostly a bad approach, IMHO. Quite popular in Java business development, though. Unfortunately.
Funny you should say this given my background Smiley.  But yes, I agree that the code generation code can quickly get brittle and hard to understand. That's why I picked doing it for messages, as the classes are very simple.
Hah ! Another business guy here  Cool

Online actual

JGO Coder


Medals: 23



« Reply #8 - Posted 2012-03-31 14:26:32 »

I have a set of messages each with their own set of properties. I am not using the config files to determine the content of the messages, only their structure. Or maybe I am confused by what you are saying.
Now I am confused...

A significant part of my game is going to be event driven which means I am going to have a number of different message types. These message types will all inherit from a base class and are pretty simple except for the properties they expose. So let's say I am writing a new part of my game and I need 5 new message types. Rather than write 5 new java files, with all of the boiler plate, I want to make entries into the config file and then run the code generation. It will read in the config file and produce the code for those 5 message types.

What I am not talking about here is save game data. The player would never see or interact with this set up. This is purely for me as the developer to use. Let's say my game has 15 message types with an average of 3 fields a piece. That is 15 source files, 11 lines a piece (165 total) vs. a single file that contains nothing but simple parameters. I acknowledge that Doing this or not certainly is not going to make or break a game project.
Offline 65K
« Reply #9 - Posted 2012-03-31 14:42:40 »

Ok, now I understand. But I wouldn't generate event code. In fact I have events as well, and it sucks writing the serialization code each and every time.
With code generation you would have the same information twice in your project.
What if the simple code generation isn't sufficient any more, what if some messages need special code, what if the generator overwrites changes by accident ?
If events would be based on external tools/formats maybe, but writing meta files by yourself instead of writing Java files ?

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Online actual

JGO Coder


Medals: 23



« Reply #10 - Posted 2012-03-31 15:25:45 »

For the messages I am talking about it works well because it is simple and there is no custom code per message but I do see where things can get complicated. Part of my motivation for posting this was to see if anyone else had tried and what their pain points were.

For instance different entity types respond to different messages but because they each respond to messages differently you couldn't really do code generation unless you included the java code in the config file itself which seems like a bad idea.
Offline ra4king

JGO Kernel


Medals: 345
Projects: 3
Exp: 5 years


I'm the King!


« Reply #11 - Posted 2012-03-31 17:26:16 »

Concerning your original post: that is impossible.

Think about it this way: you want to generate new code at runtime, but you also want the non-existing variables to compile without errors....at compile-time. That makes no sense. Those variables don't exist.

I think what you're trying to do is beyond overkill. Make those variables exist at compile-time, since you already know you are going to use them.

Online actual

JGO Coder


Medals: 23



« Reply #12 - Posted 2012-03-31 18:23:51 »

Maybe I haven't been explaining myself well. I am not looking to generate new code at run time and it isn't impossible as I have been doing it. This is about programmatically generating code that I then use at development time in order to develop the game.

Let's say I am writing up some new functionality, and I think I am going to need 5 new types of events. How would I do this normally? I would write out the 5 new classes. I could then use them in my project. How would I do that in my set up? I would at the entries for the new Event types to the config file. Run the CodeGen (right click and hit run, < 6 seconds start to finish). The source for those same 5 classes are now in the proper directory in my game project and I can use them in my project just like the classes I hand coded.

What does it get me? If I need a new event called AttackEvent I can write:
1  
2  
3  
+ Attack
attackType String
damage     int


instead of
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
package mygame.events;

public class AttackEvent extends Event {

   public final String attackType;
   public final int damage;

   public AttackEvent(Entity sender, Entity receiver, String attackType, int damage) {
      super(sender,receiver);
      this.attackType = attackType;
      this.damage = damage;
   }
}


The other thing it buys me is that it is easier for me to see all of the events I currently have defined as well as their properties. One nice list as opposed to n different java files. Think of it more like a JSP for java code.
Offline ra4king

JGO Kernel


Medals: 345
Projects: 3
Exp: 5 years


I'm the King!


« Reply #13 - Posted 2012-03-31 18:42:08 »

Ohh so you basically just created a program that creates the classes for you from the given properties. You so lazzyyyyy Grin

Online actual

JGO Coder


Medals: 23



« Reply #14 - Posted 2012-03-31 19:14:05 »

Ohh so you basically just created a program that creates the classes for you from the given properties. You so lazzyyyyy Grin

Yes...and hell yes. Smiley

Isn't that supposed to be a virtue?
Offline StumpyStrust
« Reply #15 - Posted 2012-03-31 21:03:25 »

Hmmm the only thing I have done similar to this is my particle editor which outputs .java class files so you can easily use them instead of writing every effect you want from scratch but it does not do it at runtime just makes a .txt file or something similar.

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #16 - Posted 2012-04-01 09:44:18 »

I'm still confused over why nobody got the intent of your original post. It's not like its rocket science.

What you are doing is OK, and at least >9000x better than working with (hash)maps to store properties.

Keep in mind that you overwrite Java source files: eventually you want to put methods on this Events, and you'll run into trouble. I suggest you generate abstract classes, and extend them with the versions that provide the methods.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
package mygame.events;

public abstract class GeneratedAttackEvent extends Event {

   public final String attackType;
   public final int damage;

   public AttackEvent(Entity sender, Entity receiver, String attackType, int damage) {
      super(sender,receiver);
      this.attackType = attackType;
      this.damage = damage;
   }
}


1  
2  
3  
public class AttackEvent extends GeneratedAttackEvent {
   // ...
}

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Online actual

JGO Coder


Medals: 23



« Reply #17 - Posted 2012-04-01 15:09:35 »

Thanks Riven, that's a good idea. I know that I do not want to have pure java code in my config files but wasn't sure how to apply this technique to game structures that include methods.
Offline Archibald

Junior Member


Projects: 1



« Reply #18 - Posted 2012-04-01 21:15:57 »

The self rewriting code was in various languages for ages and after a longer/shorter while it was always announced as obsolete/unrecommended/bad/lame (regardless of what language it was, which is a curious thing Smiley). There were always 2 points raised:

1) Inferior performance (missed cache in case of machine code/assembler language, unable to utilize the most advanced compilers in case of interpreted languages).
2) It's a bad coding practice (the end conclusion was always that the people who used it could have done it another way which would be better, in short people who used it were doing something wrong with their coding style or simply didn't knew how to do it properly).

Again, this is a historical thing, not necessarily related to your concept. Still, so far all self rewriting/coding generation was always marked as a bad thing by a huge majority of programmers which means you should think twice if this does apply to your situation or not.
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #19 - Posted 2012-04-01 21:32:11 »

Point 1 is not even relevant, as the code is compiled, just like everything else - hence this argument doesn't hold in any language. Even if it was runtime generated, it would perform like any other class in Java, because the JVM does nothing but loading classes just in time (not to be confused with HotSpot/JIT). In short, why are you even bringing this up as a counter point?

Point 2 is even worse. So you'd prefer unsafe dynamic typing with lookups in hashmaps? Four downsides: overly verbose accessors, IDE refactoring won't work, deplorable performance and a huge number of runtime errors, due to typos in the property names and/or assuming the wrong type of a property.

And please don't say that you told us that it might not necessarily be relevant in this context, because the provided use case is trivial and could be taken into consideration before posting.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Archibald

Junior Member


Projects: 1



« Reply #20 - Posted 2012-04-01 22:02:12 »

Point 1 is not even relevant, as the code is compiled, just like everything else - hence this argument doesn't hold in any language. Even if it was runtime generated, it would perform like any other class in Java, because the JVM does nothing but loading classes just in time (not to be confused with HotSpot/JIT). In short, why are you even bringing this up as a counter point?
Missed cache in assembly language. At first it was fine and a valid technique, but after introduction of L1/L2 cache it was becoming very bad (since you can't cache self rewritten machine code, cache has to be invalidated and the code read again).

Sure, you might say it is not relevant in this case NOW. But hey, back then it was not considered bad at first as well, it is later they invented the cache and it was all messed up. The same story is PHP eval() function and the Zend Optimizer, which again was invented later (you can't tokenize a code that is dynamic generated). It happened at least twice so far, so it is only fair if I post about history of this kind of techniques. That's relevant enough to justify a post IMHO Smiley

Quote
And please don't say that you told us that it might not necessarily be relevant in this context, because the provided use case is trivial and could be taken into consideration before posting.
You are not very friendly you know Smiley And being angry all the time is bad for skin Smiley
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #21 - Posted 2012-04-02 05:31:51 »

I hate to repeat myself, but we're discussing code generation at compile-time here. It would have performed just as well in ASM / PHP.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline davedes
« Reply #22 - Posted 2012-04-02 06:08:59 »

If you have many (IMO more than ~20) instances where you need to generate code.. I can see it's benefit. Otherwise, I see it as overkill.

Feel free to prove me wrong -- I find code generation interesting and would like to learn some practical uses for it in gereral game development (assuming such a thing even exists).

Offline sproingie

JGO Kernel


Medals: 202



« Reply #23 - Posted 2012-04-02 06:25:07 »

This is not "self-rewriting code", it's simply static class generation, an extra compile step.  These weird tangents about cache misses are comparing apples to drive shafts.  It's a perfectly sound methodology, and while I might consider it overkill for a few instances, I can't see anything wrong with it.  It's certainly safer than stuffing every attribute into a Map at runtime, where one typo will throw everything out of whack.
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #24 - Posted 2012-04-02 06:25:26 »

We should all try to steer clear of code generation. On the other hand, we should also try to steer clear of mundane tasks, like writing repetitive and/or overly verbose struct-like code in Java. In the end it's about finding the balance in usability and maintainability.

For example, when you generate code for primitive lists, sets and maps, not using code generation becomes undefendable. Java falls short in some areas and verbosity can certainly be one of them. We even have IDE plugins that take the burden of writing such code off of the developer - needless to say they all use code generation behind the scenes.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Danny02
« Reply #25 - Posted 2012-04-02 09:37:39 »

So I have time again to reply.
I think, when uyou use normal java classes you won't need to write that much more code.
Instead of extending the Event class all the Time, why not just add generic event data.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
class Event<E>
{
  private final E data;
  public E getData();
}

class AttackData
{
  public final AttackType type;
  public final int amount;
}

...
Event<AttackData> e = new Event<>(new AttackData(FIRE, 50));
...


I don't see how writing this simple class is more work then adding your config to a textfile.
With the class you can use all the benefits of the IDE, like code completion which maks writing the class over 9000 times faster then the config file.
Also you can do refactoring and so on, which you can't do with your config file. And I would thingk that stuff like alot of event datas can change a lot while devoloping.
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #26 - Posted 2012-04-02 10:53:12 »

The whole problem is that the above code doesn't work. You need 'a lot' of boilerplate, which is the mundane/verbose part I was talking about and what the original poster was trying to get rid of.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Skarion

Senior Member


Medals: 2
Projects: 1



« Reply #27 - Posted 2012-04-02 11:21:46 »

Point 2 is even worse. So you'd prefer unsafe dynamic typing with lookups in hashmaps? Four downsides: overly verbose accessors, IDE refactoring won't work, deplorable performance and a huge number of runtime errors, due to typos in the property names and/or assuming the wrong type of a property.

Java is verbosity.

To avoid verbosity you usually go to other programming languages, for instance Python.

The errors you mentions, except said verbosity, is handled by avoiding double maintenance.

For instance if the programmer has a specific attribute he wish to aquire and he knows he otherwise would've generated with his code generator, the programmer usually creates a static final enum as to avoid double maintenance. Thereby IDE refactoring works, typo errors are impossible and you can't assume the wrong type of property.

As long as the kind of events aren't changed constantly during runtime there isn't even any performance issues if you use for example an enummap.

Code generation is a classic code smell.

An example of this solution is unit/object retrieval for a game.

As the main difference between these are just parameter values you create a master class, and then you load at runtime the units/objects you wish to have from for example a textfile. Each master class with given parameters are put into an enummap and then can be aquired by a getter with an enum parameter.
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #28 - Posted 2012-04-02 11:54:20 »

I don't see how your proposed solution makes it better. The added abstraction layer of getters and enums will lead to increased code verbosity throughout the project, which is (IMHO) an even bigger problem than typing out all those classes by hand.

Maybe I'm mistaken, and you could enlighten us with a code sample.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Online actual

JGO Coder


Medals: 23



« Reply #29 - Posted 2012-04-02 13:37:02 »

So I have time again to reply.
I think, when uyou use normal java classes you won't need to write that much more code.
Instead of extending the Event class all the Time, why not just add generic event data.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
class Event<E>
{
  private final E data;
  public E getData();
}

class AttackData
{
  public final AttackType type;
  public final int amount;
}

...
Event<AttackData> e = new Event<>(new AttackData(FIRE, 50));
...


I don't see how writing this simple class is more work then adding your config to a textfile.
With the class you can use all the benefits of the IDE, like code completion which maks writing the class over 9000 times faster then the config file.
Also you can do refactoring and so on, which you can't do with your config file. And I would thingk that stuff like alot of event datas can change a lot while devoloping.

Sorry, there is no way that writing out a new class is 9000x faster than updating my config file. Let's say you want to create a new Event called ShipArrived that has 4 parameters, the entity id of the ship that has arrived, and it's x, y, and z parameters. I would type:

+ ShipArrived
entity int
x float
y float
z float


Save it, right click on the project in my IDE and click run and the message class would be available for me to use. Literally 10 seconds from the time I open the config file to the time i can start using it in my game. Are you saying that writing out a new class would be 9000x faster?

Also, on the usage side, I can now say
AttackEvent e = new AttackEvent(FIRE,50);

or

int damage = 10 * e.amount;

which is cleaner than what you have above.



Part of the motivation for doing it in the first place is that I often find myself, adding, removing, and editing message types and this config file is an easier place to do this.
Pages: [1] 2
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Nickropheliac (15 views)
2014-08-31 22:59:12

TehJavaDev (23 views)
2014-08-28 18:26:30

CopyableCougar4 (29 views)
2014-08-22 19:31:30

atombrot (41 views)
2014-08-19 09:29:53

Tekkerue (38 views)
2014-08-16 06:45:27

Tekkerue (35 views)
2014-08-16 06:22:17

Tekkerue (25 views)
2014-08-16 06:20:21

Tekkerue (34 views)
2014-08-16 06:12:11

Rayexar (72 views)
2014-08-11 02:49:23

BurntPizza (48 views)
2014-08-09 21:09:32
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!