Skip to content

Adapt LibSharedMedia-3.0 for WoW 3.3.5a WOTLK client - #3

Draft
ayanimea with Copilot wants to merge 5 commits into
mainfrom
copilot/adapt-libsharedmedia-for-wotlk
Draft

Adapt LibSharedMedia-3.0 for WoW 3.3.5a WOTLK client#3
ayanimea with Copilot wants to merge 5 commits into
mainfrom
copilot/adapt-libsharedmedia-for-wotlk

Conversation

Copilot AI commented Mar 1, 2026

Copy link
Copy Markdown

The upstream LibSharedMedia-3.0 targets modern retail/Classic-rerelease WoW clients and contains several incompatibilities with the original 3.3.5a client: missing interface version, a runtime-crashing sound sentinel value, a missing WoW API in the bundled CallbackHandler, and references to textures/fonts that don't exist in 3.3.5a.

Changes

TOC (LibSharedMedia-3.0.toc)

  • Add 30300 to ## Interface: — the WoW 3.3.5a client interface number

MINOR version

  • 1200000112000002 — kept monotonically increasing relative to upstream so this build reliably takes precedence over any older embedded LSM copy loaded via LibStub, regardless of load order

CallbackHandler-1.0 (CallbackHandler-1.0/CallbackHandler-1.0.lua)

  • securecallfunction is a retail WoW global that does not exist in the 3.3.5a client. Added a fallback that preserves CallbackHandler's error-isolation semantics using xpcall/geterrorhandler, so callback errors are caught and routed to the WoW error handler rather than propagating and aborting dispatch of subsequent handlers:
    local xpcall = xpcall
    local geterrorhandler = geterrorhandler
    local securecallfunction = securecallfunction or function(func, ...)
        if geterrorhandler then
            local errorhandler = geterrorhandler()
            if errorhandler then
                xpcall(func, errorhandler, ...)
                return
            end
        end
        return func(...)
    end

Sound "None" sentinel (LibSharedMedia-3.0.lua)

  • = 1= [[Interface\Quiet.ogg]]; PlaySoundFile in 3.3.5a is string-only — passing an integer throws a Lua error. Using a non-empty string sentinel ensures Fetch returns a valid string value to consumers; since the file does not exist in the 3.3.5a client, PlaySoundFile silently does nothing.

Removed post-WotLK background textures

Removed entry Reason
Blizzard Collections Background Collections UI added post-WotLK
Blizzard Garrison Background (×3) Garrison added in WoD (6.x)
Blizzard Parchment 2 Guild achievements added in Cataclysm (4.x)

Western-locale fonts

  • MORPHEUS_CYR.TTFMORPHEUS.TTF
  • SKURRI_CYR.TTFSKURRI.TTF

The _CYR variants were introduced in post-WotLK patches; the 3.3.5a western client ships only the base versions.

Original prompt

This section details on the original issue you should resolve

<issue_title>Adapt LibSharedMedia for WoW 3.3.5a WOTLK version</issue_title>
<issue_description>Goal:
Adapt the uploaded LibSharedMedia content to ensure compatibility with the World of Warcraft 3.3.5a WOTLK client.

Tasks:

  • Review all existing functionality and APIs used to identify 3.3.5a-specific requirements or incompatibilities.
  • Update function calls, constants, and library integrations as needed for 3.3.5a.
  • Test all features in a 3.3.5a client to confirm correct operation, including fonts, sounds, borders, and other shared media assets.
  • Document any notable changes, deprecations, or required manual configuration for users updating from earlier versions.

Acceptance Criteria:

  • The library loads without errors on 3.3.5a.
  • All media registration and retrieval functions behave correctly.
  • No breaking changes for current project consumers beyond those needed for 3.3.5a compatibility.

Let me know if any additional context or input is required to proceed with this adaptation request.</issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Co-authored-by: ayanimea <13433370+ayanimea@users.noreply.github.com>
@ayanimea
ayanimea requested a review from Copilot March 1, 2026 15:55
Copilot AI changed the title [WIP] Update LibSharedMedia for WoW 3.3.5a compatibility Adapt LibSharedMedia-3.0 for WoW 3.3.5a WOTLK client Mar 1, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates LibSharedMedia-3.0 to better support the WoW 3.3.5a (WotLK) client by adjusting metadata and default media entries to avoid referencing assets/APIs not present or incompatible on that client.

Changes:

  • Add 30300 to the TOC Interface list for 3.3.5a recognition.
  • Adjust default media tables for 3.3.5a (remove unavailable Blizzard backgrounds; fix western font paths; make sound "None" an empty string so Fetch returns nil).
  • Update the library MINOR version number.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
