Thread Tools Display Modes
11/23/15, 09:03 PM   #1
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
extending AwesomeGuildStore

This is primarily aimed at @sirinsidiator, I just wouldn't want to lose out on ideas others might suggest. Here are the two things I'm trying to do with AGS:
1) decile filter: cuts off results more expensive than N tenths of results on the current page (per item name); with N=5 the cut point is the median, so only the cheaper half of results will be shown.
2) sort results by name, then unit price -- will describe in another post

The decile filter needs to have all results before it starts filtering, so I gather them in f:BeforeRebuildSearchResultsPage, build a table of what should be kept, and f:FilterPageResult simply consults that table. It works well, but I'm still not completely comfortable with the fact that GetTradingHouseSearchResultItemInfo is called twice for each result -- first in my "Before" hook and then during the actual filtering. So I started thinking...

What if AGS' RebuildSearchResultsPage did:
- gather all ZO_TradingHouse_CreateItemData(i, GetTradingHouseSearchResultItemInfo) in a table
- pass that table to filters' PreprocessSearchResultsPage method -- this should not remove anything from the table
- replace ZO_TradingHouse_CreateItemData with a function that runs filters' FilterPageResultData and returns either data or nil

I'd like to know what you think because it has 2 quite big drawbacks so I'm not comfortable with that either:
- creating item data for all results; currently no table is created for results that are filtered out
- some ugly compatibility code:
Lua Code:
  1. function FilterBase:FilterPageResultData(data)
  2.     -- delegate to older method
  3.     return self:FilterPageResult(data.slotIndex, data.icon, data.name, data.quality, data.stackCount, data.sellerName, data.timeRemaining, data.purchasePrice, data.currencyType)
  4. end
  Reply With Quote
11/23/15, 09:56 PM   #2
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
2) sort results by name, then unit price

Sorting should probably happen before this point. AfterRebuildSearchResultsPage comes later, so would require another commit.

You can do that by temporarily replacing ZO_ScrollList_Commit. I have another suggestion, a bit hackier but one that avoids swapping global functions -- instead replacing the environment of the original method:

Lua Code:
  1. local clsRebuildSearchResultsPage = getmetatable(TRADING_HOUSE).RebuildSearchResultsPage
  2. local orgENV = getfenv(clsRebuildSearchResultsPage) -- this will be _G until more add-ons abuse it
  3. local newENV = setmetatable({}, {__index = orgENV})
  4.  
  5. setfenv(clsRebuildSearchResultsPage, newENV)
  6.  
  7. -- copy to avoid double lookups
  8. newENV.ZO_ScrollList_CreateDataEntry = orgENV.ZO_ScrollList_CreateDataEntry
  9. newENV.ZO_TradingHouse_CreateItemData = orgENV.ZO_TradingHouse_CreateItemData
  10.  
  11. function newENV.ZO_ScrollList_ResetToTop(list)
  12.     orgENV.ZO_ScrollList_ResetToTop(list)
  13.     -- BeforeRebuildSearchResultsPage
  14. end
  15.  
  16. function newENV.GetTradingHouseSearchResultItemInfo(...)
  17.     -- FakeGetTradingHouseSearchResultItemInfo
  18. end
  19.  
  20. function newENV.ZO_ScrollList_Commit(list)
  21.     -- AfterRebuildSearchResultsPage (+ sort)
  22.     orgENV.ZO_ScrollList_Commit(list)
  23. end


Now I realized I could do the decile filter after all other filters, before sorting -- in AfterRebuildSearchResultsPage, but preferably before list commit. That might actually make more sense.... but it's too late. I should read this tomorrow and see if it still sounds like a good idea
  Reply With Quote
11/24/15, 02:44 AM   #3
QuadroTony
Banned
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 828
/offtopic
btw for experienced traders only one sort order important - by time from new to old
this way also you can buy cheapest items because usually new items has lowest price than old items

Last edited by QuadroTony : 11/24/15 at 07:44 AM.
  Reply With Quote
11/24/15, 07:11 AM   #4
sirinsidiator
 
sirinsidiator's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 1,578
1) Decile filter sounds really cool, but I don't really know what I would do with one. There is already a price filter, unit price filter and MM's deal filter which all reduce the amount of items to only show the best bargains. Don't let that stop you from making one, but there is usually not much left to filter once these 3 are applied with the correct settings.

I think the additional calls to GetTradingHouseSearchResultItemInfo are the lesser of two evils. If it is called 200 times instead of 100 times should not really make a difference overall. Changing the behavior of CreateItemData just makes the code more complicated and does not have any real benefit IMO.

2) Your hack looks really hackish. I guess it would need much more comments in order to make clear what it does.
Maybe just use function swapping instead.

