| 11-02-2009, 04:30 PM | #1 |
This is a library that will help with usage of agent types. It exposes several new "keywords", they are Zinc:typecast(type)(agent a) -> type //typecast a to type LoadAgent(type)(table t,int pk,int ck) -> type // loads the object from the hashtable, useful as its easier to programatically write. typeOf(agent a) -> int // returns typeNumber of object. typeName(agent a) -> string // returns a name of the Object. IsType(type)(agent a) -> bool // returns true if the object is type. SaveTypeData(type)(agent a) -> type // save the type data for an object and return it. ReleaseTypeData(type)(agent a) -> type // release type data for an object and return it. ReleaseTypeData(agent a) -> bool // release type data and returns true always. Dealloc(agent a) -> bool // release type data and destroy the object. returns true if it destroyed the object. (some objects can't be destroyed). CommonW also includes a macro facility to create Binary tree executions to make fast running generic agent taking functions. The binary tree executions will average ln(29)+1 or ~= 5 comparisons on average. Which is certainly better then nothing. The function included to demo this is Zinc:DestroyAgent(agent a) -> bool // a function that deallocs an agent type. I am also contemplating creating a function interface and an array of that interface of size 30 so that you can define a function to execute given each type. That would suck pretty bad too. This way provided you make them generic enough you don't need to fill in array. Why am I using Cjass? Because the generic programming facilities in CJass are still much much better then those found in VJass/Zinc. Warning:: CommonW is NOT done, as I'm lazy and I can't quiet figure out a good way to parse common.j and hijack and automatically replace functions for the 29 types. I've done 2 so far, and I'll probably keep working on it. But if anyone has a good way to do it, let me know. Code:
include "cj_types.j"
define while = whilenot not;
define break = exitwhen true;
define SPACE = ;
library CommonW initializer InitW
{
#define typecast(T) = Typecast_##T
#define Dealloc(T) = Dealloc_##T
#define LoadAgent(T) = Load_##T
#define IsType(T) = IsType_##T
#define SaveTypeData(T) = saveTypeData##T
#define ReleaseTypeData(T) = releaseTypeData##T
private hashtable Table = InitHashtable();
private string array Names;
void InitW()
{
int i = 0;
Names[i++] = "UNKNOWN"
Names[i++] = "Player"
Names[i++] = "Destructable"
Names[i++] = "Item"
Names[i++] = "Unit"
Names[i++] = "Ability"
Names[i++] = "Timer"
Names[i++] = "Trigger"
Names[i++] = "TriggerCondition"
Names[i++] = "TriggerEvent"
Names[i++] = "Force"
Names[i++] = "Group"
Names[i++] = "Location"
Names[i++] = "Rect"
Names[i++] = "BooleanExpr"
Names[i++] = "Sound"
Names[i++] = "Effect"
Names[i++] = "Quest"
Names[i++] = "QuestItem"
Names[i++] = "DefeatCondition"
Names[i++] = "TimerDialog"
Names[i++] = "Leaderboard"
Names[i++] = "Multiboard"
Names[i++] = "MultiboardItem"
Names[i++] = "Trackable"
Names[i++] = "Dialog"
Names[i++] = "Button"
Names[i++] = "Region"
Names[i++] = "FogModifier"
Names[i++] = "Hashtable"
}
int typeOf(agent a)
{
int retVal = 0;
retVal = LoadInteger(Table,0,GetHandleId(a)); // shortcut mode
#if debug
if(retVal == 0)
{
BJDebugMsg("Null or non-registered type");
}
#endif
return retVal;
}
string TypeName(agent a)
{
return Names[typeOf(a)];
}
bool ReleaseTypeData(agent a)
{
RemoveSavedInteger(Table,0,GetHandleId(a));
return true;
}
#define private InitSaveRet(typeNum,TypeName,T, Deconstructor) =
{
public int TypeName = typeNum
T saveTypeData##T(T a)
{
SaveInteger(Table,0,GetHandleId(a),typeNum);
return a;
}
T releaseTypeData##T(T a)
{
RemoveSavedInteger(Table,0,GetHandleId(a));
return a;
}
T LoadAgent(T)(hashtable ht,integer pk,integer ck)
{
return Load##TypeName##Handle(ht,pk,ck);
}
bool IsType_##T(agent a)
{
return typeOf(a) == TypeName
}
T Typecast_##T(agent a)
{
T retVal = null;
if(a != null)
{
SaveAgentHandle(Table,0,0,a);
retVal = LoadAgent(T)(Table,0,0);
RemoveSavedHandle(Table,0,0);
}
return retVal;
}
bool Dealloc_##T(agent a)
{
bool retVal = false;
#if Deconstructor !=
retVal = true;
Deconstructor( typecast(T)(a))
#endif
ReleaseTypeData(a);
return true;
}
}
InitSaveRet(1,Pl##ayer,player,)
InitSaveRet(2,Destructable,destructable,RemoveDestructable)
InitSaveRet(3,Item,item,RemoveItem)
InitSaveRet(4,Unit,unit,RemoveUnit)
InitSaveRet(5,Ability,ability,)
InitSaveRet(6,Timer,timer,DestroyTimer)
InitSaveRet(7,Trigger,trigger,DestroyTrigger)
InitSaveRet(8,TriggerCondition,triggercondition,)
InitSaveRet(9,TriggerEvent,event,)
InitSaveRet(10,Force,force,DestroyForce)
InitSaveRet(11,Group,group,DestroyGroup)
InitSaveRet(12,Location,location,RemoveLocation)
InitSaveRet(13,Rect,rect,RemoveRect)
InitSaveRet(14,BooleanExpr,boolexpr,DestroyBoolExpr)
InitSaveRet(15,Sound,sound,KillSoundWhenDone)
InitSaveRet(16,Effect,effect,DestroyEffect)
InitSaveRet(17,Quest,quest,DestroyQuest)
InitSaveRet(18,QuestItem,questitem,)
InitSaveRet(19,DefeatCondition,defeatcondition,DestroyDefeatCondition)
InitSaveRet(20,TimerDialog,timerdialog, DestroyTimerDialog)
InitSaveRet(21,Leaderboard,leaderboard, DestroyLeaderboard)
InitSaveRet(22,Multiboard,multiboard, DestroyMultiboard)
InitSaveRet(23,MultiboardItem,multiboarditem, MultiboardReleaseItem)
InitSaveRet(24,Trackable,trackable,)
InitSaveRet(25,Dialog,dialog, DialogDestroy)
InitSaveRet(26,Button,button,)
InitSaveRet(27,Region,region, RemoveRegion)
InitSaveRet(28,FogModifier,fogmodifier,DestroyFogModifier)
InitSaveRet(29,Hashtable,hashtable,)
bool IsType_##widget(agent a)
{
int typeval = typeOf(a);
return (typeval == CommonW_Destructable || typeval == CommonW_Item || typeval == CommonW_Unit)
}
bool IsType_##agent(agent a)
{
return a != null
}
#define CreateBinaryAgentFunc(FuncName,args,returnType,defaultVal,funcPrefix,funcargs,agentVar) =
{
returnType FuncName(args)
{
returnType retVal = defaultVal;
int dt_type = typeOf(agentVar);
if(dt_type > 14)
{
if(dt_type < 22)
{
if(dt_type < 18)
{
if(dt_type < 16){retVal = funcPrefix##sound(funcargs)} // 15
elseif(dt_type < 17){retVal = funcPrefix##effect(funcargs)} // 16
else{retVal = funcPrefix##quest(funcargs)} // 17
}
elseif(dt_type < 21)
{
if(dt_type < 19){retVal = funcPrefix##questitem(funcargs)} // 18
elseif(dt_type < 20){retVal = funcPrefix##defeatcondition(funcargs)} // 19
else{retVal = funcPrefix##timerdialog(funcargs)} // 20
}
else{retVal = funcPrefix##leaderboard(funcargs)} // 21
}
elseif(dt_type < 26)
{
if(dt_type < 24)
{
if(dt_type < 23){retVal = funcPrefix##multiboard(funcargs)} // 22
else{retVal = funcPrefix##multiboarditem(funcargs)} // 23
}
elseif(dt_type < 25){retVal = funcPrefix##trackable(funcargs)} // 24
else{retVal = funcPrefix##dialog(funcargs)} // 25
}
elseif(dt_type < 28)
{
if(dt_type < 27){retVal = funcPrefix##button(funcargs)} // 26
else{retVal = funcPrefix##region(funcargs)} // 27
}
elseif(dt_type < 29){retVal = funcPrefix##fogmodifier(funcargs)}
else {retVal = funcPrefix##hashtable(funcargs)} // 29
}
elseif(dt_type > 7)
{
if(dt_type > 11)
if(dt_type > 13) {retVal = funcPrefix##boolexpr(funcargs)} // 14
elseif(dt_type >12) {retVal = funcPrefix##rect(funcargs)}// 13
else {retVal = funcPrefix##location(funcargs)} // 12
elseif(dt_type > 9)
if(dt_type > 10) {retVal = funcPrefix##group(funcargs)} // 11
else {retVal = funcPrefix##force(funcargs)} // 10
elseif(dt_type > 8) {retVal = funcPrefix##event(funcargs)} // 9
else {retVal = funcPrefix##triggercondition(funcargs)} // 8
}
elseif(dt_type > 3)
{
if(dt_type > 5)
if(dt_type > 6){retVal = funcPrefix##trigger(funcargs)} // 7
else {retVal = funcPrefix##timer(funcargs)} // 6
elseif(dt_type > 4){retVal = funcPrefix##ability(funcargs)} // 5
else{retVal = funcPrefix##unit(funcargs)} // 4
}
elseif(dt_type > 1)
if(dt_type > 2){retVal = funcPrefix##item(funcargs)}
else{retVal = funcPrefix##destructable(funcargs)}
elseif(dt_type > 0){retVal = funcPrefix##player(funcargs)} // 1
return retVal;
}
}
CreateBinaryAgentFunc(DestroyAgent,<agent a>,bool,false,Deallo##c_,a,a);
}// macro hell. We now go and redefine everything to use CommonW expressive nature.
// Player Natives
#define GetFilterPlayer() = SaveTypeData(player)(GetFilterPla##yer())
#define GetEnumPlayer() = SaveTypeData(player)(GetEnumPla##yer())
#define GetWinningPlayer() = SaveTypeData(player)(GetWinningP##layer())
#define GetTournamentFinishNowPlayer() = SaveTypeData(player)(GetTournamentFinishNowPla##yer())
#define GetTriggerPlayer() = SaveTypeData(player)(GetTriggerPla##yer())
#define GetChangingUnitPrevOwner() = SaveTypeData(player)(GetChangingUni##tPrevOwner())
#define GetEventDetectingPlayer() = SaveTypedata(player)(GetEventDetec##tingPlayer())
#define GetItemPlayer(it) = SaveTypeData(player)(GetItemPl##ayer(it))
#define GetOwningPlayer(Unit) = SaveTypeData(player)(GetOwningPla##yer(Unit))
#define <Player>(i) = SaveTypeData(player)(Play##er(i))
#define GetLocalPlayer() = SaveTypeData(player)(GetLocalPlaye##r())
#define LoadPlayerHandle(table,pk,ck) = SaveTypeData(player)(LoadPlayer##Handle(table,pk,ck))
//Destructable Natives
#define GetFilterDestructable() = SaveTypeData(destructable)(GetFilterDestr##uctable())
#define GetEnumDestructable() = SaveTypeData(destructable)(GetEnumDestr##uctable())
#define GetOrderTargetDestructable() = SaveTypeData(destructable)(GetOrderTargetDestru##ctable())
#define GetSpellTargetDestructable() = SaveTypeData(destructable)(GetSpellTargetDestr##uctable())
#define CreateDestructable(objectid,x,y,face,scale,variation) = SaveTypeData(destructable)(CreateDestr##uctable(objectid,x,y,face,scale,variation))
#define CreateDestructableZ(objectid,x,y,z,face,scale,variation) = SaveTypeData(destructable)(CreateDestr##uctableZ(objectid,x,y,z,face,scale,variation))
#define CreateDeadDestructable(objectid,x,y,face,scale,variation) = SaveTypeData(destructable)(CreateDeadDestr##uctable(objectid,x,y,face,scale,variation))
#define CreateDeadDestructableZ(objectid,x,y,z,face,scale,variation) = SaveTypeData(destructable)(CreateDeadDestr##uctableZ(objectid,x,y,z,face,scale,variation))
#define GetTriggerDestructable() = SaveTypeData(destructable)(GetTriggerDestr##uctable())
#define GetUnitRallyDestructable(whichUnit) = SaveTypeData(destructable)(GetUnitRallyDes##tructable())
#define LoadDestructableHandle(table,pk,ck) = SaveTypeData(destructable)(LoadDestru##ctableHandle(table,pk,ck))
#define RemoveDestructable(d) = ReleaseTypeData(destructable)(RemoveDestruc##table(d))
#define KillDestructable(d) = ReleaseTypeData(destructable)(KillDestructab##le(d)) |
| 11-04-2009, 02:00 AM | #2 |
I guess nobody actually can see a need for this? |
| 11-04-2009, 02:21 AM | #3 |
I really think it is actually just because you chose to use cJASS. |
| 11-04-2009, 12:00 PM | #4 |
It's not like it was a choice, what I'm doing here can't be done in VJass :( |
| 11-04-2009, 01:25 PM | #5 |
I just don't think the world is ready for this :). Think about it, most of the cjass types are guys that thought define is a way to save execution speed through making all functions inline-able... , and thus would not appreciate that you are introducing this functionality in exchange of a lot of overhead so they would avoid it like the plague. The rest won't even understand the code... For what's worth the major problem here is that after all the things that happened to us thanks to handle stack corruption bugs due to misusing I2H, we got used to actually knowing what the types of our agents are. I personally can't think of good uses for it, this may be because we pretty much got used to knowing the type of the agents we are using at run time... I also think this is best done completely at compile time with true generics and specialization, just give myself about a week before we have something like generics that will sort of work, I've been having mind explosions regarding how to implement it for a while... Bleh I figured out hooks really need a way to get the native's return value. |
| 11-04-2009, 02:14 PM | #6 | |
Quote:
|
| 11-04-2009, 02:19 PM | #7 |
Before, otherwise they wouldn't make a lot of sense in say, hooking RemoveUnit. |
| 11-04-2009, 02:27 PM | #8 | |
Quote:
|
| 11-05-2009, 12:07 AM | #9 |
Well, I'm that crazy guy that uses CJASS for #if which is better then static if as it can read parameters in macro declarations and tell you if they are unused. ++ //although admittedly I can live without it. macros to emulate templates. function declarations like those in C. Macros to default argument functions. // this is just so I can be lazy Oh and the all important Macros calling other macros. Which is awesome when it works. As then you don't actually have to remember what List!(T) is defed as internally. As for the other thing, there are still things you couldn't do without knowing type information. How can you have a generic destroy agent? Or load agent handle (which isn't implemented but one could just hook all the saver of agent types and add that you save an integer with type info at runtime, so you can do the execution in 5 calls instead of 29). Yes, its an overhead, but its a really neat bit of functionality. I don't think anyone except for adolf uses CJass for "inlining functions". |
