JMonkey Entity System

I’m going to look into using an embedded OrientDB for a backend to an entity system. I think a graph database makes sense for this type of system.

@ogerlord said: @pspeed I have a few SQL questions, I thought about using reflection to save and load components: -What do you do if a component has a Vector or some other non basic type as an attribute? -Is it possible to prevent that multiple EntityId/Component objects are created instead of using the only instance that would be necessary? -How can i create the instance of a class if the components do not have the standard empty constructor? -Which SQL driver would you recommend? I am not that familiar with this topic
  1. I split it out into subfields. This is done automatically by my reflection code when creating the type mappings during startup. So Vector3f pos becomes fields “POS_X”, “POS_Y”, “POS_Z”.

  2. I don’t really understand the question or why it’s important if I do.

  3. Generally: don’t do it. If you must then you will have to have some kind of strategy pattern/factory for creating objects from fields and you won’t be able to be nice and general anymore.

  4. I’m using hsqldb. It’s really fast. I just use what it gave me. Actually, I run embedded right now.

@mifth said: - i think bullets should not be entities. If you shoot 1000 bullets per second.. you will get out of Long/Integer range.

I did think it was a little funny that you gave the exact example I’d use to disprove that reusing IDs was necessary. If you’d done the math maybe we could have avoided the detour. :slight_smile:

After all, java.util.Date uses long to count milliseconds since January 1st 1970. So if your game had been firing 1000 bullets per second since 43 years ago it would still have plenty of room left. :slight_smile:

Even with a 32 bit int, you could fire 100 bullets per second for an entire year before wrapping… I’d never use int, though.

The conclusion everyone has already stated: use long. don’t reuse IDs (it’s ultimately death)

Generally: don’t do it. If you must then you will have to have some kind of strategy pattern/factory for creating objects from fields and you won’t be able to be nice and general anymore.
But how can i load components from the database without this feature? Otherwise I would force all components to have an additional empty constructor and this is kind of dangerous i think.

And I know I’m beating a dead horse now, but just to give you an idea of the scale we are talking about…

Java’s System.nanoTime() returns long. This is counting 1/1000000000 th of a second. One billionth of a second. You’d have to fire 1 billion missiles per second to keep up with it.

Now, let’s say you did that.

Long has: 18446744073709551616 unique values.
As nanoseconds that’s: 18446744073+ seconds.
So through reduction: roughly 585 years before it wraps.

@ogerlord said: But how can i load components from the database without this feature? Otherwise I would force all components to have an additional empty constructor and this is kind of dangerous i think.

It’s not that dangerous. Anyone creating empty components will figure out really quickly. The alternative is 10x more complicated.

@pspeed said: It's not that dangerous. Anyone creating empty components will figure out really quickly. The alternative is 10x more complicated.

To elaborate:
Either the no-arg constructor is completely harmless because the component has useful defaults or non-reference fields.
…or it will NPE as soon as it hits the database.

Programmer thinks, “Oops”. Fixes the bug and moves on.

Maybe i am missing something here, but isn’t POJO - DB mapping exactly the thing hibernate covers.

[java]

