Java-Gaming.org Hi !
Featured games (91)
games approved by the League of Dukes
Games in Showcase (798)
Games in Android Showcase (234)
games submitted by our members
Games in WIP (865)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Storing entity state in Map<String,Object>  (Read 25642 times)
0 Members and 1 Guest are viewing this topic.
Offline ags1

JGO Kernel


Medals: 367
Projects: 7


Make code not war!


« Posted 2015-10-30 11:56:55 »

I am storing entity state in a map. I build up entities by composition (so an entity is a list of behaviors and other properties), but I'm writing all the state to a shared map to simplify serialization. Knowing me, I need a simple way of saving state that does not rely on me remembering repeatedly to write instance variables to file.

I know it's not the most efficient approach, but I want to stay sane Smiley

I'm wondering about my string keys. Would there be a significant difference in the lookup performance in a map with longer keys ("Behavior/CraftBehavior/workCompleted") or one with short keys ("work")? I'm guessing that the hashing algorithm takes time proportional to the length of a string?

Offline Catharsis

JGO Ninja


Medals: 76
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #1 - Posted 2015-10-30 12:20:18 »

It's probably not horrendous since HashMap should be using hashCode and only do further checks if there is a clash. Since strings are immutable I gather the hash code is stored and not generated every time the method is called.

OpenJDK: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/HashMap.java#336

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Offline KevinWorkman

« JGO Plugged Duke »


Medals: 288
Projects: 12
Exp: 12 years


HappyCoding.io - Coding Tutorials!


« Reply #2 - Posted 2015-10-30 12:34:54 »

No need to guess. Why don't you just look at the source for String.hashCode()?

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }


So yes, it does appear that String stores its hash after the first time it's calculated.

But the best way to answer this question is by doing some benchmarking with your actual use case. What are the exact Strings? How many are there? What are the Objects? What's the load factor of your HashMap? How many entries does it have?

I would guess that this is a non-issue and you're suffering from premature optimization. Don't sweat the small stuff.

HappyCoding.io - Coding Tutorials!
Happy Coding forum - Come say hello!
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline princec

« JGO Spiffy Duke »


Medals: 1107
Projects: 3
Exp: 20 years


Eh? Who? What? ... Me?


« Reply #3 - Posted 2015-10-30 12:45:58 »

We could generalise on that a bit and have a general maxim:

Performance only matters on a frame-by-frame basis. Everything else can be slow and inefficient*.

Cas Smiley

* Until proven otherwise

Offline Roquen

JGO Kernel


Medals: 518



« Reply #4 - Posted 2015-10-30 16:27:53 »

If you're looking up something up enough that it effects performance, then that something needs to be moved out of the map and into the entity.  It's common thing and not a specializing thing.

I personally wouldn't go the only type you store is a String route.  It's a usage pain.  I stuck a bare-bones, dumbest thing on the planet skeleton here: https://github.com/roquendm/JGO-Grabbag/tree/master/src/roquen/wiki/dvar

The worst thing is really that Java's hash-maps implementation blows chunks...but that doesn't really matter either unless you have lots of stuff in your maps.
Offline Dane

Senior Newbie





« Reply #5 - Posted 2015-10-31 19:43:48 »

I don't know if this is recommended but

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
class KeyValue {
   Map<Object, Object> values = new HashMap<>();
   
   public <T> T get(Object key) {
      return (T)values.get(key);
   }
   
   public void put(Object key, Object value) {
      values.put(key, value);
   }
}


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
KeyValue kv = new KeyValue();

kv.put("test", "Hi I'm a thing");
kv.put(1, 123);
kv.put("myvalue", 123);

String s = kv.get("test");
int i = kv.get(1);
int j = kv.get("myvalue");

System.out.println(s + ", " + i + ", " + j);


compiles to:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
KeyValue kv = new KeyValue();

kv.put("test", "Hi I'm a thing");
kv.put(Integer.valueOf(1), Integer.valueOf(123));
kv.put("myvalue", Integer.valueOf(123));

String str = (String)kv.get("test");
int i = ((Integer)kv.get(Integer.valueOf(1))).intValue();
int j = ((Integer)kv.get("myvalue")).intValue();

System.out.println(str + ", " + i + ", " + j);
Offline Roquen

JGO Kernel


Medals: 518



« Reply #6 - Posted 2015-11-01 09:57:37 »

My take is:

Allowing anything to be a key isn't useful.
The transforms the compiler is providing for you are very expensive and don't buy you anything interesting. 
You're opening up runtime errors.
int k = kv.get("test");
Offline Catharsis

JGO Ninja


Medals: 76
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #7 - Posted 2015-11-01 10:43:16 »

