Action script that is compiled... better way?

Yet another interesting (hopefully) question about game design from Demonpants. :slight_smile:

I have a level editor for my game that should theoretically let you do anything you want. It can. Anyway, aside from the general interface that places different objects, resizes, identifies them, edits them, etc., there is an advanced event script that is used to do everything in-game, like for example killing a character if the player moves somewhere.

The code is fairly simple, but I couldn’t think of a good way to compile it, really. The usual 3 pass method didn’t seem like it would work here because I am not turning it into any sort of byte code or whatever, I am putting it into a readable in-game format.

So here is what I do:


if: (man.getX() > 200):
{
     man.move(200,man.getY());
}:

The example code will keep the object named ā€œmanā€ from moving past the 200 pixel spot on the screen. It complies like so:

First, the string is split up by the colons ā€˜:’. This theoretically splits it into the statement (if, else if, else), the condition (either boolean or comparator), and the action (statements separated by semicolons), and keeps doing this until it runs out of what I have called phrases.
In this case, it finds if, and so creates a new statement, which it passes the condition and the action to. The statement’s constructor then automatically creates conditions and actions as it needs to.

It knows how to evaluate it all in this way:
The LinkedList of phrases contains other LinkedList’s. Each separate LinkedList within the main list represents a different group of if/elses. Each LinkedList that does not contain another LinkedList contains Statements. It tries to perform the statements from left to right, if any of them evaluate to true, then it exits from that LinkedList. (it is a string of if… else if… else if… etc. statements)
In this case, there is the list of phrases with a single LinkedList that has a single Statement to represent the one above.

Each statement has a LinkedList for conditions and a LinkedList for actions. The conditions list can contain other lists, like the phrases list, only in this case it represents AND/OR conditions, along with paranthetical evaluation. The exact way it saves it unimportant, as long as you understand it does it in much the same way as the phrases list. The actions list is simply a list of actions to be performed.
In this case, the conditions list has a single LinkedList with a single Condition stored in it to represent the one above.

Each condition holds a single left operand, operator, and right operand. The operands are arrays of integers. If the operand is only length one, then it simply stores an integer value. Whereas if the operand is greater than length one, then it stores a reference to an object and one of their methods. Each object that has been given a variable name is added to a special ordered IDList upon compilation, and each object has a collection of static final ints to represent methods, and ways to access them. Therefore, every spot in the operand following the first is calling the method off the item before. (pretty convoluted, no?) Then, the operator is a simple integer that is assigned one of 6 static final values to represent the different types of operators. If there is no operator, then the left operand is a boolean condition.
In this case, the left operand might be {0,1}, the operator is 2, and the right operand is {200}

Each action is an array of integers that is accessed in the same way as the operands in each condition, but each parameter is added to the array after the actual call to the method. Any method calls within method calls are stored separately, in their own array within the main array,
In this case, the action might be {0,3,200,{0,2}}

And there you have it, more or less. Every single timestep, the game cycles through every phrase it needs to (ignoring any elses after a performed if), and performs any of them that evaluate to true. This is ALL saved through integers so it is much more efficient than compile on the fly or something like that, but I’ve had a lot of bugs getting it to work and wonder if there’s a better way.

So anybody got any suggestions? Anyone followed me at all? If you have questions about it, just ask. How do people usually do this? Should I use maps like in normal compilation?

Ugh, that’s really long.

I forgot to mention that I really don’t give a rat’s ass about compilation efficiency, as that only happens once and it happens in the level editor. What really matters is the efficiency within the actual game.

And ease of programming is nice too, as I’ve had to fix more bugs in my convoluted way of doing things than I think I ever have in one specific segment of a program, only to result in something that could create some unforseen issues with different ways of programming.

Um maybe Im missing something BUT

Why dont you either:
(a) write a real Recursive Descent Parsing compiler and then a little VM that interprets your own byte code.
Its really easy to write actually and there are plenty of good books on the subject of writing LL1 RDP parsers

I like ā€œCrafting a Compilerā€ myself. I have the classic edition in Pascal but apparently there is a Java version now: http://www.amazon.com/exec/obidos/tg/detail/-/0201385937/qid=1124342014/sr=8-2/ref=pd_bbs_2/002-1035582-1741626?v=glance&s=books&n=507846

(b) Write a compiler using a tool like Antlr and then the vm as above.

Ā© Just write java code and dynamically load classes? You can even compile a .java fiel to a .class file from your program by calling the javac class in the sun JDK.

Myself Id do Ā©.

Me Too post time.

Jeff is dead on the money, Ā© is the easiest way for you.

Though if you want it all to be a bit more dynamic you might consider one of the Java scripting languages. Personally, I’ve only ever used BeanShell.

Kev

… (d) write java byte code directly with ASM : http://asm.objectweb.org

Okay, Ā© definitely sounds like a good idea, while (d) looks like it could be very good as well. Which one will give me most balanced efficiency/ease of use, do you guys think?

If I dynamically load classes, how do I still know all the logic? Is it pretty much just looking through a file for various information of what? Any of you guys have some example code that does something similar so I can have a look?

