Here is the information that we can already get via llDetected* calls:
Group to possibly check to see if they are in the Ecosystem group
Key to identify the specific organism, and for sending email
LinkNumber to see if you're interacting with the root prim or a
"leaf"/leg
Name to get the EcoName
Pos where this thing is
Rot can possibly store info here
Type to check for active scripts
Vel to judge the critter's speed
(Other llDetected info that probably won't be useful: Grab and Owner)
Thus we need to store any data not above in the Eco-Name.
Here's my preliminary list of what might be included:
Name (string, 36) -- the name of organism / preferrably
unchanging
Version (integer, 00-99) -- the version of the Eco-Name (useful
for parsing)
Type (string, 1) -- "A"nimal or "P"lant or "O"ther
Food Amount (root) (integer, 1-1000?) -- energy that is gained by
eating
Food Amount (leaf) (integer, 1-1000?) -- energy that is gained by
eating
Energy (integer, 1-1000?) -- organism's energy
Health (integer, 1-1000?) -- organism's health
DamageMin (integer, 0-999) -- how much damage to do
on collision
DamageMax (integer, 0-999) -- max damage (can be
randomly decided)
Channel (integer, -#####) -- personal/species
communication channel
SizeX (integer, 1-10) -- the organism's root size, from
llGetScale
SizeY (integer, 1-10)
SizeZ (integer, 1-10)
ColorR (integer, 1-255) -- the organism's color, for visual
recognition
ColorG (integer, 1-255)
ColorB (integer, 1-255)
Attractiveness (string, 2) -- two-letter code for
mating beauty
Smell (string, 2) -- a two-letter
code for whatever we might want
Taste (string, 2) -- ""
Touch (string, 2) -- ""
Sound (string, 2) -- ""
Visible State (string, 2) -- a two-letter code for
whatever we might want
Signs (string, 2) -- some sort of non-verbal
communication
Key (key/string, 36) -- the key of the object that the org
is interacting w/
Action Type (string, 2) -- 2-letter code: what the org is
doing
Personal/2nd Name (string, 24) -- a personal name or other
information
Parent Key (key/string, 36) -- the org's parent
Generation (integer, 0-9999) -- generation #
All this would use a max of 225 characters, including commas.
So there's still a little bit of space... Can you think of anything
that should be added? Anything that one organism might be able to sense
or would need to know for certain mechanics?
A fish is swimming around... If the fish didn't have a list of
potential food sources, he might simply do a quick scan to see if he
sees any plants nearby. He bumps into the nearest one to taste it.
(Plants are a better choice since they're unlikely to fight back.) If
it gives a good amount of energy, he remembers the plant's name -- or
color or taste or whatever.
If I wanted to, I could just as easily make the fish learn the food
amount just by scanning, but that seems too easy. :-p
Once he selects something to go towards, he updates his eco-Name so
that the object's key is in there (Key), along with his intentions to
eat whatever he finds (Action Type = "HU" for hunt or "EA" for
eatting).
On the eventual collision, the fish checks the plant's Food Amount and
feeds itself this amount. The plant also registers the collision and
does the appropriate damage to itself (probably by getting some info
from the fish about how much of it it's eatten).
If the victim here were an animal instead, it might look around and see
that the fish has selected his Key as it's target and intends to eat
it. It could then begin to run away and remember the fish as a
predator.
(None of this is implemented yet... but hopefully i'll test it soon)
I put out some examples at Observation Station #1 in Terminus. Feel
free to browse through the script, try it out in your own critters,
etc. Just keep us informed if you make any cool additions to the code.
Also, in order to conserve memory in my applications, I'm probably only
going to have my bugs, plants and birds utilizing a small number of the
fields. I'm not sure color, beauty, etc are meaningful for my bugs as
they (as of yet) reproduce asexually. Perhaps we can come up with a
minimal standard for use now, as we are still in the prototyping phase.
Given that memory is tight, perhaps ratcheting down on the number of
these fields would be a positive step.
Also, as I mentioned in the other post, email requests can be handled
rapidly if farmed out to other scripts (via link messages), if this
approach doesn't wind up working, or users want to keep certain
interactions between species they create "private" (which I think users
have a right to do, within reason).
I agree with Luc in that there is a lot of data here, most of which
will not be useful to most organisms. So it's a lot of processing time
to parse a big name to a list, wasted if the organism doing the parsing
doesn't care about most of the fields.
However, some organisms will want to know lots of extra data, for
example Luc was telling me that his grid lice may want to know which
hive another louse is from. Of course nobody else's organisms care
about it.
So I'm tending towards having the data structure given within the name.
Something like the object name is:
n|thing_name|h|health_integer|e|energy_integer
...and so on. Incidentally, using commas for seperators, and CSV2List
has trouble if you ever want to store a vector say - the parser gets
messed up. Better to use llParseString2List and llDumpList2String
functions, with some other character (I generally use "|").
Anyway, the overhead of needing a single character for each data type
is, I think, outweighed by the efficiency of not every organism having
fields in its name for every data type that any organism anywhere cares
about.
With a system like that, if Luc wants to use 4 or 5 fields, and you
want to use 20, its fine, all fits together nicely and there are no new
versions to screw everything up - everything is always compatible with
everything else, to the extent that they overlap.
If we do go this way, then this list of properties is useful for the
datatypes that we could be interested in (and there should certainly be
a central protocols list somewhere on the wiki). We would want a core,
minimal set of data types that virtually everything has. I'm not sure
what that would be. Perhaps health, food amount, comms channel? Maybe
animal/plant, energy... some specific other things depending on if it
is an animal or a plant?
I like the idea of farming out the email to another script to make it
happen in the background. Of course the only problem is there will be a
"digestion" delay of at least 46 seconds or so while the email
handshaking happens between the eater and the food. The method used
will probably depend on how quickly the organism needs to eat and
digest.
Regarding using using CSVs, the wiki says "You can even pass complex
types like vectors or rotations even though their string
representations have commas. ... More specifically, commas inside angle
brackets ("<" and ">") are not interpretted as separaters."
Are they incorrect? I haven't tested this yet.
Regarding the organisms not needing to use every field in the Eco-Name
-- They're always free to leave any of the fields blank.
Given that we're already at 225 characters (which will be somewhat less
after removing size), I'm not yet convinced that adding a datatype for
each value would be beneficial.
Forgive me while I think this over "out loud"... Say we want to look up
an organism's health... With a datatype, we'd have to do the following:
1. Convert the name string to a list
2. Do a for-loop through the list looking for the particular
datatype, "h" in this example
3. Return the next value after "h"
Using an ordered list, we'd have to do the following:
1. Convert the name string to a list
2. Get the value at spot x (wherever health is held)
3. Return the value
Wouldn't the second method be quicker? Is there some other aspect I'm
not considering?
As for the lice knowing which hive they're from -- Simply give each bug
a distinct smell depending on which hive they're from. Since I've
defined smell as a 2-character string, something like "01", "02", "A",
or "B" could be used.
This way if some intelligent creature is wanting to understand the
bugs' behavoir, he may be able to figure out their homes from their
smells.
Or perhaps a predator bases his food choices off smell. He tastes a bug
that gives him a good amount of food so he remembers the smell. He then
proceeds to only eat bugs from the one particular hive.
Another way would be through color. Perhaps each hive has a randomly
generated color or one based off of genes. Since Luc's queen bugs have
a colored dome on their back, it could be made to match this hive
color. For the bugs, it can be used as a non-visible way to distinguish
hives. The color in the Eco-Name need not be the actual color of the
object.
I'm a big fan of eventually making all AI decisions based only on a
combination of their 5 senses and memories.
// Global variables
string MyProperName = "Plob"; // These need to be defined for
the Eco-Name
string MyEcoNameVersion = "A0";
string MyEcoType = "A"; //A=Animal, P=Plant,
R=Robot
string MyDietType = "P"; // not currently implemented in my script
//~~~~~~~~~~~~~ ECO-NAME ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// These are the standard functions to access the Eco-Name.
// If you're going to make changes to these, please speak with Never
Rust or others working on the
// Eco-system project to establish a new version number.
//
// Version A0 ("alpha zero" / initial testing)
// 0 - Proper Name (unchanging species name)
// 1 - Eco-Name version
// 2 - Type: "P"lant, "A"nimal, "R"obot, etc.
// 3 - Food/Energy amount from root
// 4 - Food/Energy amount from leaf
// 5 - Action ("EAT")
// 6 - Target Key
// 7 - Requested Food (how much you intend on eatting)
SetEcoName(integer FoodRoot, integer FoodLeaf, string Action, key
TargetKey, integer EnergyRequested) {
list EcoName = [MyProperName, MyEcoNameVersion, MyEcoType,
FoodRoot, FoodLeaf, Action, TargetKey, EnergyRequested];
llSetObjectName(llList2CSV(EcoName));
}
string EcoName2ProperName(string name) {
return llList2String(llCSV2List(name), 0);
}
string EcoNameVersion(string name) {
return llList2String(llCSV2List(name), 1);
}
integer EcoName2FoodRootAmount(string name) {
if (EcoNameVersion(name) == MyEcoNameVersion) return
llList2Integer(llCSV2List(name), 3);
else return 0;
}
integer EcoName2FoodLeafAmount(string name) {
if (EcoNameVersion(name) == MyEcoNameVersion) return
llList2Integer(llCSV2List(name), 4);
else return 0;
}
string EcoName2Action(string name) {
if (EcoNameVersion(name) == MyEcoNameVersion) return
llList2String(llCSV2List(name), 5);
else return "";
}
key EcoName2TargetKey(string name) {
if (EcoNameVersion(name) == MyEcoNameVersion) return
llList2Key(llCSV2List(name), 6);
else return NULL_KEY;
}
integer EcoName2RequestedFood(string name) {
if (EcoNameVersion(name) == MyEcoNameVersion) return
llList2Integer(llCSV2List(name), 7);
else return 0;
}
// In order for the animal to let the food know it intends to eat it,
we need to set the EcoName of the animal once it decides to attempt to
eat something...
string ActionName = "EAT";
SetEcoName(0, 0, ActionName, TargetKey, 100);
// TargetKey is the key of the food target, found from scanning and
comparing to memory
// 100 is the requested food. This should actually only be the max
amount of food the animal can eat so that it doesn't bite off more than
it can chew. (I just haven't implemented that yet since I had to split
my scripts into two)
// Here's how I use the Eco-Name functions in the animal during the
eating process...
collision(integer num_detected)
{
if (EcoName2TargetKey(llKey2Name(llGetKey())) ==
llDetectedKey(0) // if we hit the targeted obj
&& EcoName2Action(llKey2Name(llGetKey())) == "EAT")
// and eating it...
{
StopMove();
integer FoodAmount =
EcoName2FoodRootAmount(llDetectedName(0));
if (FoodAmount > 0) { //
if it gives energy then eat and remember
Eat(FoodAmount); // gives energy to the critter,
makes him pause and displays feedback
llMessageLinked(LINK_SET, FoodAmount,
(string)llDetectedPos(0), llDetectedKey(0)); // Send info to script 2
for memory -- if it was edible we should remember this food type and/or
location
} else {
llMessageLinked(LINK_SET, 0, "Inedible",
llDetectedKey(0)); // remember what's not edible
}
} else if (FALSE) { // Also need to handle what happens when we
bump into a predator not implemented yet
// check predator list
} else {
}
}
// Script for the food
string MyEcoNameVersion = "A0";
integer FoodRootWorth = 20;
string MyProperName = "Food Spore";
string MyEcoType = "P";
// also need to include most of the Eco-Name functions
reset() { // call this on rez
llSetStatus(STATUS_PHYSICS, TRUE);
llMinEventDelay(1.0);
SetEcoName(FoodRootWorth, 0, "", NULL_KEY, 0);
}
// ...And here is how the food handles getting eaten...
collision (integer num_detected)
{
if (EcoName2TargetKey(llDetectedName(0)) == llGetKey()) {
if (EcoName2RequestedFood(llDetectedName(0)) > 0) { //
should adjust this to make the food die only if the critter's requested
food amount is >= the FoodRootWorth... otherwise the food should get
depleted but not actually die. (I've just over-simplified it for
testing)
llDie();
}
}
}
This is true, but every organism has to read all 225 characters. If an
organism is only using and interested in 3 attributes, then with a
flexible system the names will be short, and parsing of them will be
quicker.
I suspect that overall the two systems would be about as fast as each
other, unless we have a lot of organisms using lots of fields (which
favours a fixed format) or a lot of organisms using very few fields
(which favours the flexible format). I think the real advantage of the
flexible format is in extensibility and, well, flexibility.
1. Convert the name string to a list
2. Do a for-loop through the list looking for the particular
datatype, "h" in this example
3. Return the next value after "h"
llListFindList is the function for doing 2.
"I'm a big fan of eventually making all AI decisions based only on a
combination of their 5 senses and memories."
How else could a script make a decision? I'm not sure I understand what
you mean. Restricting what they can know to some subset of the info in
the name? The way I see it, they don't have 5 senses... They have three
"senses", the output from llSensor, what they get from the name of
something they sense, and collision events.
I mean to duplicate the biological five senses with the programming
available to us. For instance...
Touch -- on collision read the Eco-Name of the things you collided with
and get the touch value
Smell -- do a scan, read the Eco-Names of the things you see, get the
smell value
Hearing -- do a scan, read the Eco-Names, get sound values... also
could listen to channel 0 or a specific channel for species
communication
Taste -- on collision & successful eating, read the taste value from
the Eco-Name
Sight -- do a scan, get color values and non-verbal communication from
the Eco-Name; also get other info such as llGetBoundingBox,
llDetectedPos, llDetectedVel
Ultimately creatures shouldn't - in my opinion - use information such
as species name, food value, damage value, etc. to make decisions.
Obviously these values are needed in the programming to resolve many
things, but they shouldn't be used for decision-making.
An example - Instead of doing a scan to get a food value and then
moving towards the highest food value, perhaps the critter scans and
gets a smell value. He then compares this smell value to his memory,
which is a list of each smell he's encountered followed by a value that
determines whether it likes the smell. If it has good memories of the
smell, it moves towards it and tries to eat it. If the object gives
some nourishment to the critter, he adjusts his memory to give that
smell a higher "like" value.
Of course I'm being a bit idealistic - since none of my critters can do
these things yet - but it's something to keep in mind for the future...
"Plob, A0, A, 0, 0, EAT, 71532a35-cad3-bb7f-4185-d257f069746a, 1"
That's 63 characters the only reason grid lice aren't cutting off is
because the way the name is being created appears to expose a bug they
have 70 character names apparently the ", " isn't being factored in all
the way or something. But the practical limit is 63 characters and we
are alrdy there.
This system has the advantage of putting information in Detected it has
the weakness of being human readable. The key is extremely wasteful and
since we haven't fully worked out how CVS counts in an object name we
could be wasting alot of precious space on that.
"Plob, A0, A, 0, 0, EAT, 71532a35-cad3-bb7f-4185-d257f069746a, 1"
63 characters
103f436a000020a4e501
20 characters
That conveys every bit of information the 63 character version does.
byte 0
Major Classification:
0 - Plant
1 - Animal
2 - Robot
using numbers instead of letters allows for heirarchy
if(mymajor > sensemajor)
trytoeat()
byte 1-3
Species Code: - Should be assigned to each species maybe blocks could
be assigned to devopers.(allows for 4k species)
03f - Plob
byte 4-7
My ID - Random Number between 0000 and FFFF
436a - individual number 436a of species Plob
with 65k numbers that should be reasonably unique giving our prim
counts even in a full sim. The few overlaps should never meet and
internally remembering individuals if you need to be precise you have
several options. 436a 4 - bytes 03f436a - 7 bytes 103f436a - 8 bytes or
the key.
bytes 8-9 Root Food - I still think this needs overhauled
00 - I am worth 0 Root Food
bytes 10-11 Leaf Food - I still think this needs overhauled
00 - I am worth 0 Leaf Food
byte 12 Action Code
2 - Eat
byte 13 Type Indicator for bytes 14-17
0 - Indivual
1 - Species
2 - Major
3 - Anything
bytes 14-17
a4e5 - In this case the individual code for the food spore the plob
wanted
bytes 18-19 Food Amount desired
01 - I'm looking for 1 food
And we've alrdy added extra capability
103f436a000021027401
Now the plob is saying it wants to eat any individual from Species
274(Food Spore)
103f436a000023000001
Now the plob is saying it wants to try to eat anything it hits.
And we still have 43 bytes to convey info
lets say that plob hit one of my plants
collision(integer num_detected)
{
string name = llDetectedKey(0)
if((integer)llGetSubString(name, 12, 12) == 2){
integer TargetType = llGetSubString(name, 13, 13);
if(TargetType == 3){
Eaten();
}
else{
integer Target = llGetSubString(name, 14, 17);
if(TargetType == 1){
if(Target == MySpecies)
Eaten()
else if(Target == MyID)
Eaten()
}
}
}