From 2254d61cbd4bd5536aa319ba388e167c0845d775 Mon Sep 17 00:00:00 2001 From: ts Date: Sun, 15 Aug 2021 19:15:21 -0400 Subject: [PATCH 1/5] (not tested!) pointwatch - automatically update message IDs I never logged in to test if this would load, but I did test it locally to see if the functions could pull the correct IDs from DAT files sent by a friend. (c) dos2unix, struct to lpack, read *a to read 2 --- addons/pointwatch/libs/dialog.lua | 130 ++++++++++++++++++++++++++++++ addons/pointwatch/message_ids.lua | 77 +++++++++++++++++- 2 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 addons/pointwatch/libs/dialog.lua diff --git a/addons/pointwatch/libs/dialog.lua b/addons/pointwatch/libs/dialog.lua new file mode 100644 index 0000000000..860deacc67 --- /dev/null +++ b/addons/pointwatch/libs/dialog.lua @@ -0,0 +1,130 @@ +--Copyright (c) 2014, Byrthnoth +--All rights reserved. + +--Redistribution and use in source and binary forms, with or without +--modification, are permitted provided that the following conditions are met: + +-- * Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- * Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- * Neither the name of nor the +-- names of its contributors may be used to endorse or promote products +-- derived from this software without specific prior written permission. + +--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +--ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +--WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +--DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +--DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +--(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +--LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +--ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +--(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +local xor = require('bit').bxor +require('pack') +local unpack = require('string').unpack +local pack = require('string').pack +local find = require('string').find + +local dialog = {} + +local function decode(int) + return xor(int, 0x80808080) +end +local encode = decode + +local floor = require('math').floor +local function binary_search(pos, dat, n) + local l, r, m = 1, n + while l < r do + m = floor((l+r)/2) + if decode(unpack(' 0 then + local f = io.open(ftable, 'rb') + local offset = 2*dat_id + f:seek('set', offset) + local dat = f:read(2) + f:close() + + local packed_16bit = byte(dat, 2) * 256 + byte(dat, 1) + local dir = floor(packed_16bit / 128) + local file = packed_16bit - dir * 128 + + path = rom .. tostring(dir) .. '/' .. tostring(file) .. '.DAT' + end + f:close() + n = n + 1 + local d = tostring(n) + rom = dat_path .. 'ROM' .. d .. '/' + vtable = rom .. 'VTABLE' .. d .. '.DAT' + ftable = rom .. 'FTABLE' .. d .. '.DAT' + until path or not windower.dir_exists(rom) + if not path then print('Could not convert dat ID', dat_id) return end + + -- convert dialog entry to dialog ID + local dialog = require('libs/dialog') + local search_phrase = string.char( + 158,133,214,233,243,233,244,225,238,244,160,204,233,231,232, + 244,160,201,238,244,229,238,243,233,244,249,158,129,135,208, + 229,225,242,236,229,243,227,229,238,244,186,160,138,128,160, + 175,160,197,226,239,238,186,160,138,129,135,199,239,236,228, + 229,238,186,160,138,130,160,175,160,211,233,236,246,229,242, + 249,186,160,138,131,255,177,128,135 + ) + local f = io.open(path, 'rb') + local dat = f:read('*a') + f:close() + local id = dialog.get_entry_id(dat, search_phrase) + if not id then return end -- ruh roh + + messages['z'..tostring(zone_id)].offset = id + t[zone_id] = nil + end +end + +update_offset(windower.ffxi.get_info().zone) +windower.register_event('zone change', update_offset) + return messages + From ec8f53abd71e6dfbd9edd191310de94f278c978e Mon Sep 17 00:00:00 2001 From: ts Date: Mon, 13 Sep 2021 17:14:06 -0400 Subject: [PATCH 2/5] duplicate entries There are duplicates in the tables. That's a pain. --- addons/pointwatch/libs/dialog.lua | 133 ++++++++++++++++++++---------- addons/pointwatch/message_ids.lua | 12 ++- 2 files changed, 99 insertions(+), 46 deletions(-) diff --git a/addons/pointwatch/libs/dialog.lua b/addons/pointwatch/libs/dialog.lua index 860deacc67..fcc9983df0 100644 --- a/addons/pointwatch/libs/dialog.lua +++ b/addons/pointwatch/libs/dialog.lua @@ -24,11 +24,24 @@ --(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS --SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- This library was written to help find the ID of a known +-- action message corresponding to an entry in the dialog tables. +-- While the IDs can be collected in-game, they occasionally +-- change and would otherwise need to be manually updated. +-- It can also be used to find and decode an entry given the ID. + +-- Common parameters: +-- dat: The entire content of the zone dialog DAT file +-- i.e. local dat = io.open('path/to/dialog/DAT', 'rb'):read('*a') +-- entry: The string you are looking for. If you do not know the +-- entire string, use dev_find_substring. + local xor = require('bit').bxor require('pack') -local unpack = require('string').unpack -local pack = require('string').pack -local find = require('string').find +local string = require('string') +local unpack = string.unpack +local pack = string.pack +local find = string.find local dialog = {} @@ -49,33 +62,59 @@ local function binary_search(pos, dat, n) r = m end end - return l-2 - -- -1 since we want the index to the left of where "pos" would be placed - -- another -1 to convert to 0-indexing + return l-2 -- we want the index to the left of where "pos" would be placed +end + +local function plain_text_gmatch(text, substring, n) + n = n or 1 + return function() + local pos = find(text, substring, n, true) + if pos then n = pos + 1 end + return pos + end end function dialog.dev_get_offset(dat, id) -- sanity check function - return decode(unpack(' last_offset then + break + elseif offset == last_offset then + next_pos = #dat+1 + else + next_pos = decode(unpack(' 0 then local f = io.open(ftable, 'rb') local offset = 2*dat_id - f:seek('set', offset) + f:seek('set', offset) local dat = f:read(2) f:close() @@ -249,10 +249,14 @@ local function update_offset(zone_id) local f = io.open(path, 'rb') local dat = f:read('*a') f:close() - local id = dialog.get_entry_id(dat, search_phrase) - if not id then return end -- ruh roh + local res = dialog.get_ids_matching_entry(dat, search_phrase) + if res.n ~= 1 then + print('In pointwatch/message_ids.lua: matched multiple entries') + print('Could not update message ID.') + return + end - messages['z'..tostring(zone_id)].offset = id + messages['z'..tostring(zone_id)].offset = res[1] t[zone_id] = nil end end From 30338c630b0730dbccba96794b0bfc9fe3dba665 Mon Sep 17 00:00:00 2001 From: trevor Date: Tue, 23 Nov 2021 21:12:58 -0500 Subject: [PATCH 3/5] Use the other libs/dialog --- addons/pointwatch/libs/dialog.lua | 179 ------------------------------ addons/pointwatch/message_ids.lua | 4 +- 2 files changed, 2 insertions(+), 181 deletions(-) delete mode 100644 addons/pointwatch/libs/dialog.lua diff --git a/addons/pointwatch/libs/dialog.lua b/addons/pointwatch/libs/dialog.lua deleted file mode 100644 index fcc9983df0..0000000000 --- a/addons/pointwatch/libs/dialog.lua +++ /dev/null @@ -1,179 +0,0 @@ ---Copyright (c) 2014, Byrthnoth ---All rights reserved. - ---Redistribution and use in source and binary forms, with or without ---modification, are permitted provided that the following conditions are met: - --- * Redistributions of source code must retain the above copyright --- notice, this list of conditions and the following disclaimer. --- * Redistributions in binary form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- * Neither the name of nor the --- names of its contributors may be used to endorse or promote products --- derived from this software without specific prior written permission. - ---THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ---ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ---WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ---DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY ---DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ---(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ---LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ---ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ---(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ---SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - --- This library was written to help find the ID of a known --- action message corresponding to an entry in the dialog tables. --- While the IDs can be collected in-game, they occasionally --- change and would otherwise need to be manually updated. --- It can also be used to find and decode an entry given the ID. - --- Common parameters: --- dat: The entire content of the zone dialog DAT file --- i.e. local dat = io.open('path/to/dialog/DAT', 'rb'):read('*a') --- entry: The string you are looking for. If you do not know the --- entire string, use dev_find_substring. - -local xor = require('bit').bxor -require('pack') -local string = require('string') -local unpack = string.unpack -local pack = string.pack -local find = string.find - -local dialog = {} - -local function decode(int) - return xor(int, 0x80808080) -end -local encode = decode - -local floor = require('math').floor -local function binary_search(pos, dat, n) - local l, r, m = 1, n - while l < r do - m = floor((l+r)/2) - if decode(unpack(' last_offset then - break - elseif offset == last_offset then - next_pos = #dat+1 - else - next_pos = decode(unpack(' Date: Tue, 14 Dec 2021 19:12:40 -0500 Subject: [PATCH 4/5] Moved id conversion to dialog lib --- addons/pointwatch/message_ids.lua | 57 ++++++------------------------- 1 file changed, 11 insertions(+), 46 deletions(-) diff --git a/addons/pointwatch/message_ids.lua b/addons/pointwatch/message_ids.lua index e996fdc0d7..9f893399e1 100644 --- a/addons/pointwatch/message_ids.lua +++ b/addons/pointwatch/message_ids.lua @@ -189,53 +189,18 @@ local messages = { local function update_offset(zone_id) -- zone to dat ID mapping for Abyssean zones local t = { - [15] = 6435, -- 23/80 - [45] = 6465, -- 23/110 - [132] = 6552, -- 24/69 - [215] = 6635, -- 25/24 - [216] = 6636, -- 25/25 - [217] = 6637, -- 25/26 - [218] = 6638, -- 25/27 - [253] = 6673, -- 25/62 - [254] = 6674, -- 25/63 + [15] = true, + [45] = true, + [132] = true, + [215] = true, + [216] = true, + [217] = true, + [218] = true, + [253] = true, + [254] = true, } if t[zone_id] then - -- convert dat ID to dat file path - local floor = require('math').floor - local byte = require('string').byte - local dat_id = t[zone_id] - local dat_path = windower.ffxi_path - local path - local vtable = dat_path .. 'VTABLE.DAT' - local ftable = dat_path .. 'FTABLE.DAT' - local n = 1 - local rom = dat_path .. 'ROM/' - repeat - local f = io.open(vtable, 'rb') - f:seek('set', dat_id) - if byte(f:read(1)) > 0 then - local f = io.open(ftable, 'rb') - local offset = 2*dat_id - f:seek('set', offset) - local dat = f:read(2) - f:close() - - local packed_16bit = byte(dat, 2) * 256 + byte(dat, 1) - local dir = floor(packed_16bit / 128) - local file = packed_16bit - dir * 128 - - path = rom .. tostring(dir) .. '/' .. tostring(file) .. '.DAT' - end - f:close() - n = n + 1 - local d = tostring(n) - rom = dat_path .. 'ROM' .. d .. '/' - vtable = rom .. 'VTABLE' .. d .. '.DAT' - ftable = rom .. 'FTABLE' .. d .. '.DAT' - until path or not windower.dir_exists(rom) - if not path then print('Could not convert dat ID', dat_id) return end - -- convert dialog entry to dialog ID local dialog = require('dialog') local search_phrase = string.char( @@ -246,12 +211,12 @@ local function update_offset(zone_id) 229,238,186,160,138,130,160,175,160,211,233,236,246,229,242, 249,186,160,138,131,255,177,128,135 ) - local f = io.open(path, 'rb') + local f = dialog.open_dat_by_zone_id(zone_id, 'english') local dat = f:read('*a') f:close() local res = dialog.get_ids_matching_entry(dat, search_phrase) if #res ~= 1 then - print('In pointwatch/message_ids.lua: matched multiple entries') + print('In pointwatch/message_ids.lua: matched multiple or no entries.') print('Could not update message ID.') return end From 78af443ee17a778848d9ecd8fe47e135b129f008 Mon Sep 17 00:00:00 2001 From: trevor Date: Mon, 10 Jan 2022 22:35:09 -0500 Subject: [PATCH 5/5] Verify logged in. Only update once. --- addons/pointwatch/message_ids.lua | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/addons/pointwatch/message_ids.lua b/addons/pointwatch/message_ids.lua index 9f893399e1..de950c313f 100644 --- a/addons/pointwatch/message_ids.lua +++ b/addons/pointwatch/message_ids.lua @@ -187,20 +187,9 @@ local messages = { } local function update_offset(zone_id) - -- zone to dat ID mapping for Abyssean zones - local t = { - [15] = true, - [45] = true, - [132] = true, - [215] = true, - [216] = true, - [217] = true, - [218] = true, - [253] = true, - [254] = true, - } - - if t[zone_id] then + local z_string = 'z' .. tostring(zone_id) + local m = messages[z_string] + if m and m.name then -- convert dialog entry to dialog ID local dialog = require('dialog') local search_phrase = string.char( @@ -221,12 +210,17 @@ local function update_offset(zone_id) return end - messages['z'..tostring(zone_id)].offset = res[1] - t[zone_id] = nil + m.offset = res[1] + m.name = nil end end -update_offset(windower.ffxi.get_info().zone) +do + local info = windower.ffxi.get_info() + if info.logged_in then + update_offset(info.zone) + end +end windower.register_event('zone change', update_offset) return messages