Vendor Tracking Addon

Eorzea Time
 
 
 
Language: JP EN FR DE
Version 3.1
New Items
users online
Forum » Windower » General » vendor tracking addon
vendor tracking addon
Offline
Posts: 1390
By Kaffy 2025-10-02 17:29:03
Link | Quote | Reply
 
I want to be able to toggle the addon on/off, and when I sell items to a vendor for gil, they get added to a text file by item name. Anyone able to help?
 Asura.Malkavius
Offline
Server: Asura
Game: FFXI
user: Malkavius
Posts: 97
By Asura.Malkavius 2025-10-02 17:50:31
Link | Quote | Reply
 
ChatGPT will do it for you
[+]
Offline
Posts: 1390
By Kaffy 2025-10-02 17:59:53
Link | Quote | Reply
 
funny enough I did try that first, and I did a poor job explaining what I wanted because after 3 revisions I gave up
Offline
Posts: 1390
By Kaffy 2025-10-03 11:54:13
Link | Quote | Reply
 
ok caveat emptor I am not a programmer nor do I know lots about packets, but here seems to be a simple working addon to build a list of junk by selling items to a vendor. the addon does not sell or drop anything for you, all it does is build a list so you can use it elsewhere. even so, I would double check the list before using it. if you see something majorly wrong here please let me know.

two commands
//vendor toggle to turn logging on and off, off by default
//vendor clean to sort the txt file into a lua table
Code
-- addon setup
_addon.name = 'vendor'
_addon.version = '1.0'
_addon.author = 'kaffy'
_addon.commands = {'vendor'}

local packets = require('packets')
local res_items = require('resources').items
local log_file = 'junk.txt'
local logging_enabled = false
local seen_items = {}

-- utility: write to file
local function log_item_name(item_id)
    local item = res_items[item_id]
    if item and logging_enabled and not seen_items[item.name] then
        seen_items[item.name] = true
        local f = io.open(windower.addon_path .. log_file, 'a')
        if f then
            f:write(item.name .. '\n')
            f:close()
        end
    end
end

-- hook outgoing packet: 0x084 = Sell item to NPC
windower.register_event('outgoing chunk', function(id, data, modified, injected, blocked)
    if id == 0x084 then
        local packet = packets.parse('outgoing', data)
        local item_id = packet.Item
        log_item_name(item_id)
    end
end)

-- command handler
windower.register_event('addon command', function(cmd)
    if cmd:lower() == 'toggle' then
		logging_enabled = not logging_enabled
		windower.add_to_chat(123, 'vendor: logging ' .. (logging_enabled and 'enabled' or 'disabled'))
	end
	if cmd:lower() == 'clean' then
        local path = windower.addon_path .. 'junk.txt'
        local f = io.open(path, 'r')
        if not f then
            windower.add_to_chat(123, 'vendor: junk.txt not found.')
            return
        end

        local items = {}
        for line in f:lines() do
            local name = line:match('^%s*(.-)%s*$') -- trim whitespace
            if name ~= '' then
                items[name] = true
            end
        end
        f:close()

        -- convert to sorted list
        local sorted = {}
        for name in pairs(items) do
            table.insert(sorted, name)
        end
        table.sort(sorted)

        -- write to Lua table
        local out = io.open(windower.addon_path .. 'junk.lua', 'w')
        if out then
            out:write('return {\n')
            for _, name in ipairs(sorted) do
                out:write(string.format("    %q,\n", name))
            end
            out:write('}\n')
            out:close()
            windower.add_to_chat(123, 'vendor: junk.lua written.')
        else
            windower.add_to_chat(123, 'vendor: failed to write junk.lua.')
        end
    end
end)
 Shiva.Thorny
Offline
Server: Shiva
Game: FFXI
user: Rairin
Posts: 3541
By Shiva.Thorny 2025-10-03 12:02:13
Link | Quote | Reply
 
Seems reasonable. Someone who knows what they're doing would probably just save as a table and load the same table on load, so it doesn't create duplicates every new load. Probably save as item ID instead of name; you can use the resources to output in whatever format you want when you run your dedicated command anyway.

Nothing that's blatantly wrong or likely to introduce unexpected items, though.
Offline
Posts: 1390
By Kaffy 2025-10-03 12:09:30
Link | Quote | Reply
 
great feedback, will see what I can do to save and load
 Carbuncle.Nynja
Online
Server: Carbuncle
Game: FFXI
user: NynJa
Posts: 6099
By Carbuncle.Nynja 2025-10-03 12:09:33
Link | Quote | Reply
 
my guess is he wants to take that list and put it into a sellnpc profile, and you need the name for that, not ID.


Or maybe I'm wrong
Offline
Posts: 1390
By Kaffy 2025-10-03 12:27:03
Link | Quote | Reply
 
yeah basically bypassing manual input for sellnpc, treasury, etc.

updated:
Code
-- addon setup
_addon.name = 'vendor'
_addon.version = '1.1'
_addon.author = 'kaffy'
_addon.commands = {'vendor'}

local packets = require('packets')
local res_items = require('resources').items
local junk_table_path = windower.addon_path .. 'junk.lua'
local logging_enabled = false
local seen_items = {}

-- load junk table
local function load_junk_table()
    local f = loadfile(junk_table_path)
    if f then
        local ok, data = pcall(f)
        if ok and type(data) == 'table' then
            for _, name in ipairs(data) do
                seen_items[name] = true
            end
        end
    end
end

load_junk_table()

local function log_item_name(item_id)
    local item = res_items[item_id]
    if item and logging_enabled and not seen_items[item.name] then
        seen_items[item.name] = true
    end
end

local function save_junk_table()
    local sorted = {}
    for name in pairs(seen_items) do
        table.insert(sorted, name)
    end
    table.sort(sorted)

    local out = io.open(junk_table_path, 'w')
    if out then
        out:write('return {\n')
        for _, name in ipairs(sorted) do
            out:write(string.format("    %q,\n", name))
        end
        out:write('}\n')
        out:close()
        return true
    end
    return false
end

-- hook outgoing packet: 0x084 = Sell item to NPC
windower.register_event('outgoing chunk', function(id, data, modified, injected, blocked)
    if id == 0x084 then
        local packet = packets.parse('outgoing', data)
        local item_id = packet.Item
        log_item_name(item_id)
    end
end)

-- command handler
windower.register_event('addon command', function(cmd)
    if cmd:lower() == 'toggle' then
		logging_enabled = not logging_enabled
		windower.add_to_chat(123, 'vendor: logging ' .. (logging_enabled and 'enabled' or 'disabled'))
	end
	if cmd:lower() == 'clean' then
    if save_junk_table() then
        windower.add_to_chat(123, 'vendor: junk.lua updated.')
    else
        windower.add_to_chat(123, 'vendor: failed to write junk.lua.')
    end
	end
end)

windower.register_event('unload', save_junk_table)