@Entity
public class UserManagementData implements Serializable{
@Id
@GeneratedValue
@Column(name= “UserId”)
private int userId;

@Column(name=" UserName")
private String username;

@Column(name=" UserPassword")
private String userpassword;

public UserManagementData() {
}

public int getUserId() {
    return userId;
}

public void setUserId(int userId) {
    this.userId = userId;
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getUserpassword() {
    return userpassword;
}

public void setUserpassword(String userpassword) {
    this.userpassword = userpassword;
}

@Override
public String toString() {
    return "UserManagementData{" + "userId=" + userId + ", username=" + username + ", userpassword=" + userpassword + '}';
}

}
[/java]

could be a component for example. Loading/Storing and even creation of the database is done by hibernate magically.

@zzuegg said: Maybe i am missing something here, but isn't POJO - DB mapping exactly the thing hibernate covers.

[java]

@Entity
public class UserManagementData implements Serializable{
@Id
@GeneratedValue
@Column(name= “UserId”)
private int userId;

@Column(name=" UserName")
private String username;

@Column(name=" UserPassword")
private String userpassword;

public UserManagementData() {
}

public int getUserId() {
    return userId;
}

public void setUserId(int userId) {
    this.userId = userId;
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getUserpassword() {
    return userpassword;
}

public void setUserpassword(String userpassword) {
    this.userpassword = userpassword;
}

@Override
public String toString() {
    return "UserManagementData{" + "userId=" + userId + ", username=" + username + ", userpassword=" + userpassword + '}';
}

}
[/java]

could be a component for example. Loading/Storing and even creation of the database is done by hibernate magically.

Hibernate is a HUGE library of which an entity system will be using roughly 2%.

The entity system mapping is one-to-one and very straight forward. Hibernate is overkill in several significant ways.

am i missing something or is there no download link for this?

I can only warn against Hibernate. You’ll have a huge learning curve, and the only use case it’s built for is lots of small transactions where each transaction reads all required data. It doesn’t scale to moving large amounts of data, and it doesn’t scale to complicated data structures.
The advice on “long-running conversations” is just bullshit, you’ll always struggle with LazyInitializationExceptions. And the conversation will die at the drop of a hat, i.e. at the first exception that the JDBC stack may throw, so you’ll find yourself wrapping every single database activity into a restartable unit-of-work object; that’s usually not the design that you want.
Hibernate is good for code that does short-lived, low-volume units of work, but I found it to suck royally in every other use case. Game updates are not short-lived low-volume.

Also, while Hibernate helps with the impedance mismatch, it does not eliminate it. You’ll still spend an inordinate amount of time dealing with mapping Java classes to database tables, and class members to columns. It’s a huge amount of tedious and error-prone work.
For that reason alone, I usually want to keep the entire game state in RAM and serialize a snapshot to a flat file at regular intervals. If I use a text format instead of binary JME serialization, I can even inspect game state with a text editor (and unless the game data is really huge, more than a gigabyte, text search is “fast enough” on current-day machines). If I use YAML instead of XML, I don’t even have to worry about reference cycles and get a more compact, easier-to-read representation as a windfall profit.

Databases do have their use cases:

  1. If you can’t keep the entire game data in RAM. (In practice, that’s actually rare. Game data tends to be constantly modified across the board.)
  2. If you want to do statistics and data mining.
  3. If you want to scale to multiple servers that concurrently write to a common database. (Be warned that that scenario will always be problematic, with or without a database. Ask the Wikipediat about the CAP theorem for the underlying reasons why distributed data processing tends to suck in general.)

Personally, I’m a happy Snakeyaml user for small-scale game data.

hsqldb is kind of a nice middle ground as the tables are heavily cached and the writes are journaled. It’s super fast and most things will already be in memory.

…but it’s fast enough that I don’t need to think about it, really. My server’s database is getting pretty large and the only time I notice is when I have to restart the server after it went down unnaturally (happens rarely) and then I take the start up hit for resolving the journal.

I wouldn’t stream positions of physics objects to it 60 times per second… but nearly everything else is fine. (And I do push the physics positions periodically, too.)

If I have time this weekend and it doesn’t step on anyone’s toes, I may push my ES up to contrib.

7 Likes
@pspeed said: If I have time this weekend and it doesn't step on anyone's toes, I may push my ES up to contrib.

That would be cool contribution.

Thanks beforehand. :slight_smile:

Since i do not make any progress at the moment I released the present code for everyone who wants to have a look at it.
You can find the download link at the end of the first post.
Altough the example is working I do not reccomend to use this code in a project because its a pre-alpha version.

(And please fix the forum bug for me, I have to publish every new post/edit via the wordpress interface)

Can someone give me the permission to create new pages in the wiki?

You don’t need permission, the interface is a bit convoluted but you can do it already (although I can’t remember exactly how off hand).

You've followed a link to a topic that doesn't exist yet. If permissions allow, you may create it by using the Create this page button.
I cant see any button and because of this i think I do not have the permission.
@ogerlord said: I cant see any button and because of this i think I do not have the permission.
Move your cursor to the very top of the page, to the black menu bar. The last menu item should say "Wiki". The first item in that drop-down says "Edit page".

Ah thanks. I found the hidden button in the html file and used it.
But this way is more comfortable. XD

Can someone give me access to the contributions trunk? Than I would upload the entity system as a plugin.

This is my google account, now posting works without problems.
But you still do not send emails to people who register a new account here.