The December Project (The Grand Refactoring and The License)

Ludovicus_Maior's picture

Earlier this week I got a good/bad email from my HR department informing me that I needed to take X hours of vacation between now and the end of the year, or I would lose it.

This means that starting tomorrow (Dec2), I am now forced to take Thursdays and Fridays off.  No doubt this will cause friction at home because now I will want to monopolize the computer for my own purposes.

So starting tomorrow, I will begin the changes to start putting the common bits of code in all the Guide addons (Leveling, Event, Dailies, Professions) into the base addon. 

I'll do it a function/variable at a time, quest a bit and then move on.  The basic idea is simple. 

  1. WoWPro will become a "Library" which will support the "Embed" method
  2. Every function and method to be exported will be registered with WoWPro:Export("function"), which will add it to a list
  3. The Guide addons will call the WoWPro:Embed(WowPro_XXX) method at the start of loading, which will add all the "standard" methods and functions.  The addon is free to redefine anything it wants to override.

That is it!   Once this exercise is complete, we will be left with much less code in the addons.  We can then work at migrating the leftover goodies in the guide addons back into the base addon to make functionality even across the guides.

Now, along the way, I may change the way some things work.   Right now, for instance, the guide list code is bollixed up because each addon implements its own tab and tab management functions that do not have the right information at initialization time to do the right thing.  I'll rewrite that code to make it data driven and provide functions in WowPro: for the addons to register functions to return the number of guides, the number of columns and the column labels and to provide a call back when the user selects a row.  All of the window handling logic will be centralized and the guide specific information kept out of the core addon.

Oh, and as I go along, I will start adding copyright notices to all the files.  This has been discussed on and off now for nearly a year and now we have settled on a bit of a compromise.  We have opted to not try to write one of our own licenses (that way there be dragons), but to use a customizable license: the Creative Commons License

They give us a nice little logo to use: which if you click it, leads to both a human readable and a lawyer readable license.

What does it boil down to:

  • Under this license, users can redistribute the code, which we are not thrilled about, but is a minor annoyance.They would have to attribute the code to us (the WoW-Pro Community) and link back to our web site.
  • Users can't use the code commercially.
  • Users can't redistribute the code if they modify it (so our competitors can't take it and change a couple things and redistribute it).

The advantage of this license is that it's well recognized and has an infrastructure in place which explains decently.

 

 

 

Comments

Ludovicus_Maior's picture

Progress Report for 12/27

So what could possibly take 17 calendar days?

 

  1. A missing frame:Show() in one function
  2. A misspelled variable.

Once I found the first, the second was obvious.  I was nearly in tears this afternoon.   Now I can get rid of all the debugging code  and convert the rest of the addons to use the new GuideList.

Sooo painful. Writing an automatic way of generating the trial version of the Leveling addon was trivial in comparison.

But now everything scrolls smoothly!

Ludovicus_Maior's picture

Progress Report for 1/1

I now have the other addons converted over.  Testing and releasing on Wednesday, Jan 4!

 

World Event Module

That's great news.  Hopefully the changes I made to the World Event Module won't put much of a hamper into that plan.  For the most part, they are pretty simple.  Once you release the changes, I will see about putting  in the changes I am making to the professions module.  Those are bigger changes to eliminate all those steps and make it a little more user friendly.

Crackerhead22's picture

Don't forget about the Lunar

Don't forget about the Lunar Festival Elder guides.  http://wow-pro.com/wiki/lunar_festival_alliance  and  http://wow-pro.com/wiki/lunar_festival_horde

I really need to figure out Github more...  Would probably make it a lot easier for you with me making new guides or updates.

Crackerhead22's picture

Oh yea...  I forgot Lunar

Oh yea...  I forgot Lunar Festival doesn't begin until mid January.  Sheesh I'm an idiot.

Ludovicus_Maior's picture

Progress Report for 12/10

So I got a bit distracted.   The Guide List code had this annoying bug where the number of lines displayed was a fixed constant and depending on the size of the options window, it would either not use the whole window or overflow.

Fixing it has been a pain in the $%##!   But I am now learning everything about the WoW windowing system that I have avoided for the past year.

But that was not the distraction.   I started doing archeology on my current active toon,  Agriotherium, and then realized that I had not been exploring everything as throughly as usual.   So I added Exploration guides for every zone in Kalimdor and the Eastern Kingdoms that Twists had not already done.

But the Acheivement guides use the ACH tag, which takes an acheivement Id and a criteria number.  How to get these?  Write a program!

 


