Luarules <-> AI, part 1 of 0: resources
Moderators: hoijui, Moderators
Luarules <-> AI, part 1 of 0: resources
AIs need to get more info about games that don't exactly follow TA. Let's go.
AIs will need access to the cob storage vars in this draft, and their array size will need to be expanded.
Resources draft 1:
[code]
{
    COBTeamVars[ALLY_VAR_COUNT-1] = lua resource 1 storage or -1 if inapplicable
    COBTeamVars[ALLY_VAR_COUNT-2] = lua resource 1 amount or -1 if inapplicable
    COBTeamVars[ALLY_VAR_COUNT-3] = lua resource 1 income or -1 if inapplicable
    COBTeamVars[ALLY_VAR_COUNT-4] = lua resource 1 drain or -1 if inapplicable
} repeat for all lua resources
{
    COBTeamVars[UNIT_VAR_COUNT-1] = lua resource 1 storage or -1 if inapplicable
    COBTeamVars[UNIT_VAR_COUNT-2] = lua resource 1 amount or -1 if inapplicable
    COBUnitVars[UNIT_VAR_COUNT-3] = lua resource 1 income or -1 if inapplicable
    COBUnitVars[UNIT_VAR_COUNT-4] = lua resource 1 drain or -1 if inapplicable
} repeat for all lua resources
[modinfo] {
    [resources] {
        useEnergy = 1|0;
        useMetal = 1|0;
        luaResourceCount = int;
        resourcename1 = string;
        resourcename2 = string;
        ...
    }
}
[UnitDef] {
    [customparams] {
        //these can stretch the truth to be semi-accurate when it's complex
        //assume any not present are 0
        [resource name 1]store = float;
        [resource name 1]cost = float;
        [resource name 1]make = float;
        [resource name 1]use = float;
        [resource name 1]upkeep = float;
        //repeat for all lua resources
    }
}
[WeaponDef] {
    [customparams] {
        //assume 0 if not present
        [resource name 1]cost = float;
        //repeat for all lua resources
    }
}[/code]
Some sample interpretations (please point out anything wrong):
If amount is inapplicable you're probably looking at a direct feed resource, like power.
If storage is inapplicable but you do have an amount then you can hold as much as you want.
If a unit has storage it might be ammo for weapons (check them) or it could be a harvester of some sort. (It should likely have an automatic harvesting gadget that takes over, and should lie and say that it has income of the resource in the unitdef.)
If you want some units that cost refined_materials and see that refined_materials are generated by a building, make that building.
<3 nonbreaking spaces
AIs will need access to the cob storage vars in this draft, and their array size will need to be expanded.
Resources draft 1:
[code]
{
    COBTeamVars[ALLY_VAR_COUNT-1] = lua resource 1 storage or -1 if inapplicable
    COBTeamVars[ALLY_VAR_COUNT-2] = lua resource 1 amount or -1 if inapplicable
    COBTeamVars[ALLY_VAR_COUNT-3] = lua resource 1 income or -1 if inapplicable
    COBTeamVars[ALLY_VAR_COUNT-4] = lua resource 1 drain or -1 if inapplicable
} repeat for all lua resources
{
    COBTeamVars[UNIT_VAR_COUNT-1] = lua resource 1 storage or -1 if inapplicable
    COBTeamVars[UNIT_VAR_COUNT-2] = lua resource 1 amount or -1 if inapplicable
    COBUnitVars[UNIT_VAR_COUNT-3] = lua resource 1 income or -1 if inapplicable
    COBUnitVars[UNIT_VAR_COUNT-4] = lua resource 1 drain or -1 if inapplicable
} repeat for all lua resources
[modinfo] {
    [resources] {
        useEnergy = 1|0;
        useMetal = 1|0;
        luaResourceCount = int;
        resourcename1 = string;
        resourcename2 = string;
        ...
    }
}
[UnitDef] {
    [customparams] {
        //these can stretch the truth to be semi-accurate when it's complex
        //assume any not present are 0
        [resource name 1]store = float;
        [resource name 1]cost = float;
        [resource name 1]make = float;
        [resource name 1]use = float;
        [resource name 1]upkeep = float;
        //repeat for all lua resources
    }
}
[WeaponDef] {
    [customparams] {
        //assume 0 if not present
        [resource name 1]cost = float;
        //repeat for all lua resources
    }
}[/code]
Some sample interpretations (please point out anything wrong):
If amount is inapplicable you're probably looking at a direct feed resource, like power.
If storage is inapplicable but you do have an amount then you can hold as much as you want.
If a unit has storage it might be ammo for weapons (check them) or it could be a harvester of some sort. (It should likely have an automatic harvesting gadget that takes over, and should lie and say that it has income of the resource in the unitdef.)
If you want some units that cost refined_materials and see that refined_materials are generated by a building, make that building.
<3 nonbreaking spaces
Last edited by lurker on 18 Nov 2008, 18:05, edited 1 time in total.
Re: Luarules <-> AI, part 1 of 0: resources
nice you start something lurker 
soo.. as I have no idea about mods, some questions:
1. All you wrote here, is not yet available, but if this draft were accepted, game devs would add it to files in their mod, from where we could read it and feed it to the AIs. Is that the idea?
2. The first two blocks (repeat for all lua resources), are in separate files (eg resources.lua)?
Energy and metal are still special cases. I guess that is not possible to circumvent, for backwards compatibility reasons and cause the engine expects these two resources.
But from the AIs point of few, we could remove this. In about this fashion:
Energy could be resourceIndex=0 and metal resourceIndex=1 eg.
It would be no problem for current AIs of course, cause we just had to adapt the Legacy C++ compatibility layer to use the new functions, eg:
About LUA (Unit-)Commands:
Is the problem with them, that they are only known to the engine after the AI is loaded?
If so, we could have an AI event CommandsChanged maybe. Or is the problem, that we can not provide a suitable native container for them, as they may have an arbitrary number and types of arguments? Or is it just that the engine does not know about mod specific commands, and therefore can not tell them to AIs?
Would mods publicize their custom commands to the engine for it to make them available to AIs, or would rather the engine read some files? (hmm, ok, not really a difference there :D)

