0

I'm helping a friend work on a rpg mod in Java, we basically want to give the administrators of the server a chance to provide his/her own formulas to calculate the outcome of some events.

For instance right now we have an event that happens 1% of the time, and the chance increases by 1% every level of the character. How can we make it so that the server admin is able to specify a function based on the character level that returns a chance for that event to happen?

Is there a way to do that safely, since Java has no direct lambda support? Possibly without having to write a tokenizer that parses the string and executes the function?

In php I might use eval to do such a thing (once I sanitized the input) but in Java I'm stumped.

Madness
  • 49
  • 1
  • 11

4 Answers4

2

Why not use some scripting language, like Groovy, that can very nicely integrate with Java (you can pass parameters from Java and get the result back to Java). Then you don't have to write your own parser and could also go beyond simple math formulas if the need arose. (Be aware that on the other hand you might have to restrict the use of Groovy, to prevent some security issues, see for instance here how to do this.)

Community
  • 1
  • 1
Janick Bernet
  • 20,544
  • 2
  • 29
  • 55
  • +1 for groovy with Java. Possibly you want to be aware of the security implications of this though too. – Flexo Aug 20 '11 at 15:17
  • The ram usage is a BIG issue, the more lightweight the better, consider we might drop this functionality rather than get something too heavy. – Madness Aug 20 '11 at 15:20
  • +1. JavaScript could alwo be used. It's natively supported by Java. See http://download.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.html – JB Nizet Aug 20 '11 at 15:22
  • @Madness: I don't think Groovy will use that much RAM. I would not drop it without investigating if that is really an issue first. – Janick Bernet Aug 20 '11 at 15:22
  • @awoodland: I just added something about security implications. – Janick Bernet Aug 20 '11 at 15:22
  • Security is partially relevant, as the ppl handling the config are the server admins. – Madness Aug 20 '11 at 15:32
0

Maybe you should allow only some kind of functions i.e sum of a xn where x is level After that you can store it as array of pairs a,n

I don't think you will use something like sin. Usually it will be something like ax+b

RiaD
  • 46,822
  • 11
  • 79
  • 123
  • Allowing for a parameter-only customization is what we're doing right now, but we're checking to see if there's another option available – Madness Aug 20 '11 at 15:21
0

If the expressions you need to evaluate are limited to relatively simple arithmetic, maybe some string manipulation and object property accessor/method calls, then I would look into using one of the readily available expression language libraries and see if they suffice, such as MVEL or OGNL.

Otherwise, as others have pointed out, if you need more complex behaviour consider full-fledged scripting languages such as Groovy or JRuby.

Alistair A. Israel
  • 6,417
  • 1
  • 31
  • 40
0

If you want to avoid a scripting language like Groovy, then you might want to consider using a configuration syntax that permits you to specify name=list-of-values. Let's assume the syntax is:

name = [ "list", "of", "values" ];

With such a syntax, you could specify pairs of values to provide a mapping from character level to probability of event occurring. If the character levels go from 1 to 10 and the default probabilities mirror the character level, then the entry in the configuration file would be:

level_to_probability_mapping = [
    # character level  -->  probability
    #----------------------------------
      "1",                  "1",
      "2",                  "2",
      "3",                  "3",
      "4",                  "4",
      "5",                  "5",
      "6",                  "6",
      "7",                  "7",
      "8",                  "8",
      "9",                  "9",
      "10",                 "10",
];

If your config-file syntax supports only name=single-value syntax, then you can emulate name=list-of-values by setting the value to be a string that contains comma-separated items, and then use java.util.StringTokenizer or String.split() to break up the string to gain access to the individual items.

A different approach that is much more flexible but dangerous because it allows a person to execute arbitrary code is as follows...

Step 1. Define a Java interface (or abstract base class) that defines one method. For example:

interface ProbabilityCalculator {
    public int calculateProbabilityForLevel(int level);
}

Step 2. Write a "default" class that implements that interface using a simple algorithm.

Step 3. Permit administrators to write their own class that implements the above interface, and add a jar file containing that class to the application's CLASSPATH.

Step 4. Have a variable in the configuration file specify the name of a class that implements the above interface. If this variable is not present in the configuration file, then fall back to using the name of the default implementation class.

Step 5. Use Java's reflection API to create an instance of the class specified in the configuration file, and then invoke its calculateProbabilityForLevel() method.

If you are not already familiar with Java reflection, then have a look at my Java Reflection Explained Simply presentation to learn what you will need to know.

Ciaran McHale
  • 2,126
  • 14
  • 21
  • The problem with the first approach is that there are potentially infinite levels. The problem with the second is that I want people to give me functions, not large chunks of code. :| If the javascript thing ends up being viable I might just do that, but boy, am I spoiled by the scripting languages benefits. – Madness Aug 22 '11 at 08:51