| 09-13-2009, 04:35 PM | #1 |
Hi All, I wrote a quick little method to help determine the type of your object. This might be useful, but I'm not sure how yet. It's in CJass, as I'm trying to promote it. Code:
include "cj_types.j"
define typecast(T) = DT_Type##T
library DT initializer initDT
{
private hashtable Table = InitHashtable();
private string array Names;
void initDT()
{
int i = 0;
Names[++i-1] = "UNKNOWN"
Names[++i-1] = "Player"
Names[++i-1] = "Widget"
Names[++i-1] = "Destructable"
Names[++i-1] = "Item"
Names[++i-1] = "Unit"
Names[++i-1] = "Ability"
Names[++i-1] = "Timer"
Names[++i-1] = "Trigger"
Names[++i-1] = "TriggerCondition"
Names[++i-1] = "TriggerAction"
Names[++i-1] = "TriggerEvent"
Names[++i-1] = "Force"
Names[++i-1] = "Group"
Names[++i-1] = "Location"
Names[++i-1] = "Rect"
Names[++i-1] = "BooleanExpr"
Names[++i-1] = "Sound"
Names[++i-1] = "Effect"
Names[++i-1] = "UnitPool"
Names[++i-1] = "ItemPool"
Names[++i-1] = "Quest"
Names[++i-1] = "QuestItem"
Names[++i-1] = "DefeatCondition"
Names[++i-1] = "TimerDialog"
Names[++i-1] = "Leaderboard"
Names[++i-1] = "Multiboard"
Names[++i-1] = "MultiboardItem"
Names[++i-1] = "Trackable"
Names[++i-1] = "Dialog"
Names[++i-1] = "Button"
Names[++i-1] = "TextTag"
Names[++i-1] = "Lightning"
Names[++i-1] = "Image"
Names[++i-1] = "Ubersplat"
Names[++i-1] = "Region"
Names[++i-1] = "FogState"
Names[++i-1] = "FogModifier"
Names[++i-1] = "Hashtable"
}
public string DetermineType(agent a)
{
int retVal = 0;
if(a != null)
{
SaveAgentHandle(Table,0,0,a);
if(LoadPlayerHandle(Table,0,0) != null){retVal = 1;}
elseif(LoadWidgetHandle(Table,0,0) != null){retVal = 2;}
elseif(LoadDestructableHandle(Table,0,0) != null){retVal = 3;}
elseif(LoadItemHandle(Table,0,0) != null){retVal = 4;}
elseif(LoadUnitHandle(Table,0,0) != null){retVal = 5;}
elseif(LoadAbilityHandle(Table,0,0) != null){retVal = 6;}
elseif(LoadTimerHandle(Table,0,0) != null){retVal = 7;}
elseif(LoadTriggerHandle(Table,0,0) != null){retVal = 8;}
elseif(LoadTriggerConditionHandle(Table,0,0) != null){retVal = 9;}
elseif(LoadTriggerActionHandle(Table,0,0) != null){retVal = 10;}
elseif(LoadTriggerEventHandle(Table,0,0) != null){retVal = 11;}
elseif(LoadForceHandle(Table,0,0) != null){retVal = 12;}
elseif(LoadGroupHandle(Table,0,0) != null){retVal = 13;}
elseif(LoadLocationHandle(Table,0,0) != null){retVal = 14;}
elseif(LoadRectHandle(Table,0,0) != null){retVal = 15;}
elseif(LoadBooleanExprHandle(Table,0,0) != null){retVal = 16;}
elseif(LoadSoundHandle(Table,0,0) != null){retVal = 17;}
elseif(LoadEffectHandle(Table,0,0) != null){retVal = 18;}
elseif(LoadUnitPoolHandle(Table,0,0) != null){retVal = 19;}
elseif(LoadItemPoolHandle(Table,0,0) != null){retVal = 20;}
elseif(LoadQuestHandle(Table,0,0) != null){retVal = 21;}
elseif(LoadQuestItemHandle(Table,0,0) != null){retVal = 22;}
elseif(LoadDefeatConditionHandle(Table,0,0) != null){retVal = 23;}
elseif(LoadTimerDialogHandle(Table,0,0) != null){retVal = 24;}
elseif(LoadLeaderboardHandle(Table,0,0) != null){retVal = 25;}
elseif(LoadMultiboardHandle(Table,0,0) != null){retVal = 26;}
elseif(LoadMultiboardItemHandle(Table,0,0) != null){retVal = 27;}
elseif(LoadTrackableHandle(Table,0,0) != null){retVal = 28;}
elseif(LoadDialogHandle(Table,0,0) != null){retVal = 29;}
elseif(LoadButtonHandle(Table,0,0) != null){retVal = 30;}
elseif(LoadTextTagHandle(Table,0,0) != null){retVal = 31;}
elseif(LoadLightningHandle(Table,0,0) != null){retVal = 32;}
elseif(LoadImageHandle(Table,0,0) != null){retVal = 33;}
elseif(LoadUbersplatHandle(Table,0,0) != null){retVal = 34;}
elseif(LoadRegionHandle(Table,0,0) != null){retVal = 34;}
elseif(LoadFogStateHandle(Table,0,0) != null){retVal = 35;}
elseif(LoadFogModifierHandle(Table,0,0) != null){retVal = 36;}
elseif(LoadHashtableHandle(Table,0,0) != null){retVal = 37;}
RemoveSavedHandle(Table,0,0)
}
return Names[retVal];
}
public agent TypeAgent(agent a)
{
return a; // not needed but you might be ultrastrict!
}
define private InittypeCast(TypeName,T) =
{
public T Type##T(agent a)
{
T retVal = null;
if(a != null)
{
SaveAgentHandle(Table,0,0,a);
retVal = Load##TypeName##Handle(Table,0,0)
}
return retVal;
}
}
InittypeCast(Player,player)
InittypeCast(Widget,widget)
InittypeCast(Destructable,destructable)
InittypeCast(Item,item)
InittypeCast(Unit,unit)
InittypeCast(Ability,ability)
InittypeCast(Timer,timer)
InittypeCast(Trigger,trigger)
InittypeCast(TriggerCondition,triggercondition)
InittypeCast(TriggerAction,triggeraction)
InittypeCast(TriggerEvent,event)
InittypeCast(Force,force)
InittypeCast(Group,group)
InittypeCast(Location,location)
InittypeCast(Rect,rect)
InittypeCast(BooleanExpr,boolexpr)
InittypeCast(Sound,sound)
InittypeCast(Effect,effect)
InittypeCast(UnitPool,unitpool)
InittypeCast(ItemPool,itempool)
InittypeCast(Quest,quest)
InittypeCast(QuestItem,questitem)
InittypeCast(DefeatCondition,defeatcondition)
InittypeCast(TimerDialog,timerdialog)
InittypeCast(Leaderboard,leaderboard)
InittypeCast(Multiboard,multiboard)
InittypeCast(MultiboardItem,multiboarditem)
InittypeCast(Trackable,trackable)
InittypeCast(Dialog,dialog)
InittypeCast(Button,button)
InittypeCast(TextTag,texttag)
InittypeCast(Lightning,lightning)
InittypeCast(Image,image)
InittypeCast(Ubersplat,ubersplat)
InittypeCast(Region,region)
InittypeCast(FogState,fogstate)
InittypeCast(FogModifier,fogmodifier)
InittypeCast(Hashtable,hashtable)
}Usage is simple, you type typeCast(typeYouWantCastToHere), it must be an agent type. This will let you cast things to agent subtypes safely. You can also determine type by using the method DT_DetermineType(myObj). It'll return a string of the type of the object. |
| 09-13-2009, 04:47 PM | #2 |
Determine agent type: Rather useless, unless you want it in debug messages. Even so calling 50 lines of code for debugging a single thing is also a little lame. TypeCastWhatever: Also quite useless. I dunno but we basically got used to not needing these typecasts... In the remote case we need one, calling HashTable directly seems easier than for example, saving an agent in an array and then calling the hashtable natives on it just to do the conversion. |
| 09-13-2009, 11:21 PM | #3 |
Look man, I hate C++ style typecast notation too, but its not bad and can be useful to write a generic deconstructor. Plus, it can make simpler attach systems like right now you might have to attach 2 peices of information or have dual redundancy to figure out type. I.e. The struct attached to the timer might have the triggering unit or the triggering item but you won't know. So right now your struct has 2 fields:: .triggerItem .triggerUnit and when you check to see hwat to handle you call, you check both. With this can store it as .triggerWidget and just check which typecast works. It's basically 'obj as T' in C#, or static_cast<T>(obj) in C++. DT_DetermineType is pretty useless agreed, but that's because we don't store enough information. I have an idea for some hook library to fix that though. |
| 09-14-2009, 01:50 AM | #4 |
generics are very nice feature in programming, indeed, and i hope it will get implemented into vJass cus lately ive been making data structure libraries like list, trees, heaps, queues and so fort |
| 09-14-2009, 05:12 AM | #5 |
Here is the updated version of the library. With an incomplete deallocator template. I delineated the body to give better performance. Instead of performing 29 comparisons you're looking at an average of 6 for registered types. For nonregistered obj its about 35. You can register an object using DT_SaveRet(T)(value here) which will allow you to use faster type casts, and allow quick deallocation. I'll work on the Dealloc later (as I'm lazy), but then I'll create a runtime stack. JASS:define typecast(T) = DT_TypeT define <Destroy>(T) = DT_DeallocT library DT initializer initDT { private hashtable Table = InitHashtable(); private string array Names; void initDT() 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" public int DetermineTypeInt(agent a) int retVal = 0; if(a != null) { retVal = LoadInteger(Table,0,GetHandleId(a)); // shortcut mode if(retVal == 0) // no shortcut. SaveAgentHandle(Table,0,0,a); if(LoadPlayerHandle(Table,0,0) != null){ retVal = DT_Player;} elseif(LoadDestructableHandle(Table,0,0) != null){ retVal = DT_Destructable;} elseif(LoadItemHandle(Table,0,0) != null){ retVal = DT_Item;} elseif(LoadUnitHandle(Table,0,0) != null){ retVal = DT_Unit;} elseif(LoadAbilityHandle(Table,0,0) != null){ retVal = DT_Ability;} elseif(LoadTimerHandle(Table,0,0) != null){ retVal = DT_Timer;} elseif(LoadTriggerHandle(Table,0,0) != null){ retVal = DT_Trigger;} elseif(LoadTriggerConditionHandle(Table,0,0) != null){ retVal = DT_TriggerCondition;} elseif(LoadTriggerEventHandle(Table,0,0) != null){ retVal = DT_TriggerEvent;} elseif(LoadForceHandle(Table,0,0) != null){ retVal = DT_Force;} elseif(LoadGroupHandle(Table,0,0) != null){ retVal = DT_Group;} elseif(LoadLocationHandle(Table,0,0) != null){ retVal = DT_Location;} elseif(LoadRectHandle(Table,0,0) != null){ retVal = DT_Rect;} elseif(LoadBooleanExprHandle(Table,0,0) != null){ retVal = DT_BooleanExpr;} elseif(LoadSoundHandle(Table,0,0) != null){ retVal = DT_Sound;} elseif(LoadEffectHandle(Table,0,0) != null){ retVal = DT_Effect;} elseif(LoadQuestHandle(Table,0,0) != null){ retVal = DT_Quest;} elseif(LoadQuestItemHandle(Table,0,0) != null){ retVal = DT_QuestItem;} elseif(LoadDefeatConditionHandle(Table,0,0) != null){ retVal = DT_DefeatCondition;} elseif(LoadTimerDialogHandle(Table,0,0) != null){ retVal = DT_TimerDialog;} elseif(LoadLeaderboardHandle(Table,0,0) != null){ retVal = DT_Leaderboard;} elseif(LoadMultiboardHandle(Table,0,0) != null){ retVal = DT_Multiboard;} elseif(LoadMultiboardItemHandle(Table,0,0) != null){ retVal = DT_MultiboardItem;} elseif(LoadTrackableHandle(Table,0,0) != null){ retVal = DT_Trackable;} elseif(LoadDialogHandle(Table,0,0) != null){ retVal = DT_Dialog;} elseif(LoadButtonHandle(Table,0,0) != null){ retVal = DT_Button;} elseif(LoadRegionHandle(Table,0,0) != null){ retVal = DT_Region;} elseif(LoadFogModifierHandle(Table,0,0) != null){ retVal = DT_FogModifier;} elseif(LoadHashtableHandle(Table,0,0) != null){ retVal = DT_Hashtable;} RemoveSavedHandle(Table,0,0); } return retVal; public string DetermineTypeName(agent a) return Names[DetermineTypeInt(a)]; define private InitSaveRet(typeNum,TypeName,T, Deconstructor,ED) = public int TypeName = typeNum public T TypeT(agent a) { T retVal = null; int id = 0; if(a != null) retVal = LoadTypeNameHandle(Table,0,GetHandleId(a)); if(retVal == null) { SaveAgentHandle(Table,0,0,a); retVal = LoadTypeNameHandle(Table,0,0); RemoveSavedHandle(Table,0,0); } return retVal; } public T saveRetT(T a) { SaveAgentHandle(Table,0,GetHandleId(a),a); SaveInteger(Table,0,GetHandleId(a),typeNum); return a; } public void deallocT(agent a) { Deconstructor typecast(T)(a) ED } /*public bool Deallocate(agent a) { bool retVal = false; int dt_type = DetermineTypeInt(a); if(dt_type > 14) { if(dt_type < 22) { if(dt_type < 18) { if(dt_type < 16){return 15} // 15 elseif(dt_type < 17){return 16} // 16 else{return 17} // 17 } elseif(dt_type < 21) { if(dt_type < 19){return 18} // 18 elseif(dt_type < 20){return 19} // 19 else{return 20} // 20 } else{return 21} // 21 } elseif(dt_type < 26) { if(dt_type < 24) { if(dt_type < 23){return 22} // 22 else{return 23} // 23 } elseif(dt_type < 25){return 24} // 24 else{return 25} // 25 } elseif(dt_type < 28) { if(dt_type < 27){return 26} // 26 else{return 27} // 27 } elseif(dt_type < 29){return 28} else {return 29} // 29 } elseif(dt_type > 7) { if(dt_type > 11) if(dt_type > 13) {return 14} // 14 elseif(dt_type >12) {return 13}// 13 else {return 12} // 12 elseif(dt_type > 9) if(dt_type > 10) {return 11} // 11 else {return 10} // 10 elseif(dt_type > 8) {return 9} // 9 else {return 8} // 8 } elseif(dt_type > 3) { if(dt_type > 5) if(dt_type > 6){return 7} // 7 else {return 6} // 6 elseif(dt_type > 4){return 5} // 5 else{return 4} // 4 } elseif(dt_type > 1) if(dt_type > 2){dealloc} else { RemoveDestructable(typecast(destructable)(a)); retVal = true; } elseif(dt_type > 0){} else{ return 0} return retVal; }*/ public agent TypeAgent(agent a) return a; // not needed but you might be ultrastrict! // The 29 agent types, these support type casting, //those with a 4th param & 5thsupport deconstruction InitSaveRet(1,Player,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,,) } it's funny that I'm practically the father of the H2I monster method, and here I am creating typecasters again. I was looking over my old code like ItemMenu and I found a comment on H2I did anyone think this was going away? Well I guess I didn't. Anyway, It seems bizarre that there are agent types that don't have deconstructors, and there all also non-agent types that do! |
| 09-14-2009, 06:59 AM | #6 | |
Quote:
ability being an agent is the only really weird one I can find from a quick look. As for non-agents with destructors: Agents are allocated in the "normal" handle table within the game. That's what defines the agent type. lightning, weathereffect (the type for which null is always the first value returned by the Create method. And null works as a valid value, too!), texttag, and a few others I think, are allocated in different/weird ways within the game. You can tell that just by creating values of different types and running them through GetHandleID(). Those above 0x1000000 (... i think thats the right number of 0's. It's been a while.) are allocated normally as reference-counted agents. Also note that GetConverted_____(int) functions are native I2H(). So is Player(int). (Why blizzard didn't have these types extend integer instead of handle is a fucking mystery...) |
| 09-14-2009, 01:45 PM | #7 | |
Quote:
|
| 09-15-2009, 12:19 AM | #8 |
Isn't the ability agent not creatable? |
| 09-15-2009, 01:56 AM | #9 |
No constructor, but you can fetch an instance with:: constant native GetSpellAbility takes nothing returns ability Not sure what you can do with it. I guess you can store it in a hashtable and check |
