18 Apr, 2013, Nathan wrote in the 1st comment:
Votes: 0
I have been coding a mud server in Java for some time (see signature), and I'm wondering how best to represent properties of things. I've currently got a system for some things. For example, armor that a person might wear. At present, I have an object and an enum, Armor and ArmorType.

MUDObject -> Item -> Armor

Armor is the class for the object that you carry around and wear. ArmorType is an enum class where each enum represents a defined type of armor and holds basic properties of that armor like it's type (ex. light, medium, heavy, etc), cost, weight, etc.

Type           Name       Cost        P  G     S  C     AB DB AC   SPF   WHT
Type.LIGHT, "Padded", new int[] { 0, 5, 0, 0 }, 1, 8, 0, 0.05, 10)


Unfortunately, it recently occurred to me that this might present some problems. Namely that the current way of handling what Armor is is to assign it an ArmorType which is referenced when I want to know, say, what the Armor's armor bonus is. This is useful in that all padded armor, for instance, would be the same or it would be easy to tweak the "balance" of the equipment. Unfortunately this also means that new armor must be defined in that enum and care taken to not mess up the current arrangement (the "db" uses the enum ordinals for persistence) and differences must be handled as adjustments to the standard. Not a whole lot of flex here with regard to additional properties, etc.

I'm kind curious how other people would handle this kind of stuff in the code.

* I have been using some D&D/d20 stuff so far, just because it's a system where how combat and stuff works is defined for you.
18 Apr, 2013, quixadhal wrote in the 2nd comment:
Votes: 0
Why on earth would you use cryptic things like arrays and enums, when you could just use a mapping/associative-array?

mapping ArmorTypes = ([
"Type" : "Light",
"Name" : "Padded",
"Cost" : ([
"Platinum" : 0,
"Gold" : 5,
"Silver" : 0,
"Copper" : 0
]),
"AttackBonus" : 1,
"DefenseBonus" : 8,
"ArmorClass" : 0,
"SpeedFactor" : 0.05,
"Weight" : 10
]);


That's in LPC, but there are equivalents in every modern langauge.. only crufty things like C and C++ make doing that a big deal.
You mention using a database for persistence. If you're using an OBJECT database, you can just serialize the data and push it out.
If it's traditional SQL…

CREATE TABLE Costs (
CostID SERIAL NOT NULL PRIMARY KEY,
Platinum INTEGER,
Gold INTEGER,
Silver INTEGER,
Copper INTEGER
);

CREATE TABLE ArmorTypes (
"Type" TEXT NOT NULL,
Name TEXT NOT NULL,
CostID INTEGER NOT NULL REFERENCES Costs(CostID),
AttackBonus INTEGER,
DefenseBonus INTEGER,
ArmorClass INTEGER,
SpeedFactor FLOAT,
Weight INTEGER
);

BEGIN
INSERT INTO Costs (Platinum, Gold, Silver, Copper) VALUES (0, 5, 0, 0);
INSERT INTO ArmorTypes("Type", Name, CostID, AttackBonus, DefenseBonus, ArmorClass, SpeedFactor, Weight)
VALUES ('Light', 'Padded', LASTVAL(), 1, 8, 0, 0.05, 10);
– LASTVAL() is the most recently inserted/updated sequence value in PostgreSQL, others may have different ways to get this.


Plenty of ways to do it.

The point is, there's NO need to make your data structures cryptic and hard to maintain. Sure, it's a bit more typing, and today you see no value in it. But should you ever hand it off to someone else, or revisit in in 15 years, wouldn't it be nice to just look at the code, or a data dump, and SEE what everything is… without having to go look up what the 5th integer in array foobar is supposed to be?

If you want to keep things more generic and runtime extensible, you can always use tables that are more like key/value sets. The above shows the use of a table to represent an array (the coin data). You can also use junction tables and break everything down into name/value pairs with an instance ID tagging along.

IE;

INSERT INTO Properties (ObjectID, Key, Val) VALUES (1, 'Type', 'Light');
INSERT INTO Properties (ObjectID, Key, Val) VALUES (1, 'Name', 'Padded');
INSERT INTO Properties (ObjectID, Key, Val) VALUES (1, 'Platinum', '0');
INSERT INTO Properties (ObjectID, Key, Val) VALUES (1, 'Gold', '5');
INSERT INTO Properties (ObjectID, Key, Val) VALUES (1, 'Silver', '0');
INSERT INTO Properties (ObjectID, Key, Val) VALUES (1, 'Copper', '0');


