• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

(vJASS/Lua) ModelPathExtractor

Level 19
Joined
Aug 16, 2007
Messages
881
ModelPathExtractor allow one to get the model path as string of Widgets, Units, Items and Destructables.

Demo map and example images attached.

JASS:
library ModelPathExtractor initializer Init requires optional WidgetType
//===========================================================================
//
//   ModelPathExtractor, 1.2a | 2023-12-30
//   by lolreported
//   https://www.hiveworkshop.com/threads/vjass-lua-modelpathextractor.352061/
//
//   Credits appreciated, but not required.
//
// 
//   This library provides an easy way to get the model path as string from
//   any widget, unit, item or destructable.
//
//   Uses BlzSetItemSkin and BlzGetItemStringField natives in order to get the model path.
//   BlzSetItemSkin skinId doesn't care what type of id is given.
// 
//
//   Optional Requirement(s):
//   WidgetType by Pyrogasm and lolreported
//   https://www.hiveworkshop.com/threads/vjass-lua-modelpathextractor.352061/post-3606079
//
//
//   Generic API
//   function GetModelPathByType             takes integer anyType                returns string // returns the model path of any type id/skin id
//
//   Note: Functions below are wrapper functions of GetModelPathByType for convenience
//
//   function GetModelPath                   takes widget whichWidget             returns string // returns the default model path of any widget (requires WidgetType library)
//   function GetModelPathWithSkin           takes widget whichWidget             returns string // returns the current model path of any widget (requires WidgetType library)
//
//   Unit API
//   function GetUnitModelPathByType         takes integer unitType               returns string // returns the model path of unit-type
//   function GetUnitModelPath               takes unit whichUnit                 returns string // returns the default model path
//   function GetUnitModelPathWithSkin       takes unit whichUnit                 returns string // returns the current model path
//
//   Item API
//   function GetItemModelPathByType         takes integer itemType               returns string // returns the model path of item-type
//   function GetItemModelPath               takes item whichItem                 returns string // returns the default model path
//   function GetItemModelPathWithSkin       takes item whichItem                 returns string // returns the current model path
//
//   Destructable API
//   function GetDestructableModelPathByType takes integer destructableType       returns string // returns the model path of destructable-type
//   function GetDestructableModelPath       takes destructable whichDestructable returns string // returns the default model path
//
//
//===========================================================================

    globals
        private item i = null
    endglobals

    private function Init takes nothing returns nothing
        // Create the item to be used with model path extraction and then hide it forever.
        set i = CreateItem('ratf', 0, 0)
        call SetItemVisible(i, false)
    endfunction

    // GENERIC
    function GetModelPathByType takes integer anyType returns string
        call BlzSetItemSkin(i, anyType)
        return BlzGetItemStringField(i, ITEM_SF_MODEL_USED)
    endfunction
  
    static if LIBRARY_WidgetType then
        function GetModelPath takes widget whichWidget returns string
            return GetModelPathByType(GetWidgetTypeId(whichWidget))
        endfunction
      
        function GetModelPathWithSkin takes widget whichWidget returns string
            return GetModelPathByType(GetWidgetSkin(whichWidget))
        endfunction
    endif

    // UNIT
    function GetUnitModelPathByType takes integer unitType returns string
        return GetModelPathByType(unitType)
    endfunction
  
    function GetUnitModelPath takes unit whichUnit returns string
        return GetModelPathByType(GetUnitTypeId(whichUnit))
    endfunction
  
    function GetUnitModelPathWithSkin takes unit whichUnit returns string
        return GetModelPathByType(BlzGetUnitSkin(whichUnit))
    endfunction
  
    // ITEM
    function GetItemModelPathByType takes integer itemType returns string
        return GetModelPathByType(itemType)
    endfunction
  
    function GetItemModelPath takes item whichItem returns string
        return GetModelPathByType(GetItemTypeId(whichItem))
    endfunction
  
    function GetItemModelPathWithSkin takes item whichItem returns string
        return GetModelPathByType(BlzGetItemSkin(whichItem))
    endfunction
  
    // DESTRUCTABLE
    function GetDestructableModelPathByType takes integer destructableType returns string
        return GetModelPathByType(destructableType)
    endfunction
  
    function GetDestructableModelPath takes destructable whichDestructable returns string
        return GetModelPathByType(GetDestructableTypeId(whichDestructable))
    endfunction
  
    //function GetDestructableModelPathWithSkin takes destructable whichDestructable returns string
    //    return GetModelPathByType(BlzGetDestructableSkin(whichDestructable)) // native BlzGetDestructableSkin Not Implemented
    //endfunction