My take is that what we're talking about here is a "poor man's" component architecture implementation regardless of storing by strings or objects.

It ignores the main benefit of Java which is the Class / type system. I've gone down the full component architecture implementation path with TyphonRT.

A simplified / reduced example from the API:
1  
2  
3  
4  
5  
6  
7  
8  
   public final <T extends IComponent> T getAs(@Nonnull Class<T> componentType) { ... }

   public final <T extends IComponent> boolean set(@Nonnull Class<T> componentType, @Nonnull T component) { ... }


   // Basic usage
   entity.set(Stuff.class, new Stuff());
   Stuff stuff = entity.getAs(Stuff.class);


The nice thing about using the type system to your advantage is that it allows type safety for setting and getting objects / components out of the container. In my efforts I also allow storage in a List by type and retrieving a protected iterator by type.

The big trouble spot for all Java entity systems / component architectures is the trick of storing multiple single components or collections by the same type. I've overcome that by some really fancy extensible enum tricks and generic method signatures for the component architecture API.

You can do:

1  
2  
3  
4  
5  
6  
7  
   // LEFT_ENGINE, RIGHT_ENGINE come from an extensible enum let's say `Engines` and statically imported. 

   entity.set(LEFT_ENGINE, new Engine());
   entity.set(RIGHT_ENGINE, new Engine());

   Engine engineLeft = entity.getAs(LEFT_ENGINE);
   Engine engineRight = entity.getAs(RIGHT_ENGINE);


So, in short for the OP. What you are doing is a pseudo solution and one that ignores the biggest benefit of Java which is the type system. I'd say take a look at the various entity system implementations out there. They are adequate, but not as far as things can actually be taken.

For now check out:
https://github.com/junkdog/artemis-odb
https://github.com/libgdx/ashley

One day I'll release the beast / TyphonRT...  Roll Eyes

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Offline micecd

Junior Devvie


Medals: 8



« Reply #8 - Posted 2015-11-03 05:29:12 »

If you're going component architecture, you don't have to follow the articles everyone googles and follows.
Using the <T extends ComponentType> and then making the ComponentType class is such a mess, unless you want to make it your mess then go for it.

Here's what I do, I make a hashset, and then use integers to identify the component type, then I use strings to hold the values (to take away from the oop side of programming in case I'm using over 9000 objects with this.)

The reason why is simple.

"Check if this entities collides with collide-able entities."
How do we do that?
Well instead of using a 'T extends Collideable', we just store the entity that's collideable in a Set of values that are collideable. If they aren't in that Set, they aren't solid.

I think that's what you're going after.

You will probably want to have an indexer create tags for each unique object you are using, place that object in a Map with an Integer (Tag) as the key and the Entity as the value.

Then take all the information of that entity and pass it through a class that keeps track of the Sets of entities with attributes of a certain type so that you don't have to perform excessive forloop iterations.

Seems redundant, but it's better than going through every entity you have and checking it for specific conditions, when you can hold a set for said conditions to iterate over.
Offline Catharsis

JGO Ninja


Medals: 76
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #9 - Posted 2015-11-03 06:19:19 »

@micecd Your reply is diverging from the OP topic which is a way to store / retrieve data with an emphasis on serialization.

I also should have commented on serialization aspects in my previous post as that is the goal of the OP. Of course by storing data using the Java type system aids serialization since one can use the type data during serialization and deserialization.

I probably should have given the simple code example as:
1  
2  
3  
public final <T> T getAs(@Nonnull Class<T> type) { ... }

public final <T> boolean set(@Nonnull Class<T> type, @Nonnull T object) { ... }


The "<T extends IComponent>" you misunderstood perhaps as there is no separate "ComponentType" class. It's just the Class of the object one is storing. In my CA (component architecture) I have a component interface (IComponent) which just provides a few extra methods for resetting state and recycling the component / basic house keeping on top of "Object" that makes something a "component" in the context of my CA.

The rest of your post diverges into other topics of which there are reasonable solutions in my CA, but are beyond discussing in this thread. I can agree with this though, "If you're going component architecture, you don't have to follow the articles everyone googles and follows."

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Roquen

JGO Kernel


Medals: 518



« Reply #10 - Posted 2015-11-03 08:53:06 »

Mimicking prototype based variables is far from poor man's component based.
Offline princec

« JGO Spiffy Duke »


Medals: 1107
Projects: 3
Exp: 20 years


Eh? Who? What? ... Me?


« Reply #11 - Posted 2015-11-03 09:07:55 »

I just realised @ags1 never quite mentioned what the actual use case was for the question.