One major problem with changing the local sort order is that the API uses the item index for purchasing, so we need to keep that information intact.
I would just do everything related to sorting in a swapped out ZO_ScrollList_Commit and leave the other methods alone.
The searchtab wrapper is already wrapping around that method twice and calls ZO_ScrollList_Commit a second time, so that should also be combine into one call with some added hook points.
And last but not least there was also the feature request from Tony to prevent the scroll list from resetting to top in some cases which would also go in there. (I haven't forgotten about that )

Quite a few things that will go in there.

Maybe ZOS can add a few hook points to make it a bit easier?

Lua Code:
  1. function ZO_TradingHouse_CreateItemData(index, fn, filter)
  2.     local icon, name, quality, stackCount, sellerName, timeRemaining, purchasePrice, currencyType = fn(index)
  3.     if(name ~= "" and stackCount > 0) then
  4.       if(type(filter) == "function" and filter(icon, name, quality, stackCount, sellerName, timeRemaining, purchasePrice, currencyType)) then
  5.         local result =
  6.         {
  7.             slotIndex = index,
  8.             icon = icon,
  9.             name = name,
  10.             quality = quality,
  11.             stackCount = stackCount,
  12.             sellerName = sellerName,
  13.             timeRemaining = timeRemaining,
  14.             purchasePrice = purchasePrice,
  15.             currencyType = currencyType or CURT_MONEY
  16.         }
  17.  
  18.         return result
  19.       else
  20.         return true -- to indicate that it exists but was filtered
  21.       end
  22.     end
  23. end

Lua Code:
  1. function ZO_TradingHouseManager:RebuildSearchResultsPage(preventResetToTop)
  2.     local list = self.m_searchResultsList
  3.     local scrollData = ZO_ScrollList_GetDataList(list)
  4.     ZO_ScrollList_Clear(list)
  5.     if(not preventResetToTop) then ZO_ScrollList_ResetToTop(list) end
  6.  
  7.     self:BeforeFilterSearchResultsPage()
  8.     local hiddenNumItems = 0
  9.     for i = 1, self.m_numItemsOnPage do
  10.         local result = ZO_TradingHouse_CreateItemData(i, GetTradingHouseSearchResultItemInfo, self.SearchResultFilterFunction) -- The default SearchResultFilterFunction just returns true and can be prehooked or wrapped by addons
  11.         if(result == true) then hiddenNumItems = hiddenNumItems + 1
  12.         elseif(result) then
  13.             scrollData[#scrollData + 1] = ZO_ScrollList_CreateDataEntry(SEARCH_RESULTS_DATA_TYPE, result)
  14.         end
  15.     end
  16.  
  17.     local numItems = #scrollData
  18.     local totalNumItems = hiddenNumItems + numItems
  19.     self:AfterFilterSearchResultsPage(totalNumItems, numItems)
  20.     self:UpdateItemsLabels(totalNumItems, numItems)
  21.  
  22.     -- If no results were returned, disallow further searches (until one or more search criteria are modified),
  23.     -- and display a "no items found" label.
  24.     self.m_searchAllowed = (totalNumItems ~= 0)
  25.     self.m_noItemsLabel:SetHidden(totalNumItems ~= 0)
  26.  
  27.     self:SortSearchResultsPage(scrollData)
  28.     ZO_ScrollList_Commit(list)
  29. end
  30.  
  31. function ZO_TradingHouseManager:OnPurchaseSuccess()
  32.     self:RebuildSearchResultsPage(true)
  33. end
  Reply With Quote
11/24/15, 10:32 AM   #5
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Originally Posted by sirinsidiator View Post
1) Decile filter sounds really cool, but I don't really know what I would do with one. There is already a price filter, unit price filter and MM's deal filter which all reduce the amount of items to only show the best bargains. Don't let that stop you from making one, but there is usually not much left to filter once these 3 are applied with the correct settings.
It spawned from my usage of guild stores. I don't use MM, it's pointless without a high frequency trading guild, and even if I had one, I'd be reluctant to use MM because then it'd be a hog.

For instance, I'm buying Shadowhide and Void Cloth for writs; for me cheap Shadowhide is ~4g, Void Cloth ~5g. Stack price filter helps, I set max 1000g. Unit price doesn't help much, since there are stores with dozens of Shadowhide stacks @4.5g. I'd need separate presets with name filter. Actually when I first messaged you about it, I was writing a different thing -- adding context menu entry for marking an item overpriced (by itemId) and then filtering those out. But that would basically require building a database of fair prices by hand, so I scratched that. Plus it wouldn't help at all with the case when I mark Shadowhide overpriced @4.5g and then visit a store with 40 stacks of Shadowhide for 4.4g.

I don't want to have separate presets for Shadowhide, Void Cloth, Elegant Lining, Dreugh Wax, raw mats etc...
Some stores have only a few stacks of nothing interesting, I don't want to go through 5 presets to find that out.

Now I come to a store searching for Clothing mats, set stack price filter max to 2000g, decile filter to 1st (1/10) ... and if there are 50 full stacks of shadowhide on the page, I only see 5 no matter what their price is; so I don't have to scroll as much to find some Void Cloth. And I also get to see cheap raw mats if there are any under 10g.

Originally Posted by sirinsidiator View Post
One major problem with changing the local sort order is that the API uses the item index for purchasing, so we need to keep that information intact.
I would just do everything related to sorting in a swapped out ZO_ScrollList_Commit and leave the other methods alone.
The searchtab wrapper is already wrapping around that method twice and calls ZO_ScrollList_Commit a second time, so that should also be combine into one call with some added hook points.
And last but not least there was also the feature request from Tony to prevent the scroll list from resetting to top in some cases which would also go in there. (I haven't forgotten about that )
There's "slotIndex" in the data, the order in list is irrelevant (proof is the added "go to previous page" row).

I didn't notice the second wrapper. That one could be injected between sort and commit.
  Reply With Quote

ESOUI » Developer Discussions » General Authoring Discussion » extending AwesomeGuildStore


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off