function WoWPro.Achievements:DumpInfo(achnum)
local count = GetAchievementNumCriteria(achnum)
WoWPro.Achievements.eBox = WoWPro.Achievements.eBox or CreateFrame("EditBox", nil,UIParent,ChatFrameEditBoxTemplate)
local eBox = WoWPro.Achievements.eBox
eBox:SetWidth(512)
eBox:SetHeight(128)
eBox:SetMultiLine(true)
eBox:SetAutoFocus(true)
eBox:SetFontObject(GameFontHighlight)
local text=""
for achitem=1, count do
local description, type, completed, quantity, requiredQuantity, characterName, flags, assetID, quantityString, criteriaID = GetAchievementCriteriaInfo(achnum, achitem)
local line = string.format("F %s|QID|%d|M|0.00,0.00|ACH|%d;%d|",description,900000000+10000*achnum+achitem,achnum,achitem)
-- self:Print(line)
text = text .. line .. "\n"
end
eBox:SetText(text)
eBox:SetPoint("CENTER")
eBox:Show()
eBox:SetScript("OnEscapePressed", function (self) self:Hide() end)
self:Print("Dumped %d items",count)
end

So if you "/run WoWPro.Achievements:DumpInfo(859)" this pops a window in the middle of the screen with a sketch for a guide for achievement 859, Explore Eversong Woods.

Now the fun part starts, write a program to order the flight points to minimize the travel time, assuming you can fly.

The classic shortest path problem, time to drag out Dijkstra's Algorithm!

Obtaining objectives

This is alot easier then the way I was doing it.  What I was doing was going to wowhead for the zone.  The numbers are then layed out in rows going from the 1st one on the left (1) to the second on the right (2), then back to the left next (3), etc.  It pretty much follows that pattern.

The hard part is the locations.  Those are not always given in wowhead.  I haven't really had time to tackle the rest of the explorations ones, but I am working hard on re-writing the code for the professions guide.  Hope to have that one soon.

 

I really hate this captcha.

Ludovicus_Maior's picture

Obtaining objectives - First find a chump

I have a confession to make:   I did not fill in the coordinates for the exploration guides.

I have slowly trained my spouse to do things like edit guides, cross reference things against wowhead and how to fill in the blanks.

So I offered to cook a fancy dinner and bribed him into doing >95% of them.

The first drafts are now checked in, and the release is cut.  I need to do some quick checks and I will release it tomorrow.

I have this VERY beta change to the module that re-orders the exploration points according to your current position in the zone, triggered by a zone change.  This means the guide will present you with the closest objective that you have not acheived yet.  It needs to be sped up a bit and to have a better way of controlling which guides it gets applied to.

BUT I should really finish up the GuideList changes.  Now I know I never want to do UI programming for a living. 

 

Crackerhead22's picture

That is just too funny.  Wish

That is just too funny.  Wish I could do the same, but I can't cook.  Not from lack of trying, I just don't have the knack for it (though I am good with desserts..).  And my wife isn't very good with editing and cross referencing.

Crackerhead22's picture

WoWPro Achievment module Error

Not sure what is going on, but getting this error.

Date: 2011-12-10 19:30:12
ID: 1
Error occured in: Global
Count: 1
Message: ...s\WoWPro_Achievements\WoWPro_Achievements_Parser.lua line 204:
attempt to index field 'ach' (a nil value)
Debug:
[C]: ?
...s\WoWPro_Achievements\WoWPro_Achievements_Parser.lua:204:
...s\WoWPro_Achievements\WoWPro_Achievements_Parser.lua:125
...s\WoWPro_Achievements\WoWPro_Achievements_Parser.lua:229: LoadGuide()
WoWPro\WoWPro_Broker.lua:66: LoadGuide()
WoWPro\WoWPro.lua:162:
WoWPro\WoWPro.lua:155

Ludovicus_Maior's picture

WoWPro Achievment module Error, -- patch

Yup! Got a patch for that:

diff --git a/WoWPro_Achievements/WoWPro_Achievements.lua b/WoWPro_Achievements/WoWPro_Achievements.lua
index 320317f..6a6f5a5 100644
--- a/WoWPro_Achievements/WoWPro_Achievements.lua
+++ b/WoWPro_Achievements/WoWPro_Achievements.lua
@@ -17,7 +19,7 @@ function WoWPro.Achievements:OnEnable()
        WoWPro:dbp("|cff33ff33Enabled|r: Achievements Module")
        
        -- Achievements Tag Setup --