If it's for modestly persistent storage (in-game entity hibernation) I'd use reflective serialization. If it's long-term storage I'd use either a database (if there are a lot) or just file-per-entity containing, say, JSON, which again would be generated automatically using reflection and annotations.

Cas Smiley

Offline Catharsis

JGO Ninja


Medals: 76
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #12 - Posted 2015-11-03 10:21:38 »

Mimicking prototype based variables is far from poor man's component based.

How so? I wouldn't really connote it to "mimicking prototype" / prototypical inheritance ala Javascript. The basic Map<String, Object> store has nothing to do with being prototype based or prototype properties IMHO. Losing all typing in a typed language does not make it or mimic being prototypical.

As a side note while I've been waiting for Vulkan in the past 3 months I've been jamming on a lot of modern ES6 Javascript framework dev to get around the 30% tax for mobile apps for a new product. Hell hath frozen over and after 20 years I can now say I don't hate Javascript w/ a passion. With ES6 + JSPM / SystemJS for package management / modularization it's actually pretty neat.

I just realised @ags1 never quite mentioned what the actual use case was for the question.
If it's for modestly persistent storage (in-game entity hibernation) I'd use reflective serialization.

If it's just for serialization and @ags1 is sticking with OOP indeed this is the way to go for the normal use case and there are plenty of serialization libraries that support this well.

If @ags1 is taking a step towards the entity system / component architecture route ala implicit composition then indeed there are better solutions.

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Offline Roquen

JGO Kernel


Medals: 518



« Reply #13 - Posted 2015-11-03 10:41:52 »

Quote
The basic Map<String, Object> store has nothing to do with being prototype based or prototype properties IMHO.
Of course one can take multiple views of manual feature extensions.  Having an instance that at runtime one can add new fields and/or methods is the origin of prototype based as a programming model.

Quote
Losing all typing in a typed language does not make it or mimic being prototypical.
That's not a requirement.  You can choose whatever level of strong vs. weak typing you want.
Offline ags1

JGO Kernel


Medals: 367
Projects: 7


Make code not war!


« Reply #14 - Posted 2015-11-03 11:25:11 »

I just realised @ags1 never quite mentioned what the actual use case was for the question.

If it's for modestly persistent storage (in-game entity hibernation) I'd use reflective serialization. If it's long-term storage I'd use either a database (if there are a lot) or just file-per-entity containing, say, JSON, which again would be generated automatically using reflection and annotations.

Cas Smiley

That is obviously a much better solution, it is pretty simple and it takes away my performance concerns. The goal would be to have a system that does not require per-field mapping. For example, annotation only the fields I don't want to persist... Also it gives me the opportunity to work with annotations a bit more; the only ones I use on a day-to-day basis are the JUnit and TestNG ones.

It's not going to be a file-per-entity; that would be 60k+ files.

Also, nothing in Vangard hibernates Smiley

EDIT: ....and I now have a prototype no-per-field-coding reflection approach working!

Offline Catharsis

JGO Ninja


Medals: 76
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #15 - Posted 2015-11-03 19:04:58 »

EDIT: ....and I now have a prototype no-per-field-coding reflection approach working!

Any reason you wouldn't use something like Kryo?

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Offline ags1

JGO Kernel


Medals: 367
Projects: 7


Make code not war!


« Reply #16 - Posted 2015-11-03 19:55:44 »

Because what I want to do is fairly trivial and I don't want to add a whole library to do single very specific task that I can accomplish in just a few lines.

Pages: [1]
  ignore  |  Print  
 
 

 
Riven (81 views)
2019-09-04 15:33:17

hadezbladez (4332 views)
2018-11-16 13:46:03

hadezbladez (1546 views)
2018-11-16 13:41:33

hadezbladez (4460 views)
2018-11-16 13:35:35

hadezbladez (863 views)
2018-11-16 13:32:03

EgonOlsen (4152 views)
2018-06-10 19:43:48

EgonOlsen (4855 views)
2018-06-10 19:43:44

EgonOlsen (2803 views)
2018-06-10 19:43:20

DesertCoockie (3707 views)
2018-05-13 18:23:11

nelsongames (3998 views)
2018-04-24 18:15:36
Java Gaming Resources
by philfrei
2019-05-14 16:15:13

Deployment and Packaging
by philfrei
2019-05-08 15:15:36

Deployment and Packaging
by philfrei
2019-05-08 15:13:34

Deployment and Packaging
by philfrei
2019-02-17 20:25:53

Deployment and Packaging
by mudlee
2018-08-22 18:09:50

Java Gaming Resources
by gouessej
2018-08-22 08:19:41

Deployment and Packaging
by gouessej
2018-08-22 08:04:08

Deployment and Packaging
by gouessej
2018-08-22 08:03:45
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!