soo.. as I have no idea about mods, some questions:
1. All you wrote here, is not yet available, but if this draft were accepted, game devs would add it to files in their mod, from where we could read it and feed it to the AIs. Is that the idea?
2. The first two blocks (repeat for all lua resources), are in separate files (eg resources.lua)?
Energy and metal are still special cases. I guess that is not possible to circumvent, for backwards compatibility reasons and cause the engine expects these two resources.
But from the AIs point of few, we could remove this. In about this fashion:
Code: Select all
AICallback {
int getNumResources();
const char* getResourceName(int resourceIndex);
float getResourceIncome(int resourceIndex);
float getResourceStorage(int resourceIndex);
...
}
It would be no problem for current AIs of course, cause we just had to adapt the Legacy C++ compatibility layer to use the new functions, eg:
Code: Select all
LegacyAICallback {
float GetMetalIncome() {
static METAL_RESOURCE_INDEX = -1;
if (METAL_RESOURCE_INDEX) {
int size = getNumResources();
for (int i=0; i < size; ++i) {
if (strcmp(getResourceName(i), "Metal") == 0) {
METAL_RESOURCE_INDEX = i;
break;
}
}
}
return getResourceIncome(METAL_RESOURCE_INDEX);
}
}
About LUA (Unit-)Commands:
Is the problem with them, that they are only known to the engine after the AI is loaded?
If so, we could have an AI event CommandsChanged maybe. Or is the problem, that we can not provide a suitable native container for them, as they may have an arbitrary number and types of arguments? Or is it just that the engine does not know about mod specific commands, and therefore can not tell them to AIs?
Would mods publicize their custom commands to the engine for it to make them available to AIs, or would rather the engine read some files? (hmm, ok, not really a difference there :D)
Re: Luarules <-> AI, part 1 of 0: resources
Pretty much.hoijui wrote:1. All you wrote here, is not yet available, but if this draft were accepted, game devs would add it to files in their mod, from where we could read it and feed it to the AIs. Is that the idea?
No, those are live data in CCobInstance::globalVars, CCobInstance::teamVars, CCobInstance->unitVars. They're already exposed to both cob and lua; just needing AI bindings.hoijui wrote:2. The first two blocks (repeat for all lua resources), are in separate files (eg resources.lua)?
This works if you want dedicated functions. The way I was thinking there would be different types of data stored in the cob vars that wouldn't need any engine support. If you do go with dedicated functions then dedicated storage and lua functions might be a good idea, but it can become harder for cob to access.hoijui wrote:Energy could be resourceIndex=0 and metal resourceIndex=1 eg.Code: Select all
AICallback { int getNumResources(); const char* getResourceName(int resourceIndex); float getResourceIncome(int resourceIndex); float getResourceStorage(int resourceIndex); ... }
I didn't give much thought to unit commands yet, nor do I know what would be the best way to go about them. The only thing that came to me so far was using tokens to describe commands. 'point attack' 'area attack' 'area team help' 'randomly use this while attacking' 'similar to creating unit x free' 'similar to creating unit x for cost' 'free upgrade' 'upgrade for cost'
Re: Luarules <-> AI, part 1 of 0: resources
... i have really no idea what you are talking about here :Dlurker wrote:This works if you want dedicated functions. The way I was thinking there would be different types of data stored in the cob vars that wouldn't need any engine support. If you do go with dedicated functions then dedicated storage and lua functions might be a good idea, but it can become harder for cob to access.hoijui wrote:Energy could be resourceIndex=0 and metal resourceIndex=1 eg.Code: Select all
AICallback { int getNumResources(); const char* getResourceName(int resourceIndex); float getResourceIncome(int resourceIndex); float getResourceStorage(int resourceIndex); ... }
you mean AIs should read values directly from the mod VFS? :/
hmm...lurker wrote: I didn't give much thought to unit commands yet, nor do I know what would be the best way to go about them. The only thing that came to me so far was using tokens to describe commands. 'point attack' 'area attack' 'area team help' 'randomly use this while attacking' 'similar to creating unit x free' 'similar to creating unit x for cost' 'free upgrade' 'upgrade for cost'
this is, how AIs could possibly get an idea what a command can be used for in a dynamic way, hm?
I was rather thinking on how we could make AIs to have access to Mod LUA commands at all.
Re: Luarules <-> AI, part 1 of 0: resources
The word cob has no business in these forums. Please exercise encapsulation.
Re: Luarules <-> AI, part 1 of 0: resources
AI needs a two-way Lua interface so the AI can interrogate the mod about it's capabilities. Using COB values is a hack and IMHO an ugly one.
I'd suggest something that complements the current SendToAI (or whatever it's called):
CallModLua(funcname, args)
where args are a serialized dictionary, eg. using JSON notation or Lua table notation. Lua is good since the functions to access the table are already done in spring, so using an opaque void* should be enough in the AI. The interface should only export SetTable*(k, v)/GetTable*(k) family of functions.
when that's available, we could define a protocol, e.g. when AI is loaded, it calls
CallModLua("InitAI", {AI name, version, difficulty, etc})
which the mod sees as a call to
function InitAI(playerid, teamid, {AI name, version, difficulty, etc})
that sets up the cheats according to the difficulty level (levels should be defined somewhere else, like in the modinfo.tdf). InitAI could then return something, like supported functions, resource model, whatever.
other functions, like GetResources, GetPointsOfInterest(type), etc could be standardized by the community and defined by the mod itself without any engine changes. i hope you get the idea.
BTW my emphasis is on standardized by the community, all this could be made now with a defacto standard SendToAI protocol that AIs respected.
I'd suggest something that complements the current SendToAI (or whatever it's called):
CallModLua(funcname, args)
where args are a serialized dictionary, eg. using JSON notation or Lua table notation. Lua is good since the functions to access the table are already done in spring, so using an opaque void* should be enough in the AI. The interface should only export SetTable*(k, v)/GetTable*(k) family of functions.
when that's available, we could define a protocol, e.g. when AI is loaded, it calls
CallModLua("InitAI", {AI name, version, difficulty, etc})
which the mod sees as a call to
function InitAI(playerid, teamid, {AI name, version, difficulty, etc})
that sets up the cheats according to the difficulty level (levels should be defined somewhere else, like in the modinfo.tdf). InitAI could then return something, like supported functions, resource model, whatever.
other functions, like GetResources, GetPointsOfInterest(type), etc could be standardized by the community and defined by the mod itself without any engine changes. i hope you get the idea.
BTW my emphasis is on standardized by the community, all this could be made now with a defacto standard SendToAI protocol that AIs respected.
Re: Luarules <-> AI, part 1 of 0: resources
AFAIK AIs have access to Unit,Team,Ally and Game vars (those aren't in the wiki, but used by CA) -> no need for COB. Also there is the two-way callin/-out system (useful for events) named by you.imbaczek wrote:AI needs a two-way Lua interface so the AI can interrogate the mod about it's capabilities. Using COB values is a hack and IMHO an ugly one.
Yeah, there are more than enough ways to interact with AI, it is just that AI devs aren't doing anything into that direction ...imbaczek wrote:BTW my emphasis is on standardized by the community, all this could be made now with a defacto standard SendToAI protocol that AIs respected.
Re: Luarules <-> AI, part 1 of 0: resources
but we've been shooting cute glances with big shiny anime eyes in your direction looking all helpless for quite a while now, please lay down some palms so we can storm in with the heavy machinery!
Re: Luarules <-> AI, part 1 of 0: resources
..i am more confused now
Re: Luarules <-> AI, part 1 of 0: resources
Forget about cob. The important thing is that these are global arrays that anything can access. Since resources update a lot I was thinking of a way to cut down on function calls but have the data in a friendly place for everyone. This proposal is for a community standard needing no engine support. Feel free to change it to use only calls back and forth or propose something else entirely.
Re: Luarules <-> AI, part 1 of 0: resources
tbh cob is something we only use because lua doesnt support animation yet. Anything in cob should be purely animation, anything more complex should eb done in lua even if its possible in cob
Re: Luarules <-> AI, part 1 of 0: resources
Version 2, with an api. Uses a theoretical ability for AIs to read some form of dictionary.
This is all from the point of view of LuaRules.
_G.Resources[teamid] = {
    monies = {
        storage = false;
        amount = 7000;
        income = 500;
        drain = 0;
    },
    power = {
        storage = false;
        amount = false;
        income = 1200;
        drain = 1100;
    },
}
function GetTeamResources(playerid, teamid)
    return _G.Resources[teamid] --already in the correct format
end
function GetUnitResources(playerid, teamid, unitid)
    local unit = _G.UnitResources[unitid]
    if unit == nil then return nil end
    local unitResources = {
        monies = {
            storage = false;
            amount = false;
            income = unit.moniesincome;
            drain = false;
        },
        power = {
            storage = false;
            amount = false;
            income = unit.energymake;
            drain = unit.energyuse;
        },
    }
    return unitResources
end
function GetResourceInfo()
    local useEnergy = 1
    local useMetal = 1
    local luaResources = {
        monies,
        power,
    }
    return useEnergy, useMetal, luaResources
end
function UnitDefHints()
    local hints = {
        unitDefID = {
            --these can stretch the truth to be semi-accurate when it's complex
            --assume any not present are 0
            [resource name 1]store = float;
            [resource name 1]cost = float;
            [resource name 1]make = float;
            [resource name 1]use = float;
            [resource name 1]upkeep = float;
            --repeat for all lua resources
        },
        unitDefID = { --etc.
        },
    }
    return hints
end
function WeaponDefHints()
    local hints = {
        weaponDefID = {
            [resource name 1]cost = float;
            --repeat for all lua resources
        },
    }
    return hints
}
end
This is all from the point of view of LuaRules.
_G.Resources[teamid] = {
    monies = {
        storage = false;
        amount = 7000;
        income = 500;
        drain = 0;
    },
    power = {
        storage = false;
        amount = false;
        income = 1200;
        drain = 1100;
    },
}
function GetTeamResources(playerid, teamid)
    return _G.Resources[teamid] --already in the correct format