-       WoWPro:RegisterTags({"QID", "questtext", "rep", "noncombat"})
+       WoWPro:RegisterTags({"QID", "questtext", "rep", "noncombat","ach"})
        
        -- Event Registration --
        WoWPro.Achievements.Events = {"QUEST_LOG_UPDATE", "QUEST_COMPLETE", 

lfo@throne;69$ 

Crackerhead22's picture

So this is addon code to help

So this is addon code to help make achievment guides?  If so, what should the .lua file be named and located?

Dijkstra's Algorithm!  Run away!  Haven't seen that in ages, so long I forgot about it.

Ludovicus_Maior's picture

... I guess I ought to ...

It was a little thow-away code that I wrote.

I'll stick it in WoWPro_Achievements.lua for now and it will be out on Wednesday.

I was just thinking this morning that it would also help with many other types of acheivements, like the fishing or kill one of X ones.

 

Crackerhead22's picture

Yep, I agree.

Yep, I agree.  Also if possible, maybe have the option to have it save to a txt document?  If that is too much though don't worry about it.

Ludovicus_Maior's picture

WoW and Text Documents

WoW specifcally prohbits creating/reading/writing/deleting files in order to make it "safe".

Lord I wish you had access to web information!

But the window my snippet creates is an edit window and supports select all and copy paste, which makes it easy to plop into a text document yourself.

 

Crackerhead22's picture

I see, so that makes it just

I see, so that makes it just as good then, if not better.

Ludovicus_Maior's picture

The new GuideList.lua, a progress report for 12/3

So I decided to tackle the GuideLists as the first refactoring mini-project.

I cut down the code in the Leveling module to just the following blocks:

WoWPro.Leveling.GuideList = {}

-- Creating a Table of Guides for the Guide List and sorting based on level --
local guides = {}
for guidID,guide in pairs(WoWPro.Guides) do
	if guide.guidetype == "Leveling" then
	    local progress = ""
	    if guide.total and guide.progress then
	        progress = guide.progress .. "/" .. guide.total
	    end
		table.insert(guides, {
			GID = guidID,
			Zone = guide.zone,
			Author = guide.author,
			Range = "("..guide.startlevel.."-"..guide.endlevel..")",
			Progress = progress, 
			startlevel = guide.startlevel,
		})
	end
end
WoWPro.Leveling.GuideList.Guides = guides

-- Sorting Functions --
local sorttype = "Default"
local function authorSort()
	if sorttype == "AuthorAsc" then
		table.sort(guides, function(a,b) return a.author > b.author end)
		WoWPro.Leveling:UpdateGuideList()
		sorttype = "AuthorDesc"
	else
		table.sort(guides, function(a,b) return a.author < b.author end)
		WoWPro.Leveling.UpdateGuideList()
		sorttype = "AuthorAsc"
	end
end
local function zoneSort()
   ...
end
local function rangeSort()
...
end
rangeSort()             -- Sort by range
sorttype = "Default"    -- and reset to Default
		
-- Describe the table to the Core Module
WoWPro.Leveling.GuideList.Format={{"Zone",0.35,zoneSort},
      {"Range",0.15,rangeSort},
      {"Author",0.30,authorSort},
      {"Progess",0.20,nil}}

The base module looks at the specification in GuideList.Format and builds the buttons and text boxes and uses the field names to extract the data out of GuideList.Guides . UpdateGuideList() is a generic method imported from the WoWPro module. The fractional numbers set the width of the field as a percent of the total width.

Once I get it functional (I am a terrible speller), it should be easy to get the other Guides converted. It should even handle the new muti-sized options window correctly.

Crackerhead22's picture

Err...?

Err...?  I have no idea what this means.  I can do simple stuff but you're kind of beyond my realm of current understanding.

 

  1. WoWPro will become a "Library" which will support the "Embed" method
  2. Every function and method to be exported will be registered with WoWPro:Export("function"), which will add it to a list
  3. The Guide addons will call the WoWPro:Embed(WowPro_XXX) method at
    the start of loading, which will add all the "standard" methods and
    functions.  The addon is free to redefine anything it wants to override.

I think I need to stick with dealing with PC hardware for the most part.  XD

Ludovicus_Maior's picture

A Practical Example

The first function I ported was :Print().

In  WowPro.Lua:

 

WoWPro.Name = "WoWPro"
...
WowPro:Export("Print")
function WoWPro:Print(message)
    if message ~= nil then
        print(string.format("|cffffff00%s|r: %s", self.Name or "Wow-Pro" , message))
    end
end

In WowPro_Leveling.lua:

WoWPro.Leveling.Name = "WowProLeveling"

WoWPro:Embed(WoWPro.Leveling)

...

WoWPro.Leveling:Print("|cff33ff33Enabled|r")

Now when you call :Print, it gets passed as the self object either WoWPro.Leveling or WoWPro and can therefore prefix the message with the name of the module.  Every function in WoWPro.Leveling that gets migrated, I need to decide if any variable or function references need to be changed to self: or pegged at WowPro: .  Does that make it any clearer?

 

Completed Zone Re-Selecting?

(For whatever reason I can't create a NEW post, so I'm sorry to do it this way, but I don't see another method...)

While you are working under the hood on wow-pro, is there a way to enable still being able to select a Zone even if every task in it is checfked off?  The way it is now, if every task is checked as completed (or even skipped, I think), the interface no longer allows the User to select that Zone.  It just jumps to the next one in the list.  I've ran into several times when I really wanted to get to a specific step to remeber where I was (or how to get somewhere), but if the interface disallows re-selecting completed Zones, this isn't possible.

 

Thank you!

 

M.

Crackerhead22's picture

Actually there is a way. 

Actually there is a way.  Reset the guide, shift+click it while in the Guide List.

Crackerhead22's picture

Nope, but hazarding a guess I

Nope, but hazarding a guess I would say it is basically what it prints on the screen for us to read?

Silvann's picture

Sounds good! I'll wait before

Sounds good! I'll wait before messing with the Localization then.