LibSharedMedia-3.0/LibSharedMedia-3.0.lua Updates library MINOR and adjusts default media entries (backgrounds/fonts/sound “None”) for 3.3.5a compatibility.
LibSharedMedia-3.0.toc Adds 30300 to the Interface metadata to support WoW 3.3.5a.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread LibSharedMedia-3.0/LibSharedMedia-3.0.lua Outdated
@ayanimea

ayanimea commented Mar 1, 2026

Copy link
Copy Markdown
Owner

@copilot apply changes based on the comments in this thread

…ibStub precedence

Co-authored-by: ayanimea <13433370+ayanimea@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

-- SOUND
if not lib.MediaTable.sound then lib.MediaTable.sound = {} end
lib.MediaTable.sound["None"] = 1 -- Relies on the fact that PlaySoundFile doesn't error on this value
lib.MediaTable.sound["None"] = [[]] -- PlaySoundFile in WoW 3.3.5a requires a string; Fetch returns nil for empty strings (no sound)

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With lib.MediaTable.sound["None"] = [[]], lib:Fetch("sound", "None") will return nil because of the result ~= "" and result or nil guard. Since the comment notes that PlaySoundFile in 3.3.5a is string-only, consumers doing PlaySoundFile(LSM:Fetch(...)) will still error (now due to nil, not due to an integer). Consider keeping Fetch’s return value a (non-empty) string for the "None" sound (e.g., adjust Fetch to not nil-out empty strings for sound, or use a known-safe string sentinel) so existing consumer call patterns don’t crash.

Suggested change
lib.MediaTable.sound["None"] = [[]] -- PlaySoundFile in WoW 3.3.5a requires a string; Fetch returns nil for empty strings (no sound)
lib.MediaTable.sound["None"] = [[Interface\Quiet.ogg]] -- Use a non-empty dummy path so Fetch returns a string; represents "no sound" while keeping PlaySoundFile(LSM:Fetch(...)) safe

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 9ed8493 — changed to [[Interface\Quiet.ogg]]. Fetch now returns a non-nil string for "None", so PlaySoundFile(LSM:Fetch("sound","None")) receives a valid string. Since that file doesn't exist in 3.3.5a, PlaySoundFile silently does nothing.

@ayanimea

ayanimea commented Mar 1, 2026

Copy link
Copy Markdown
Owner

@copilot Lua errors (58 of them, here is the first):
Message: ...edia-3.0\CallbackHandler-1.0\CallbackHandler-1.0.lua:19: attempt to call upvalue 'securecallfunction' (a nil value)
Time: 03/01/26 17:03:06
Count: 1
Stack: ...edia-3.0\CallbackHandler-1.0\CallbackHandler-1.0.lua:19: in function <...edia-3.0\CallbackHandler-1.0\CallbackHandler-1.0.lua:15>
...edia-3.0\CallbackHandler-1.0\CallbackHandler-1.0.lua:54: in function Fire' ...dMedia-3.0\LibSharedMedia-3.0\LibSharedMedia-3.0.lua:271: in function Register'
Interface\AddOns\DBM-Core\DBM-TimerTracker.lua:32: in main chunk

Locals: handlers =