end
function GetUnitResources(playerid, teamid, unitid)
    local unit = _G.UnitResources[unitid]
    if unit == nil then return nil end
    local unitResources = {
        monies = {
            storage = false;
            amount = false;
            income = unit.moniesincome;
            drain = false;
        },
        power = {
            storage = false;
            amount = false;
            income = unit.energymake;
            drain = unit.energyuse;
        },
    }
    return unitResources
end
function GetResourceInfo()
    local useEnergy = 1
    local useMetal = 1
    local luaResources = {
        monies,
        power,
    }
    return useEnergy, useMetal, luaResources
end
function UnitDefHints()
    local hints = {
        unitDefID = {
            --these can stretch the truth to be semi-accurate when it's complex
            --assume any not present are 0
            [resource name 1]store = float;
            [resource name 1]cost = float;
            [resource name 1]make = float;
            [resource name 1]use = float;
            [resource name 1]upkeep = float;
            --repeat for all lua resources
        },
        unitDefID = { --etc.
        },
    }
    return hints
end
function WeaponDefHints()
    local hints = {
        weaponDefID = {
            [resource name 1]cost = float;
            --repeat for all lua resources
        },
    }
    return hints
}
end
Last edited by lurker on 18 Nov 2008, 18:20, edited 3 times in total.
- BrainDamage
- Lobby Developer
- Posts: 1164
- Joined: 25 Sep 2006, 13:56
Re: Luarules <-> AI, part 1 of 0: resources
no negative amount of res supported (ie debt) ?
you sure it's a good idea to have to create an additional resource to have to represent debt?
you sure it's a good idea to have to create an additional resource to have to represent debt?
Re: Luarules <-> AI, part 1 of 0: resources
Good point. Since this is all lua-tastic now let's use false for inapplicable. Editing the post above you. It might be better to use nil in the end but false is clearer for now, and both evaluate to false.
Re: Luarules <-> AI, part 1 of 0: resources
LuaRules.cpp
use them
Code: Select all
lua_getglobal(L, "Spring");
LuaPushNamedCFunc(L, "SetRulesInfoMap", SetRulesInfoMap);
LuaPushNamedCFunc(L, "SetUnitRulesParam", SetUnitRulesParam);
LuaPushNamedCFunc(L, "SetTeamRulesParam", SetTeamRulesParam);
LuaPushNamedCFunc(L, "SetGameRulesParam", SetGameRulesParam);
LuaPushNamedCFunc(L, "CreateUnitRulesParams", CreateUnitRulesParams);
LuaPushNamedCFunc(L, "CreateTeamRulesParams", CreateTeamRulesParams);
LuaPushNamedCFunc(L, "CreateGameRulesParams", CreateGameRulesParams);
lua_pop(L, 1);
Re: Luarules <-> AI, part 1 of 0: resources
hmmm, can we send strings across the lua<-> AI divide or was that problem never solved? I remember looking at the signature for the new API addition when trepan added it and noticing it did not have allowances for anything but numerical values but i havent checked since.
AIs would need to search for a particular lua file and then load their own lua virtual machines in order to parse it. Currently no native AI has a lua runtime inside it yet, so if we can simplify this into a more message based system then that would be much better. Thus i think we should approach this form a networking point of view not a lua API view, because there are no function calls across the boundaries, just a collection of values sent to a specific AI like a broadcast from my understanding.
I also think this resource spec is not flexible enough because they all assume that they follow the normal system of TA in that its beneficial to gather as much resources as you can. What if we want a resource representing score where we want the value to be as small as possible?
For example, we might have to look after citizens, and we may represent their alarm as a resource we want as little of as possible encase they revolt.
AIs would need to search for a particular lua file and then load their own lua virtual machines in order to parse it. Currently no native AI has a lua runtime inside it yet, so if we can simplify this into a more message based system then that would be much better. Thus i think we should approach this form a networking point of view not a lua API view, because there are no function calls across the boundaries, just a collection of values sent to a specific AI like a broadcast from my understanding.
I also think this resource spec is not flexible enough because they all assume that they follow the normal system of TA in that its beneficial to gather as much resources as you can. What if we want a resource representing score where we want the value to be as small as possible?
For example, we might have to look after citizens, and we may represent their alarm as a resource we want as little of as possible encase they revolt.
Re: Luarules <-> AI, part 1 of 0: resources
Edit a couple months later to fix, had to read the code twice to understand it yay:
I couldn't find any documentation, so here is my best shot.
SetRulesInfoMap(table):
Wipes out the existing InfoMap before it starts.
map<string, string>& infoMap = luaRules->infoMap;
Takes a flat lua table, shoves it into this string to string std::map.
The next two use these these pairs of variables:
    lr->gameParamsMap and gameParamsMap
    team->modParams and modParamsMap
    unit->modParams and modParamsMap