The idea being, to restore Object 1, you'd select (key, val) from Properties where ObjectID = 1;
Then just loop through the resultset, assigning things as you go. There might even be an automation library to do this for you (I don't know java).
The downside is, you can't ensure type safety (the value column has to be serialized), and you can't use foreign keys or constraints as sanity checks either. The upside is, it's easy to changes things at runtime, since there are no fixed structures in the data layer.

You can, of course, mix the two with junction tables.
ArmorTypes above could have an ObjectID field which would then allow some properties to exist in key/value form.
19 Apr, 2013, Kline wrote in the 3rd comment:
Votes: 0
Nathan said:
Armor is the class for the object that you carry around and wear. ArmorType is an enum class where each enum represents a defined type of armor and holds basic properties of that armor like it's type (ex. light, medium, heavy, etc), cost, weight, etc.


This seems inordinately complex. Why not do something simpler like Object -> WearableObject and then use more generic properties from there such as protection value, cost, etc. Unless you explicitly want to ensure all "leather armor" is essentially identical? Maybe I'm confused with what your end goal here is. Basically, I don't see why you are defining every property of your ArmorType and restricting yourself only to those pre-defined properties. I could understand limits perhaps, and I have done such a system myself to restrict certain attribute bonuses to only certain gear pieces, or maximum values based on the base type, etc; but not pre-defining everything.
19 Apr, 2013, Nathan wrote in the 4th comment:
Votes: 0
@quixadhal

I said "db" because that's what I call it, even though at the present time it's more of a structured flat file that consists of lines like below. As it is, objects just get loaded with data from the file plus some predefined stuff for fields not stored in the file.

A room:
Quote
4#Red Dragon Inn#RS#A cheerful, brightly lit inn with a place to sit and eat, the rooms being upstairs.#0#I#10,10,10#-1#


An armor item:
Quote
221#chain mail#I#armor#19#0#6#0


where the first 5 fields are the same basic information about any object. I have considered converting to json, because it'd be a relatively easy
to switch over without a huge change. I'd like the code to work without needing a database server installed, honestly. It's not high on the list, but maybe sqlite? As to why I'd use enums and arrays; Those are the things I understand. I was initially trying, I think, to create a way to not have similarly named armor have completely different attributes (i.e. a way to get the same attributes). Still, the former is desirable at some level, at least with respect to being able to affect just one piece of armor.

I also don't have to load an enum in the code with explicit .put(…) methods on a map or the like. In any case such a map in Java could
only be genericized to <String, Object>. You'd have to assume about what the object is.

@Kline

I have Item(s) and Thing(s) which subclass MUDObject, Item(s) can be picked up (put in inventory, etc), and Thing(s) cannot. Armor is a subclass of Item, and has a ArmorType field. I was, at the time I wrote that part, aiming for just being able to have some kind of working armor in as an equippable item. As it is Armor doesn't have all those fields in it, it just gets the appropriate value from it's ArmorType. There's nothing keeping me from adding other fields and methods inside Armor.
19 Apr, 2013, quixadhal wrote in the 5th comment:
Votes: 0
I do encourage you to look into JSON. It's a nice, simple, format that's well supported and standardized. If you use it, you eliminate 99% of all your loading and saving code, since all you need to do is serialize your objects to JSON, and restore them directly.

To automate types, you could probably just wrap the object in a thin object that had the type name, followed by the object data. Restore the JSON entity string into a generic "wrapper object", pluck out the type name, then restore the rest of it into a new object of that type. Assuming the serialization methods don't already handle that for you.

I'll admit, I don't know how messy that will be in Java… I've done such in perl and ruby, but they have squishy types.
19 Apr, 2013, Nathan wrote in the 6th comment:
Votes: 0
quixadhal said:
I do encourage you to look into JSON. It's a nice, simple, format that's well supported and standardized. If you use it, you eliminate 99% of all your loading and saving code, since all you need to do is serialize your objects to JSON, and restore them directly.

To automate types, you could probably just wrap the object in a thin object that had the type name, followed by the object data. Restore the JSON entity string into a generic "wrapper object", pluck out the type name, then restore the rest of it into a new object of that type. Assuming the serialization methods don't already handle that for you.

I'll admit, I don't know how messy that will be in Java… I've done such in perl and ruby, but they have squishy types.


I had been looking into google-gson (https://code.google.com/p/google-gson/), but I'm not a hundred percent sure about code licenses right now. I really need to finish reading through the full Apache 2.0 license. Incidentally it has an abstract class called TypeAdapter that you subclass and define for a type and then you basically tell it exactly how you want it to reduce a class to json and read it back by implementing a read(…) and write(…) method. It'd be easier if I had all the data persisted the way I want, but I'm in danger of feature creep as it is. I've only got a loose sense of what finished means at the moment.
19 Apr, 2013, quixadhal wrote in the 7th comment:
Votes: 0
Pro-tip… use industry standards whenever possible. JSON is supported by just about every language, on just about every platform. Google's bizzaro thing, well, this is the first I've ever heard of it. :)
20 Apr, 2013, plamzi wrote in the 8th comment:
Votes: 0
quixadhal said:
Pro-tip… use industry standards whenever possible. JSON is supported by just about every language, on just about every platform. Google's bizzaro thing, well, this is the first I've ever heard of it. :)


In defense of Google, it looks like all this is is a JSON <–> Java Object converter library:

Quote
Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.
22 Apr, 2013, Runter wrote in the 9th comment:
Votes: 0
Yeah, it's just a conversion library to make it easier to use json. It's the equivalent of to_json in ruby converting a hash to a json string automagically I believe. I think json is a pretty fine general use case format.
0.0/9