endlibrary

Based of Version 1.0a,
doesn't have functions:
  • GetModelPath
  • GetModelPathWithSkin
  • GetDestructableModelPathWithSkin

Link: [vJASS] - ModelPathExtractor
Credits to Wrda


# 1.0a
Release

# 1.1a
Added optional library WidgetType by Pyrogasm
Added function GetModelPath (requires WidgetType)
Added function GetModelPathWithSkin (requires WidgetType)
Added disabled function GetDestructableModelPathWithSkin in case Blizzard implements BlzGetDestructableSkin native in the future

# 1.2a
Updated WidgetType library to v1.1
Added link to this page and date in documentation


Any feedback appreciated!
 

Attachments

  • example1.png
    example1.png
    5.6 MB · Views: 28
  • example2.png
    example2.png
    5.5 MB · Views: 27
  • ModelPathExtractor1.2a.w3m
    22.9 KB · Views: 2
Last edited:

Wrda

Spell Reviewer
Level 26
Joined
Nov 18, 2012
Messages
1,888
Here you go. Debug Utils and total Initialization aren't required.

Lua:
if Debug then Debug.beginFile "ModelPathExtractor" end
--[[===========================================================================
//
//   ModelPathExtractor
//   1.0a by lolreported
//   Credits appreciated, but not required.
//
//   This library provides an easy way to get the model path as string from
//   any unit, item or destructable.
//
//   Uses BlzSetItemSkin and BlzGetItemStringField natives in order to get the model path.
//   BlzSetItemSkin skinId doesn't care what type of id is given.
//   
//
//   Generic API
//   function GetModelPathByType             takes integer anyType                returns string // returns the model path of any type
//
//   Note: Functions below are wrapper functions of GetModelPathByType for convenience
//
//   Unit API
//   function GetUnitModelPathByType         takes integer unitType               returns string // returns the model path of unit-type
//   function GetUnitModelPath               takes unit whichUnit                 returns string // returns the default model path
//   function GetUnitModelPathWithSkin       takes unit whichUnit                 returns string // returns the current model path
//
//   Item API
//   function GetItemModelPathByType         takes integer itemType               returns string // returns the model path of item-type
//   function GetItemModelPatah               takes item whichItem                 returns string // returns the default model path
//   function GetItemModelPathWithSkin       takes item whichItem                 returns string // returns the current model path
//
//   Destructable API
//   function GetDestructableModelPathByType takes integer destructableType       returns string // returns the model path of destructable-type
//   function GetDestructableModelPath       takes destructable whichDestructable returns string // returns the default model path
//
//
//===========================================================================]]
    local item
    local cache = setmetatable({}, {})
    local mt = getmetatable(cache)
    mt.__index = function(t, k)
        BlzSetItemSkin(item, k)
        return BlzGetItemStringField(item, ITEM_SF_MODEL_USED)
    end

    local function init()
        -- Create the item to be used with model path extraction and then hide it forever.
        item = CreateItem(FourCC('ratf'), 0, 0)
        SetItemVisible(item, false)
    end
    if OnInit then
        OnInit.global(init)
    else
        local old = MarkGameStarted
        function MarkGameStarted()
            old()
            init()
        end
    end

    ---GENERIC
    ---@param anyType integer
    ---@return string
    function GetModelPathByType(anyType)
        return cache[anyType]
    end
    
    --function GetModelPath takes widget whichWidget returns string
    --  Let me know if it is possible to detect if the widget is of unit, item or destructable.
    --end

    --UNIT

    ---@param unitType integer
    ---@return string
    function GetUnitModelPathByType(unitType)
        return GetModelPathByType(unitType)
    end
    
    ---@param whichUnit unit
    ---@return string
    function GetUnitModelPath(whichUnit)
        return GetModelPathByType(GetUnitTypeId(whichUnit))
    end
    
    ---@param whichUnit unit
    ---@return string
    function GetUnitModelPathWithSkin(whichUnit)
        return GetModelPathByType(BlzGetUnitSkin(whichUnit))
    end
    
    ---ITEM
    ---@param itemType integer
    ---@return string
    function GetItemModelPathByType(itemType)
        return GetModelPathByType(itemType)
    end
    
    ---@param whichItem item
    ---@return string
    function GetItemModelPath(whichItem)
        return GetModelPathByType(GetItemTypeId(whichItem))
    end
    
    ---@param whichItem item
    ---@return string
    function GetItemModelPathWithSkin(whichItem)
        return GetModelPathByType(BlzGetItemSkin(whichItem))
    end
    
    --- DESTRUCTABLE
    ---@param destructableType integer
    ---@return string
    function GetDestructableModelPathByType(destructableType)
        return GetModelPathByType(destructableType)
    end

    ---@param whichDestructable destructable
    ---@return string
    function GetDestructableModelPath(whichDestructable)
        return GetModelPathByType(GetDestructableTypeId(whichDestructable))
    end
if Debug then Debug.endFile() end
 

Attachments

  • ModelPathExtractorLua1.0a.w3m
    112.6 KB · Views: 1
Last edited:
Level 39
Joined
Feb 27, 2007
Messages
5,016
Let me know if it is possible to detect if the widget is of unit, item or destructable.
Yes, at the cost of 2-6 hashtable stores/reads per widget. That might matter if checking an obscene number of them but it shouldn't be an issue generally. The various Get<widget>TypeId functions all return 0 if you typecast to a different type than the widget actually is. There probably isn't a situation where this doesn't work but I added _UNKNOWN just in case.
JASS:
library WidgetType
  // by Pyrogasm and lolreported v1.1
  // 12-30-2023

  globals
    constant integer WIDGET_TYPE_UNKNOWN = 0
    constant integer WIDGET_TYPE_UNIT = 1
    constant integer WIDGET_TYPE_ITEM = 2
    constant integer WIDGET_TYPE_DESTRUCTABLE = 3
    
    private unit TestU
    private item TestI
    private destructable TestD

    private hashtable HT = InitHashtable()
  endglobals

  function GetWidgetType takes widget W returns integer
    call SaveWidgetHandle(HT,0,0,W)
    
    if GetUnitTypeId(LoadUnitHandle(HT,0,0)) > 0 then
      return WIDGET_TYPE_UNIT
    elseif GetItemTypeId(LoadItemHandle(HT,0,0)) > 0 then
      return WIDGET_TYPE_ITEM
    elseif GetDestructableTypeId(LoadDestructableHandle(HT,0,0)) > 0 then
      return WIDGET_TYPE_DESTRUCTABLE
    endif
    
    return WIDGET_TYPE_UNKNOWN
  endfunction
  
  function GetWidgetTypeId takes widget W returns integer
    local integer id
    call SaveWidgetHandle(HT,0,0,W)
    
    set id = GetUnitTypeId(LoadUnitHandle(HT,0,0))
    if id > 0 then
      return id
    endif
    set id = GetItemTypeId(LoadItemHandle(HT,0,0))
    if id > 0 then
      return id
    endif
    set id = GetDestructableTypeId(LoadDestructableHandle(HT,0,0))
    if id > 0 then
      return id
    endif
    
    return 0
  endfunction
  
  function GetWidgetSkin takes widget W returns integer
    call SaveWidgetHandle(HT,0,0,W)
    
    set TestU = LoadUnitHandle(HT,0,0)
    if GetUnitTypeId(TestU) > 0 then
      return BlzGetUnitSkin(TestU)
    endif

    set TestI = LoadItemHandle(HT,0,0)
    if GetItemTypeId(TestI) > 0 then
      return BlzGetItemSkin(TestI)
    endif
    
    set TestD = LoadDestructableHandle(HT,0,0)
    if GetDestructableTypeId(TestD) > 0 then
      //return BlzGetDestructableSkin(TestD) // native BlzGetDestructableSkin Not Implemented
      return 0
    endif
    
    return 0
  endfunction
endlibrary
 
Last edited:
Level 19
Joined
Aug 16, 2007
Messages
881
ModelPathExtractor updated to 1.1a, changes in main post.

Edit: ModelPathExtractor updated to 1.2a, changes in main post.


Yes, at the cost of 2-6 hashtable stores/reads per widget. That might matter if checking an obscene number of them but it shouldn't be an issue generally. The various Get<widget>TypeId functions all return 0 if you typecast to a different type than the widget actually is. There probably isn't a situation where this doesn't work but I added _UNKNOWN just in case.
JASS:
library GetWidgetType
  // by Pyrogasm v1.0
  // 12-29-2023

  globals
    constant integer WIDGET_TYPE_UNKNOWN = 0
    constant integer WIDGET_TYPE_UNIT = 1
    constant integer WIDGET_TYPE_ITEM = 2
    constant integer WIDGET_TYPE_DESTRUCTABLE = 3
  
    private unit TestU
    private item TestI
    private destructable TestD

    private hashtable HT = InitHashtable()
  endglobals

  function GetWidgetType takes widget W returns integer
    call SaveWidgetHandle(HT,0,0,W)
    set TestU = LoadUnitHandle(HT,0,0)
    if GetUnitTypeId(TestU) > 0 then
      return WIDGET_TYPE_UNIT
    endif

    call SaveWidgetHandle(HT,0,0,W)
    set TestI = LoadItemHandle(HT,0,0)
    if GetItemTypeId(TestI) > 0 then
      return WIDGET_TYPE_ITEM
    endif
  
    call SaveWidgetHandle(HT,0,0,W)
    set TestD = LoadDestructableHandle(HT,0,0)
    if GetDestructableTypeId(TestD) > 0 then
      return WIDGET_TYPE_DESTRUCTABLE
    endif
  
    return WIDGET_TYPE_UNKNOWN
  endfunction
endlibrary
Great, thanks!

I added two functions to your library,
JASS:
  function GetWidgetTypeId takes widget W returns integer
    call SaveWidgetHandle(HT,0,0,W)
    set TestU = LoadUnitHandle(HT,0,0)
    if GetUnitTypeId(TestU) > 0 then
      return GetUnitTypeId(TestU)
    endif

    call SaveWidgetHandle(HT,0,0,W)
    set TestI = LoadItemHandle(HT,0,0)
    if GetItemTypeId(TestI) > 0 then
      return GetItemTypeId(TestI)
    endif
   
    call SaveWidgetHandle(HT,0,0,W)
    set TestD = LoadDestructableHandle(HT,0,0)
    if GetDestructableTypeId(TestD) > 0 then
      return GetDestructableTypeId(TestD)
    endif
   
    return 0
  endfunction
 
  function GetWidgetSkin takes widget W returns integer
    call SaveWidgetHandle(HT,0,0,W)
    set TestU = LoadUnitHandle(HT,0,0)
    if GetUnitTypeId(TestU) > 0 then
      return BlzGetUnitSkin(TestU)
    endif

    call SaveWidgetHandle(HT,0,0,W)
    set TestI = LoadItemHandle(HT,0,0)
    if GetItemTypeId(TestI) > 0 then
      return BlzGetItemSkin(TestI)
    endif
   
    call SaveWidgetHandle(HT,0,0,W)
    set TestD = LoadDestructableHandle(HT,0,0)
    if GetDestructableTypeId(TestD) > 0 then
      //return BlzGetDestructableSkin(TestD) // native BlzGetDestructableSkin Not Implemented
      return 0
    endif
   
    return 0
  endfunction

If you approve, please edit your post with the functions, as I refer to your post for the library.
Let me know if you don't approve and I'll make an update with my own library for widgets.
 
Last edited:
Top