CreateUnitRulesParams(unitid, table)
CreateTeamRulesParams(team, table)
CreateGameRulesParams(table)
    Wipes out the existing RulesParams before it starts.
    Takes a lua table with both named and unnamed float values.
    vector<float>& params
    The values go in here.
    map<string, int>& paramsMap
    The names go in here, with the int being the index of the float value.
SetUnitRulesParam(unitid, index, value)
SetTeamRulesParam(team, index, value)
SetGameRulesParam(key, value)
    Does not wipe out the existing members.
    If key is an int, params[index] = value if the vector already
    has a params[index]
    If key is a string, the value is stored in params, increasing the
    size if necessary. paramsMap[key] is the index in params where
    the value can be found.
I couldn't find any documentation, so here is my best shot.
SetRulesInfoMap(table):
Wipes out the existing InfoMap before it starts.
map<string, string>& infoMap = luaRules->infoMap;
Takes a flat lua table, shoves it into this string to string std::map.
The next two use these these pairs of variables:
    lr->gameParamsMap and gameParamsMap
    team->modParams and modParamsMap
    unit->modParams and modParamsMap
CreateUnitRulesParams(unitid, table)
CreateTeamRulesParams(team, table)
CreateGameRulesParams(table)
    Wipes out the existing RulesParams before it starts.
    Takes a lua table with both named and unnamed float values.
    vector<float>& params
    The values go in here.
    map<string, int>& paramsMap
    The names go in here, with the int being the index of the float value.