{
(null) = defined @interface\AddOns\LibSharedMedia-3.0\CallbackHandler-1.0\CallbackHandler-1.0.lua:109
(null) = defined @interface\AddOns\LibSharedMedia-3.0\CallbackHandler-1.0\CallbackHandler-1.0.lua:109
}
index =
{
ChatEdit_SetLastActiveWindow = defined @interface\AddOns\Chatter\Modules\EditBox.lua:400
SetDefaultModuleLibraries = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:398
Enable = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:325
NewModule = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:266
FCF_Tab_OnClick = defined @interface\AddOns\Chatter\Modules\EditBox.lua:366
EnableModule = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:363
modules =
{
}
GetModule = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:241
IterateEmbeds = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:473
SecureHookScript = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceHook-3.0\AceHook-3.0.lua:410
defaultModuleLibraries =
{
}
RawHookScript = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceHook-3.0\AceHook-3.0.lua:395
LibSharedMedia_Registered = defined @interface\AddOns\Chatter\Modules\EditBox.lua:233
GetName = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:310
GetOptions = defined @interface\AddOns\Chatter\Modules\EditBox.lua:416
SetAttach = defined @interface\AddOns\Chatter\Modules\EditBox.lua:491
name = "Chatter_Edit Box Polish"
IsEnabled = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:482
orderedModules =
{
}
Decorate = defined @interface\AddOns\Chatter\Modules\EditBox.lua:287
DisableModule = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:381
baseName = "Chatter"
SetBackdrop = defined @interface\AddOns\Chatter\Modules\EditBox.lua:420
HookScript = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceHook-3.0\AceHook-3.0.lua:366
frames =
{
}
SecureHook = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceHook-3.0\AceHook-3.0.lua:336
IsHooked = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceHook-3.0\AceHook-3.0.lua:493
UnhookAll = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceHook-3.0\AceHook-3.0.lua:477
SetBorderByChannel = defined @interface\AddOns\Chatter\Modules\EditBox.lua:438
IsModule = defined @interface\AddOns\Bagnon\libs\AceAddon-3.0\AceAddon-3.0.lua:237
db =
{
}
SetDefaultModuleState = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:418
ChatEdit_DeactivateChat = defined @interface\AddOns\Chatter\Modules\EditBox.lua:409
OnDisable = defined @interface\AddOns\Chatter\Modules\EditBox.lua:373
SetEnabledState = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:455
Hook = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceHook-3.0\AceHook-3.0.lua:274
enabledState = false
OnEnable = defined @interface\AddOns\Chatter\Modules\EditBox.lua:321
OnInitialize = def

@ayanimea

ayanimea commented Mar 1, 2026

Copy link
Copy Markdown
Owner

@copilot apply changes based on the comments in this thread

…sound None sentinel

Co-authored-by: ayanimea <13433370+ayanimea@users.noreply.github.com>

Copilot AI commented Mar 1, 2026

Copy link
Copy Markdown
Author

@copilot Lua errors (58 of them, here is the first):
Message: ...edia-3.0\CallbackHandler-1.0\CallbackHandler-1.0.lua:19: attempt to call upvalue 'securecallfunction' (a nil value)
Time: 03/01/26 17...

Fixed in 9ed8493. securecallfunction is a retail-era WoW global that doesn't exist in 3.3.5a. CallbackHandler-1.0 now falls back to a direct call: local securecallfunction = securecallfunction or function(func, ...) return func(...) end. This eliminates the "attempt to call upvalue 'securecallfunction' (a nil value)" crash that triggered the 58 errors.

Copilot AI commented Mar 1, 2026

Copy link
Copy Markdown
Author

@copilot apply changes based on the comments in this thread

Both changes from that review thread were already applied in 9ed8493:

  • Sound "None" sentinel changed to [[Interface\Quiet.ogg]] so Fetch returns a non-nil string and PlaySoundFile receives a valid string argument
  • securecallfunction fallback added to CallbackHandler-1.0 to fix the nil-call crash on 3.3.5a

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +10 to +11
-- securecallfunction does not exist in WoW 3.3.5a; fall back to a direct call
local securecallfunction = securecallfunction or function(func, ...) return func(...) end

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fallback implementation function(func, ...) return func(...) end changes CallbackHandler behavior vs. the intended securecallfunction: any error thrown by a callback will now propagate and abort dispatching subsequent handlers (and can break the caller). To preserve CallbackHandler’s error-isolation semantics on 3.3.5a, the fallback should wrap the call in pcall/xpcall and report errors via geterrorhandler() (or equivalent) instead of raising them directly.

Suggested change
-- securecallfunction does not exist in WoW 3.3.5a; fall back to a direct call
local securecallfunction = securecallfunction or function(func, ...) return func(...) end
local xpcall = xpcall
local geterrorhandler = geterrorhandler
-- securecallfunction does not exist in WoW 3.3.5a; provide a fallback that preserves error-isolation semantics
local securecallfunction = securecallfunction or function(func, ...)
if geterrorhandler then
local errorhandler = geterrorhandler()
if errorhandler then
xpcall(func, errorhandler, ...)
return
end
end
return func(...)
end

Copilot uses AI. Check for mistakes.
@ayanimea

ayanimea commented Mar 1, 2026

Copy link
Copy Markdown
Owner

@copilot apply changes based on the comments in this thread

…rror isolation

Co-authored-by: ayanimea <13433370+ayanimea@users.noreply.github.com>

Copilot AI commented Mar 1, 2026

Copy link
Copy Markdown
Author

@copilot apply changes based on the comments in this thread

Done in b8d39c5. The securecallfunction fallback now uses xpcall/geterrorhandler to preserve error-isolation semantics: callback errors are caught and routed to geterrorhandler() rather than propagating and aborting dispatch of subsequent handlers.

@ayanimea

ayanimea commented Mar 1, 2026

Copy link
Copy Markdown
Owner

Message: Interface\AddOns\ZygorGuidesViewer\MapCoords.lua:21: attempt to index global 'Enum' (a nil value)
Time: 03/01/26 17:53:42
Count: 1
Stack: [C]: ?
Interface\AddOns\ZygorGuidesViewer\MapCoords.lua:21: in main chunk

Locals: ZGV =

{
STEPMARGIN_Y = 4
STEPMARGIN_X = 3
UPDATE_FACTION_Faction = defined @interface\AddOns\ZygorGuidesViewer\Faction.lua:119
RaceClassMatch = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:2457
modules =
{
}
CancelTimer = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceTimer-3.0\AceTimer-3.0.lua:166
completedQuests =
{
}
OnGuidesLoaded = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:3175
GoalOnLeave = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:2908
CacheReputations = defined @interface\AddOns\ZygorGuidesViewer\Faction.lua:39
stepframes =
{
}
SetIconAlpha = defined @interface\AddOns\ZygorGuidesViewer\Options.lua:1180
CreateCartographerWaypoints = defined @interface\AddOns\ZygorGuidesViewer\Waypoints.lua:463
SetDefaultModulePrototype = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:440
QUEST_PROGRESS = defined @interface\AddOns\ZygorGuidesViewer\QuestAutoAccept.lua:161
Options_SetupBlizConfig = defined @interface\AddOns\ZygorGuidesViewer\Options.lua:1131
QUEST_COMPLETE = defined @interface\AddOns\ZygorGuidesViewer\QuestAutoAccept.lua:180
IsEnabled = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceAddon-3.0\AceAddon-3.0.lua:482
QuestTracking_ResetDailies = defined @interface\AddOns\ZygorGuidesViewer\QuestTracking.lua:203
ScheduleTimer = defined @interface\AddOns\DBM-Core\Libs\Ace3\AceTimer-3.0\AceTimer-3.0.lua:113
registered_groups =
{
}
RegisterMessage = defined @interface\AddOns\LibSharedMedia-3.0\CallbackHandler-1.0\CallbackHandler-1.0.lua:82
UnregisterMessage = defined @interface\AddOns\LibSharedMedia-3.0\CallbackHandler-1.0\CallbackHandler-1.0.lua:145
ParseGuides = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:3198
GetTranslatedNPC = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:3738
OpenOptions = defined @interface\AddOns\ZygorGuidesViewer\Options.lua:1259
SetFrameScale = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:1998
IsVisible = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:2426
IsNoteHidden = defined @interface\AddOns\ZygorGuidesViewer\Waypoints.lua:430
Rep_Going = defined @interface\AddOns\ZygorGuidesViewer\Faction.lua:101
ConnectWaypointAddon = defined @interface\AddOns\ZygorGuidesViewer\Waypoints.lua:21
MIN_STEP_HEIGHT = 15
RaceClassMatchList = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:2478
Foglight =
{
}
PLAYER_CONTROL_GAINED = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:2657
registeredmapspotsets =
{
}
STEP_SPACING = 2
AlignFrame = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:2022
FormatDistance = defined @interface\AddOns\ZygorGuidesViewer\Pointer.lua:451
Pointer =
{
}
ResizeFrame = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:2337
BFL =
{
}
RevChains =
{
}
GetItemData = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:3698
GoalProto_mt =
{
}
GetMapZoneFile = defined @interface\AddOns\ZygorGuidesViewer\Waypoints.lua:608
OnInitialize = defined @interface\AddOns\ZygorGuidesViewer\ZygorGuidesViewer.lua:101
UnregisterAllEvents = defined @interface\AddOns\LibSharedMedia-3.0\CallbackHandler-1.0\CallbackHandler-
@copilot

Copilot AI commented Mar 1, 2026

Copy link
Copy Markdown
Author

Message: Interface\AddOns\ZygorGuidesViewer\MapCoords.lua:21: attempt to index global 'Enum' (a nil value)
Time: 03/01/26 17:53:42
Count: 1
...

This error originates in ZygorGuidesViewer\MapCoords.lua:21, not in LibSharedMedia-3.0. The Enum global is a retail WoW API that doesn't exist on the 3.3.5a client — ZygorGuidesViewer itself needs to be patched for WotLK 3.3.5a compatibility. This is outside the scope of this PR.

@ayanimea

ayanimea commented Mar 1, 2026

Copy link
Copy Markdown
Owner

@copilot This error log finishes by "UnregisterAllEvents = defined @interface\AddOns\LibSharedMedia-3.0\CallbackHandler-1.0\CallbackHandler-"
Why is that?

Copilot AI commented Mar 1, 2026

Copy link
Copy Markdown
Author

@copilot This error log finishes by "UnregisterAllEvents = defined @interface\AddOns\LibSharedMedia-3.0\CallbackHandler-1.0\CallbackHandler-"
Why is that?

The log is simply truncated there — the WoW error viewer has a display length limit and cut off the full path CallbackHandler-1.0.lua. UnregisterAllEvents is a standard method that CallbackHandler mixes into any object that embeds it (you can see RegisterMessage/UnregisterMessage listed just above it for the same reason). There's no issue here — it's a display artifact, not an error in our code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adapt LibSharedMedia for WoW 3.3.5a WOTLK version

3 participants