-
Posts
2,943 -
Joined
-
Last visited
Cashlaz's Achievements
Single Status Update
-
Duck Survival [+3 Cheats] ad
Context
Duck Survival = Unity IL2CPP + ToLua. Ad logic lives in Lua (
VipCtrl,AdManager,EventSystem).The native tweak (
DuckSpend) hookslua_pcall/DecodeDataand injectsinject.luainto the live Lua state. Once lobby modules exist, we monkey-patch their globals.How the game normally grants the reward
Typical flow:
-
UI calls
AdManager.ShowAd(reasonId, adOrPayId). -
If ad-free is set (
VipCtrl.GetAddedAdFreeFlag()), the game skips the video and firesEventDefine.OnFinishAd. -
Listeners on
OnFinishAd(shop, daily reward, etc.) grant the reward usingreasonId/adOrPayId.
So the reward is keyed off the internal Lua event
OnFinishAd, not directly off the native SDK callback.What we do (two layers)
Source:
tweak/DuckSpend/inject.lua, gated byon('ads')→_G.__DuckT.ads.1. Fake VIP / ad-free
function VipCtrl.GetAddedAdFreeFlag()if on('ads') then return true endreturn origVip()endAny code that checks “is ad-free?” before showing an ad gets
trueand often never reaches the SDK.2. Short-circuit
ShowAd(main reward path)function AdManager.ShowAd(reasonId, adOrPayId)if not on('ads') thenreturn origShow(reasonId, adOrPayId)endlocal params = { r = reasonId, i = adOrPayId }EventSystem:Trigger(EventDefine.OnFinishAd, params)if AdManager.SendAdsEvent then pcall(AdManager.SendAdsEvent, 3, 1) endreturn -- do not call original ShowAd → no videoend-
skip original
ShowAd→ no native video; -
immediately
Trigger(OnFinishAd, { r = reasonId, i = adOrPayId })→ same listeners as a real completion; -
optional
SendAdsEvent(3, 1)— analytics “success” (best-effort, not required for the grant).
{ r, i }matches the payload the game’sOnFinishAdhandlers expect (same as the vanilla ad-free path).Why the reward still arrives
We emulate a successful completion at the game’s Lua layer, not a fake response from the ad network. Client Lua treats the watch as done and runs its normal reward flow.
Details
Point Meaning Idempotency_G.__DuckAdVip/__DuckAdShowwrap onceToggleon('ads') == false→ full original pathTimingwrap installs afterVipCtrl/AdManagerexist in lobby (retry via pcall inject)Serverif a reward is validated server-side via an ad token, this may fail; this path is client event-drivenBottom line: skip = don’t call the SDK + fire
OnFinishAdwith the same ids, plus the VIP flag as an extra short-circuit for code that checks ad-free beforeShowAd. -
UI calls