SetUnitRulesParam(unitid, index, value)
SetTeamRulesParam(team, index, value)
SetGameRulesParam(key, value)
    Does not wipe out the existing members.
    If key is an int, params[index] = value if the vector already
    has a params[index]
    If key is a string, the value is stored in params, increasing the
    size if necessary. paramsMap[key] is the index in params where
    the value can be found.
Last edited by lurker on 18 Nov 2008, 19:17, edited 1 time in total.
- BrainDamage
- Lobby Developer
- Posts: 1164
- Joined: 25 Sep 2006, 13:56
Re: Luarules <-> AI, part 1 of 0: resources
is separated income and drain even necessary when using false as separate state?lurker wrote:         income = 1200;
        drain = 1100;
can't they just be tied togheter in a single delta value which is income - drain? or is there any case when you'd want to know them separated? don't get get summed anyway in the resource pool?
point me where it's stated thatAF wrote:I also think this resource spec is not flexible enough because they all assume that they follow the normal system of TA in that its beneficial to gather as much resources as you can.
the ai will look at the value and try to minimize it?, or if you want, you can just have the resource always be negative, this way an improvement delta is positive (approaching 0) and a loss is negative ( going deeper on negative side), this way the logic you assumed is still respectedAF wrote:What if we want a resource representing score where we want the value to be as small as possible?
Last edited by BrainDamage on 18 Nov 2008, 19:06, edited 1 time in total.
Re: Luarules <-> AI, part 1 of 0: resources
I think that should change to a happier tune once you read the documentation I spent half an hour onAF wrote:stuff

I never said it was a complete spec; what are your ideas to show that? One way could be to mark them as 'get as much as possible', 'get enough to use', 'avoid', etc.AF wrote:For example, we might have to look after citizens, and we may represent their alarm as a resource we want as little of as possible encase they revolt.
Edit: Yeah, I like the idea of the AI-exposed resource being negative.
Last edited by lurker on 18 Nov 2008, 19:06, edited 1 time in total.
Re: Luarules <-> AI, part 1 of 0: resources
you can turn stuff on/off.Brain Damage wrote:is separated income and drain even necessary when using false as separate state?lurker wrote:         income = 1200;
        drain = 1100;
can't they just be tied togheter in a single delta value which is income - drain? or is there any case when you'd want to know them separated? don't get get summed anyway in the resource pool?