ASM sounds like it’s doing pretty much the same thing, except that it’s doing it faster or gives you more control? Hmm…

I’ll start looking into this. Thanks as always, guys.

I found and read this: http://www.javaworld.com/javaworld/jw-09-1997/jw-09-howto.html and it seems to be what you guys are talking about, but I don’t see exactly how this can help me build a compiler…

If you are doing Ā© you dont build a compiler.
You just create an API, let your suers write Java code that talks to that API, write that to a .java file and call the javac class to compile it to a .class file. Then you dynmically load the class file.

If you are doing (d) then you need to write a compiler that generates bytecodes. Thsi is easy enough if you know how and have the right rools, thats why I gave you a refernce to a good book on writing compilers and a pointer to a parser-generator (ANTLR). You then write a classloader that you cna feed your synthetic byte codes to create classes from.

If you are doing (a) or (b) then you define your own bytecodes, write an interpreter that understands those byte codes, and a compiler like in (d) above except instead of generating Java bytecodes you generate your own.

That article is msotly orthogonal to what you want to do, btw.

The only really common thing is the dynamic laod of a class.

Okay, I see now! Ā© sounds excellent. Although it of course leads me to a few more questions.

  1. I have two separate applications, one for compiling and one for running. The compiler saves everything to a file, the other program reads the file and interprets it. Simple enough, except for the fact that references, of course, cannot be saved to a file. And even if they were, variable names created in the compiler will not transfer over to the running program… so how do I solve that? Should I just do what I did before and change it to calls to a list instead?

  2. I have a simple text editor for the API, which should be fine. Then, do I simply create the .java file the same way I would save a text file but using the .java extension? javac is a command in the terminal. What is the name of the class that calls it? (there is no Javac class in the API, obviously) Then I dynamically load the class like in the article?

Thanks for spending all this time on little old me. Hopefully other people can look back at these threads later and will find them useful.

Then you should go for beanshell : bsh is source-compatible with java, so it can interpret java source files, and later, you compile those classes with javac.

javac is available from the tools.jar, included in the jdk but not in the jre.

Lilian

If I understand your question correctly, then what you want is soem form of symbolic reference that cna be stored. This can be as simple as storing each of your obejcts in a large list and converting references to the objects to references into the list at save time and then converting abckla t load time.

Mayny systems use ā€œtagsā€ to solve this problem. NWN does this. Every game obecjt is given a unique tag when it is created. You then have an API call for the user code that willr eturn an object given its tag at runtime.

Okay, I already pretty much did tags, but saved a little time by only putting objects the user gives a tag to into the list. So I’ll load it all up in the same way, then.

And that article looks to be exactly what I need. Thanks for the pointers!

After I get it all to work, I’ll make a conclusion post with a step by step process for all of this like I did in my other thread.

The problem it seems to me with using java in any way is that you limit the number of people who can make content for your game to ppl who know java. And ppl who know java(or other programming language fairly well) are not (in my experience) likely to be they ones making content for your game (non-commmercial game). A script language like graalscript from graalonline.com seems to me a good way to go as i remeber making levels and npcs for graal years ago using the simple script without any knowledge of any other progaming.

just a thought floating around my head…

The most successful scripting lnaguages to date have all been one-offs that no-one knew (NWNC, QuakeC).
Furthermore they were based on C syntax which is a lot harder to learn then Java syntax.

So IMHO its a non-issue.

Yeah, it really doesn’t make much of a difference, for several reasons:

  1. Included point-and-click code generator. Using Swing I’ve created a JList of various commonly used actions that will automatically generate the proper Java when you select one of them. This means that unless you want to get incredibly deep within the game, you don’t need any previous knowledge other than simple logic processing and using a mouse. :wink:

  2. Easy Docs and examples are provided, making it very easy to learn how to do things. It’s not like people are making full fledged programs. You rarely need to even declare a variable. You create all Sentients and other objects using the easy interface, then you reference tagged ones in your code. It’s all incredibly easy.

  3. I always learned how to code by looking at examples, and by the time this is released there will be a) every designed levelto look at and b) tutorial levels and a flash tutorial included for potential coders.

As long as you show people how to do it well enough, it’s not like Java is a difficult thing to learn. :slight_smile:

Roboforge was a great example of this. They had an entire tree-based editor for writing your robot logic, which generated a Java calss out the back end.

And there is alsoa wealth of info on Java coding, something that isnt true for most point-solution scripting languages.

due to c’s simplicity I actually think it’s a lot LESS complex than java! so I understand why one would base a scripting language on it.

Well either way Java isn’t very complicated, and because my level editor can generate commonly used code for you (as well as letting you save your own common code to be used with 3 clicks), I think this is a non-issue. People will learn simple programming practices and syntax by looking at what is created, enough that they should be able to modify it if they want to.

Id disagree.

C is highly obtuse. Not very reasable except to C experts, In general a bad synatx for the goals of a scripting language.

It is easier to implement then Java because its a preocedural language, but ofcourse you dont have to implement Java :slight_smile:
You can hide Java’s OOness if you want to in the editor if your doing an event driven system. You have the user write what is methoid code and you wrap it in an object to compile it