nccgs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/nccgs-accessibility-specialist.md +26 -0
- package/.claude/agents/nccgs-adversarial-reviewer.md +26 -0
- package/.claude/agents/nccgs-ai-programmer.md +26 -0
- package/.claude/agents/nccgs-analytics-engineer.md +26 -0
- package/.claude/agents/nccgs-art-direction-lead.md +26 -0
- package/.claude/agents/nccgs-audio-direction-lead.md +26 -0
- package/.claude/agents/nccgs-creative-director.md +26 -0
- package/.claude/agents/nccgs-documentation-manager.md +26 -0
- package/.claude/agents/nccgs-economy-designer.md +26 -0
- package/.claude/agents/nccgs-engine-programmer.md +26 -0
- package/.claude/agents/nccgs-game-design-lead.md +26 -0
- package/.claude/agents/nccgs-game-designer.md +26 -0
- package/.claude/agents/nccgs-gameplay-programmer.md +26 -0
- package/.claude/agents/nccgs-level-designer.md +26 -0
- package/.claude/agents/nccgs-live-ops-designer.md +26 -0
- package/.claude/agents/nccgs-localization-lead.md +26 -0
- package/.claude/agents/nccgs-narrative-lead.md +26 -0
- package/.claude/agents/nccgs-network-programmer.md +26 -0
- package/.claude/agents/nccgs-performance-analyst.md +26 -0
- package/.claude/agents/nccgs-producer.md +26 -0
- package/.claude/agents/nccgs-production-coordinator.md +23 -0
- package/.claude/agents/nccgs-programming-lead.md +26 -0
- package/.claude/agents/nccgs-prototyper.md +26 -0
- package/.claude/agents/nccgs-qa-engineer.md +26 -0
- package/.claude/agents/nccgs-qa-lead.md +26 -0
- package/.claude/agents/nccgs-release-engineer.md +26 -0
- package/.claude/agents/nccgs-release-lead.md +26 -0
- package/.claude/agents/nccgs-security-engineer.md +26 -0
- package/.claude/agents/nccgs-sound-designer.md +26 -0
- package/.claude/agents/nccgs-systems-designer.md +26 -0
- package/.claude/agents/nccgs-technical-architect.md +26 -0
- package/.claude/agents/nccgs-technical-artist.md +26 -0
- package/.claude/agents/nccgs-technical-director.md +26 -0
- package/.claude/agents/nccgs-tools-programmer.md +26 -0
- package/.claude/agents/nccgs-ui-programmer.md +26 -0
- package/.claude/agents/nccgs-unity-build-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-content-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-implementer.md +26 -0
- package/.claude/agents/nccgs-unity-rendering-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-systems-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-ui-specialist.md +26 -0
- package/.claude/agents/nccgs-ux-designer.md +26 -0
- package/.claude/agents/nccgs-verification-engineer.md +26 -0
- package/.claude/agents/nccgs-world-builder.md +26 -0
- package/.claude/agents/nccgs-writer.md +26 -0
- package/.claude/nccgs/THIRD_PARTY_NOTICES.md +13 -0
- package/.claude/nccgs/VERSION +1 -0
- package/.claude/nccgs/constitution.md +131 -0
- package/.claude/nccgs/hooks/agent-audit.mjs +10 -0
- package/.claude/nccgs/hooks/common.mjs +41 -0
- package/.claude/nccgs/hooks/post-compact.mjs +1 -0
- package/.claude/nccgs/hooks/pre-compact.mjs +8 -0
- package/.claude/nccgs/hooks/protect-git.mjs +22 -0
- package/.claude/nccgs/hooks/protect-write.mjs +17 -0
- package/.claude/nccgs/hooks/session-start.mjs +15 -0
- package/.claude/nccgs/hooks/session-stop.mjs +7 -0
- package/.claude/nccgs/protocols/agent-contract.md +34 -0
- package/.claude/nccgs/protocols/context-packets.md +13 -0
- package/.claude/nccgs/protocols/evidence.md +15 -0
- package/.claude/nccgs/protocols/model-routing.md +22 -0
- package/.claude/nccgs/protocols/orchestration.md +26 -0
- package/.claude/nccgs/protocols/unity-boundary.md +11 -0
- package/.claude/nccgs/settings.fragment.json +77 -0
- package/.claude/nccgs/studio.json +347 -0
- package/.claude/nccgs/tools/configure-models.mjs +39 -0
- package/.claude/nccgs/unity-skills-manifest.json +727 -0
- package/.claude/nccgs/workflow-catalog.json +317 -0
- package/.claude/rules/nccgs-canonical-docs.md +19 -0
- package/.claude/rules/nccgs-editor-tools.md +12 -0
- package/.claude/rules/nccgs-localization.md +12 -0
- package/.claude/rules/nccgs-networking.md +13 -0
- package/.claude/rules/nccgs-performance.md +14 -0
- package/.claude/rules/nccgs-rendering.md +16 -0
- package/.claude/rules/nccgs-security.md +13 -0
- package/.claude/rules/nccgs-tests.md +18 -0
- package/.claude/rules/nccgs-ui.md +14 -0
- package/.claude/rules/nccgs-unity-assets.md +21 -0
- package/.claude/rules/nccgs-unity-code.md +22 -0
- package/.claude/skills/accessibility-review/SKILL.md +14 -0
- package/.claude/skills/architecture-decision/SKILL.md +14 -0
- package/.claude/skills/asset-audit/SKILL.md +14 -0
- package/.claude/skills/audit/SKILL.md +16 -0
- package/.claude/skills/audit/references/dimensions.md +46 -0
- package/.claude/skills/balance-review/SKILL.md +14 -0
- package/.claude/skills/bug-triage/SKILL.md +14 -0
- package/.claude/skills/build-live-game/SKILL.md +317 -0
- package/.claude/skills/build-live-game/references/achievements.md +779 -0
- package/.claude/skills/build-live-game/references/apis.md +280 -0
- package/.claude/skills/build-live-game/references/authentication.md +437 -0
- package/.claude/skills/build-live-game/references/battlepass.md +860 -0
- package/.claude/skills/build-live-game/references/cloud-code.md +563 -0
- package/.claude/skills/build-live-game/references/cloud-save.md +474 -0
- package/.claude/skills/build-live-game/references/deployment.md +216 -0
- package/.claude/skills/build-live-game/references/player-account.md +813 -0
- package/.claude/skills/build-live-game/references/remote-config.md +96 -0
- package/.claude/skills/build-live-game/references/tooling.md +431 -0
- package/.claude/skills/closure/SKILL.md +14 -0
- package/.claude/skills/code-review/SKILL.md +14 -0
- package/.claude/skills/compatibility-review/SKILL.md +14 -0
- package/.claude/skills/context-pack/SKILL.md +14 -0
- package/.claude/skills/dependency-review/SKILL.md +14 -0
- package/.claude/skills/design/SKILL.md +20 -0
- package/.claude/skills/design-review/SKILL.md +14 -0
- package/.claude/skills/evidence-review/SKILL.md +14 -0
- package/.claude/skills/hotfix/SKILL.md +14 -0
- package/.claude/skills/implement-in-app-purchases/README.md +233 -0
- package/.claude/skills/implement-in-app-purchases/SKILL.md +158 -0
- package/.claude/skills/implement-in-app-purchases/references/api-notes.md +562 -0
- package/.claude/skills/implement-in-app-purchases/references/codeless-catalog.md +331 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-adapty.md +268 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-essentialkit.md +239 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-revenuecat.md +275 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-unipay.md +145 -0
- package/.claude/skills/implement-in-app-purchases/references/migration-v4-to-v5.md +204 -0
- package/.claude/skills/implement-in-app-purchases/references/path-add-iap-to-new-project.md +198 -0
- package/.claude/skills/implement-in-app-purchases/references/path-convert-native-google-billing.md +356 -0
- package/.claude/skills/implement-in-app-purchases/references/path-convert-native-storekit.md +446 -0
- package/.claude/skills/implement-in-app-purchases/references/path-implement-iap-d2c.md +680 -0
- package/.claude/skills/implement-in-app-purchases/references/platform-notes.md +204 -0
- package/.claude/skills/implement-in-app-purchases/references/pre-check.md +205 -0
- package/.claude/skills/incident-recovery/SKILL.md +14 -0
- package/.claude/skills/initialize-ai-navigation/SKILL.md +95 -0
- package/.claude/skills/initialize-ai-navigation/references/navigation-system.md +794 -0
- package/.claude/skills/levelplay-unity-integration/CHANGELOG.md +57 -0
- package/.claude/skills/levelplay-unity-integration/README.md +74 -0
- package/.claude/skills/levelplay-unity-integration/SKILL.md +1126 -0
- package/.claude/skills/levelplay-unity-integration/references/banner-api.md +920 -0
- package/.claude/skills/levelplay-unity-integration/references/best-practices.md +536 -0
- package/.claude/skills/levelplay-unity-integration/references/ilrd-api.md +337 -0
- package/.claude/skills/levelplay-unity-integration/references/initialization-api.md +630 -0
- package/.claude/skills/levelplay-unity-integration/references/interstitial-api.md +899 -0
- package/.claude/skills/levelplay-unity-integration/references/ios-setup.md +491 -0
- package/.claude/skills/levelplay-unity-integration/references/migration-sdk-9.md +666 -0
- package/.claude/skills/levelplay-unity-integration/references/privacy-settings.md +608 -0
- package/.claude/skills/levelplay-unity-integration/references/rewarded-api.md +902 -0
- package/.claude/skills/localization/SKILL.md +135 -0
- package/.claude/skills/localization/references/api-notes.md +76 -0
- package/.claude/skills/localization/resources/L10nBatchProcessor.cs +69 -0
- package/.claude/skills/localization/resources/LocalizedFontAsset.cs +18 -0
- package/.claude/skills/localize-game/SKILL.md +14 -0
- package/.claude/skills/migrate-project/SKILL.md +21 -0
- package/.claude/skills/migrate-project/references/procedure.md +63 -0
- package/.claude/skills/milestone-review/SKILL.md +14 -0
- package/.claude/skills/new-unity-project/SKILL.md +179 -0
- package/.claude/skills/optimize-audio/SKILL.md +199 -0
- package/.claude/skills/optimize-audio/resources/audio-import-api.md +146 -0
- package/.claude/skills/optimize-audio/resources/platform-settings.md +48 -0
- package/.claude/skills/optimize-text-mesh-pro/SKILL.md +182 -0
- package/.claude/skills/optimize-web/SKILL.md +393 -0
- package/.claude/skills/optimize-web/resources/WebOptimizer.cs +21 -0
- package/.claude/skills/optimize-web/resources/toktx-examples.sh +11 -0
- package/.claude/skills/performance-audit/SKILL.md +14 -0
- package/.claude/skills/physics-3d-collision/SKILL.md +442 -0
- package/.claude/skills/physics-3d-collision/references/troubleshooting.md +41 -0
- package/.claude/skills/physics-3d-collision/resources/CollisionDebugger.cs +33 -0
- package/.claude/skills/plan-feature/SKILL.md +14 -0
- package/.claude/skills/playtest/SKILL.md +14 -0
- package/.claude/skills/project-stage/SKILL.md +14 -0
- package/.claude/skills/prototype-feature/SKILL.md +14 -0
- package/.claude/skills/qa-plan/SKILL.md +14 -0
- package/.claude/skills/release/SKILL.md +18 -0
- package/.claude/skills/release-readiness/SKILL.md +14 -0
- package/.claude/skills/retrospective/SKILL.md +14 -0
- package/.claude/skills/review/SKILL.md +16 -0
- package/.claude/skills/security-audit/SKILL.md +14 -0
- package/.claude/skills/setup-multiplayer-services/SKILL.md +39 -0
- package/.claude/skills/setup-multiplayer-services/references/dgs-entrypoint.md +79 -0
- package/.claude/skills/setup-multiplayer-services/references/entrypoints.md +213 -0
- package/.claude/skills/setup-multiplayer-services/references/examples.md +33 -0
- package/.claude/skills/setup-multiplayer-services/references/implementation-fit.md +30 -0
- package/.claude/skills/setup-multiplayer-services/references/underlying-services.md +11 -0
- package/.claude/skills/setup-multiplayer-services/references/workflows-prerequisites.md +17 -0
- package/.claude/skills/setup-vivox-voice-chat/SKILL.md +118 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/.env.example +6 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/README.md +101 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/promptfooconfig.yaml +32 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/tests/init-and-login.yaml +76 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/tests/text-chat.yaml +65 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/tests/voice-channels.yaml +74 -0
- package/.claude/skills/setup-vivox-voice-chat/references/events-and-participants.md +79 -0
- package/.claude/skills/setup-vivox-voice-chat/references/init-and-login.md +92 -0
- package/.claude/skills/setup-vivox-voice-chat/references/text-chat.md +93 -0
- package/.claude/skills/setup-vivox-voice-chat/references/troubleshooting.md +47 -0
- package/.claude/skills/setup-vivox-voice-chat/references/voice-channels.md +90 -0
- package/.claude/skills/shader-graph-create-custom-node/SKILL.md +25 -0
- package/.claude/skills/shader-graph-create-custom-node/resources/all_hints.hlsl +182 -0
- package/.claude/skills/sprint-plan/SKILL.md +14 -0
- package/.claude/skills/sprite-editor/SKILL.md +66 -0
- package/.claude/skills/sprite-editor/references/api_reference.md +151 -0
- package/.claude/skills/sprite-editor/references/background.md +112 -0
- package/.claude/skills/sprite-editor/references/templates.md +72 -0
- package/.claude/skills/sprite-editor/scripts/AutomaticSliceTexture.cs +40 -0
- package/.claude/skills/sprite-editor/scripts/GenerateNewSpriteRects.cs +200 -0
- package/.claude/skills/sprite-editor/scripts/GetTextureSourceImageSize.cs +32 -0
- package/.claude/skills/sprite-editor/scripts/GetTextureToSlice.cs +55 -0
- package/.claude/skills/sprite-editor/scripts/GridSliceTexture.cs +40 -0
- package/.claude/skills/sprite-editor/scripts/IsometricSliceTexture.cs +141 -0
- package/.claude/skills/sprite-editor/scripts/README.md +134 -0
- package/.claude/skills/sprite-editor/scripts/SetPivotExample.cs +58 -0
- package/.claude/skills/sprite-editor/scripts/SpriteToPng.cs +88 -0
- package/.claude/skills/status/SKILL.md +16 -0
- package/.claude/skills/story-readiness/SKILL.md +14 -0
- package/.claude/skills/test/SKILL.md +16 -0
- package/.claude/skills/ui/SKILL.md +142 -0
- package/.claude/skills/ui-imgui/SKILL.md +186 -0
- package/.claude/skills/ui-imgui/references/gui-elements.md +156 -0
- package/.claude/skills/ui-imgui/references/templates.md +141 -0
- package/.claude/skills/ui-review/SKILL.md +14 -0
- package/.claude/skills/ui-ugui/SKILL.md +282 -0
- package/.claude/skills/ui-ugui/references/scrollview-setup.md +29 -0
- package/.claude/skills/ui-uitk/SKILL.md +235 -0
- package/.claude/skills/ui-uitk/references/common-issues.md +74 -0
- package/.claude/skills/ui-uitk/references/custom-elements.md +241 -0
- package/.claude/skills/ui-uitk/references/painter2d.md +282 -0
- package/.claude/skills/ui-uitk/references/pointermanipulator-guide.md +94 -0
- package/.claude/skills/ui-uitk/references/svg-icons.md +136 -0
- package/.claude/skills/ui-uitk/references/ui-runtime-binding.md +234 -0
- package/.claude/skills/ui-uitk/references/uss-guide.md +138 -0
- package/.claude/skills/unity-cli/CHANGELOG.md +233 -0
- package/.claude/skills/unity-cli/SECURITY.md +22 -0
- package/.claude/skills/unity-cli/SKILL.md +414 -0
- package/.claude/skills/unity-cli/references/auth-license-cloud.md +146 -0
- package/.claude/skills/unity-cli/references/build-run-test.md +349 -0
- package/.claude/skills/unity-cli/references/collaboration.md +472 -0
- package/.claude/skills/unity-cli/references/config-hub.md +103 -0
- package/.claude/skills/unity-cli/references/diagnostics-maintenance.md +326 -0
- package/.claude/skills/unity-cli/references/editors-install.md +327 -0
- package/.claude/skills/unity-cli/references/integration-advanced.md +472 -0
- package/.claude/skills/unity-cli/references/projects-templates.md +574 -0
- package/.claude/skills/unity-package-management/SKILL.md +304 -0
- package/.claude/skills/unity-package-management/references/select-packages.md +108 -0
- package/.claude/skills/urp-postprocessing/SKILL.md +188 -0
- package/.claude/skills/urp-postprocessing/references/code-templates.md +119 -0
- package/.claude/skills/urp-postprocessing/references/effect-reference.md +86 -0
- package/.claude/skills/validate-urp-render-graph-renderer-feature/SKILL.md +269 -0
- package/.claude/skills/work/SKILL.md +36 -0
- package/.claude/skills/work/references/classification.md +41 -0
- package/.claude/skills/work/references/closure.md +50 -0
- package/.claude/skills/work/references/feature-contracts.md +32 -0
- package/.claude/skills/work/references/verification.md +26 -0
- package/CLAUDE.md +6 -0
- package/LICENSE +21 -0
- package/README.md +162 -0
- package/THIRD_PARTY_NOTICES.md +23 -0
- package/UPGRADING.md +32 -0
- package/VERSION +1 -0
- package/docs/ARCHITECTURE.md +73 -0
- package/docs/HUONG-DAN-MIGRATE-VA-SU-DUNG.md +324 -0
- package/docs/MIGRATION-MATRIX.md +23 -0
- package/docs/PROJECT-POLICY.md +67 -0
- package/docs/WORKFLOWS.md +61 -0
- package/package-assets/setup-vivox-voice-chat-evals.gitignore +7 -0
- package/package.json +41 -0
- package/scaffold/.nccgs/bugs/.gitkeep +1 -0
- package/scaffold/.nccgs/closures/.gitkeep +1 -0
- package/scaffold/.nccgs/context/.gitkeep +1 -0
- package/scaffold/.nccgs/decisions/.gitkeep +1 -0
- package/scaffold/.nccgs/evidence/.gitkeep +1 -0
- package/scaffold/.nccgs/features/.gitkeep +1 -0
- package/scaffold/.nccgs/migrations/.gitkeep +1 -0
- package/scaffold/.nccgs/playtests/.gitkeep +1 -0
- package/scaffold/.nccgs/project.yaml +103 -0
- package/scaffold/.nccgs/requirements.yaml +10 -0
- package/scaffold/.nccgs/reviews/.gitkeep +1 -0
- package/scaffold/.nccgs/state.md +40 -0
- package/scaffold/.nccgs/templates/agent-handoff.md +25 -0
- package/scaffold/.nccgs/templates/architecture-decision.md +27 -0
- package/scaffold/.nccgs/templates/closure-record.md +51 -0
- package/scaffold/.nccgs/templates/context-packet.yaml +17 -0
- package/scaffold/.nccgs/templates/evidence-record.md +23 -0
- package/scaffold/.nccgs/templates/feature-contract.md +35 -0
- package/scaffold/.nccgs/templates/migration-plan.md +40 -0
- package/scaffold/.nccgs/templates/waiver.md +11 -0
- package/scripts/cli.mjs +56 -0
- package/scripts/install.mjs +267 -0
- package/scripts/sync-unity-skills.mjs +126 -0
- package/scripts/validate.mjs +205 -0
- package/tests/framework.test.mjs +121 -0
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
# Rewarded Ads API Reference
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- [Overview](#overview)
|
|
5
|
+
- [Key Characteristics](#key-characteristics)
|
|
6
|
+
- [Implementation Pattern](#implementation-pattern)
|
|
7
|
+
- [API Reference](#api-reference)
|
|
8
|
+
- [Data Types](#data-types)
|
|
9
|
+
- [Best Practices](#best-practices)
|
|
10
|
+
- [Common Issues](#common-issues)
|
|
11
|
+
- [Testing Checklist](#testing-checklist)
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
Rewarded ads are video ads that users choose to watch in exchange for in-app rewards. They're the highest-earning ad format and provide excellent user experience when implemented correctly.
|
|
16
|
+
|
|
17
|
+
## Key Characteristics
|
|
18
|
+
|
|
19
|
+
- **User-initiated**: Users explicitly choose to watch
|
|
20
|
+
- **Win-win**: Users get valuable rewards, developers get revenue
|
|
21
|
+
- **Best for**: Extra lives, hints, currency, power-ups, skipping wait times
|
|
22
|
+
|
|
23
|
+
## Implementation Pattern
|
|
24
|
+
|
|
25
|
+
### Basic Rewarded Ad Implementation
|
|
26
|
+
|
|
27
|
+
```csharp
|
|
28
|
+
using UnityEngine;
|
|
29
|
+
using Unity.Services.LevelPlay;
|
|
30
|
+
|
|
31
|
+
public class RewardedAdManager : MonoBehaviour
|
|
32
|
+
{
|
|
33
|
+
private LevelPlayRewardedAd rewardedAd;
|
|
34
|
+
private string adUnitId = "YOUR_REWARDED_AD_UNIT_ID";
|
|
35
|
+
|
|
36
|
+
void Start()
|
|
37
|
+
{
|
|
38
|
+
// Create the rewarded ad object and register event listeners.
|
|
39
|
+
// Do not call LoadAd() here — load is triggered explicitly by a publisher-controlled
|
|
40
|
+
// action (e.g. a button press, scene entry, or a point in gameplay where the ad
|
|
41
|
+
// should be available). See LoadAd() below.
|
|
42
|
+
rewardedAd = new LevelPlayRewardedAd(adUnitId);
|
|
43
|
+
|
|
44
|
+
// Register event listeners
|
|
45
|
+
rewardedAd.OnAdLoaded += OnAdLoaded;
|
|
46
|
+
rewardedAd.OnAdLoadFailed += OnAdLoadFailed;
|
|
47
|
+
rewardedAd.OnAdDisplayed += OnAdDisplayed;
|
|
48
|
+
rewardedAd.OnAdDisplayFailed += OnAdDisplayFailed;
|
|
49
|
+
rewardedAd.OnAdRewarded += OnAdRewarded;
|
|
50
|
+
rewardedAd.OnAdClosed += OnAdClosed;
|
|
51
|
+
rewardedAd.OnAdClicked += OnAdClicked;
|
|
52
|
+
rewardedAd.OnAdInfoChanged += OnAdInfoChanged; // Fires when the loaded ad updates after a new auction result
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
void OnDestroy()
|
|
56
|
+
{
|
|
57
|
+
// Unregister event listeners
|
|
58
|
+
if (rewardedAd != null)
|
|
59
|
+
{
|
|
60
|
+
rewardedAd.OnAdLoaded -= OnAdLoaded;
|
|
61
|
+
rewardedAd.OnAdLoadFailed -= OnAdLoadFailed;
|
|
62
|
+
rewardedAd.OnAdDisplayed -= OnAdDisplayed;
|
|
63
|
+
rewardedAd.OnAdDisplayFailed -= OnAdDisplayFailed;
|
|
64
|
+
rewardedAd.OnAdRewarded -= OnAdRewarded;
|
|
65
|
+
rewardedAd.OnAdClosed -= OnAdClosed;
|
|
66
|
+
rewardedAd.OnAdClicked -= OnAdClicked;
|
|
67
|
+
rewardedAd.OnAdInfoChanged -= OnAdInfoChanged;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Call LoadAd() from a publisher-controlled trigger (e.g. a button or scene entry).
|
|
72
|
+
// The SDK does not auto-load, so LoadAd() must be called explicitly.
|
|
73
|
+
public void LoadAd()
|
|
74
|
+
{
|
|
75
|
+
Debug.Log("Loading rewarded ad...");
|
|
76
|
+
rewardedAd.LoadAd();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public void ShowAd()
|
|
80
|
+
{
|
|
81
|
+
if (rewardedAd.IsAdReady())
|
|
82
|
+
{
|
|
83
|
+
Debug.Log("Showing rewarded ad");
|
|
84
|
+
rewardedAd.ShowAd();
|
|
85
|
+
}
|
|
86
|
+
else
|
|
87
|
+
{
|
|
88
|
+
Debug.LogWarning("Rewarded ad is not ready yet");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Event Callbacks
|
|
93
|
+
private void OnAdLoaded(LevelPlayAdInfo adInfo)
|
|
94
|
+
{
|
|
95
|
+
Debug.Log("Rewarded ad loaded successfully");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private void OnAdLoadFailed(LevelPlayAdError error)
|
|
99
|
+
{
|
|
100
|
+
Debug.LogWarning($"Rewarded ad failed to load: {error.ErrorMessage}");
|
|
101
|
+
// Retry loading after a delay
|
|
102
|
+
Invoke(nameof(LoadAd), 30f);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private void OnAdDisplayed(LevelPlayAdInfo adInfo)
|
|
106
|
+
{
|
|
107
|
+
Debug.Log("Rewarded ad displayed");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private void OnAdDisplayFailed(LevelPlayAdInfo adInfo, LevelPlayAdError error)
|
|
111
|
+
{
|
|
112
|
+
Debug.LogError($"Rewarded ad failed to display: {error.ErrorMessage}");
|
|
113
|
+
// Load a new ad
|
|
114
|
+
LoadAd();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private void OnAdRewarded(LevelPlayAdInfo adInfo, LevelPlayReward reward)
|
|
118
|
+
{
|
|
119
|
+
Debug.Log($"User earned reward: {reward.Amount} {reward.Name}");
|
|
120
|
+
// Grant the reward to the user
|
|
121
|
+
GrantReward(reward);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private void OnAdClosed(LevelPlayAdInfo adInfo)
|
|
125
|
+
{
|
|
126
|
+
Debug.Log("Rewarded ad closed");
|
|
127
|
+
// LoadAd() is not called here automatically. If your game preloads rewarded ads
|
|
128
|
+
// eagerly (so one is always ready), call LoadAd() here. If load is triggered by
|
|
129
|
+
// a player action, wait for that action instead.
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private void OnAdClicked(LevelPlayAdInfo adInfo)
|
|
133
|
+
{
|
|
134
|
+
Debug.Log("Rewarded ad clicked");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private void OnAdInfoChanged(LevelPlayAdInfo adInfo)
|
|
138
|
+
{
|
|
139
|
+
// Optional: log or update analytics with the latest revenue estimate
|
|
140
|
+
Debug.Log($"Rewarded ad info changed - network: {adInfo.AdNetwork}, revenue: ${adInfo.Revenue}");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private void GrantReward(LevelPlayReward reward)
|
|
144
|
+
{
|
|
145
|
+
// Implement your reward logic here
|
|
146
|
+
Debug.Log($"Granting {reward.Amount} {reward.Name} to the user");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Advanced: Multiple Rewarded Ad Placements
|
|
152
|
+
|
|
153
|
+
```csharp
|
|
154
|
+
using UnityEngine;
|
|
155
|
+
using Unity.Services.LevelPlay;
|
|
156
|
+
using System.Collections.Generic;
|
|
157
|
+
|
|
158
|
+
public class MultiPlacementRewardedAdManager : MonoBehaviour
|
|
159
|
+
{
|
|
160
|
+
// Single ad unit ID, multiple placements
|
|
161
|
+
private string adUnitId = "YOUR_REWARDED_AD_UNIT_ID";
|
|
162
|
+
private LevelPlayRewardedAd rewardedAd;
|
|
163
|
+
|
|
164
|
+
// Track which placement is currently being shown
|
|
165
|
+
private string currentPlacement;
|
|
166
|
+
|
|
167
|
+
void Start()
|
|
168
|
+
{
|
|
169
|
+
// Create single rewarded ad object
|
|
170
|
+
rewardedAd = new LevelPlayRewardedAd(adUnitId);
|
|
171
|
+
|
|
172
|
+
// Register callbacks
|
|
173
|
+
rewardedAd.OnAdLoaded += OnAdLoaded;
|
|
174
|
+
rewardedAd.OnAdLoadFailed += OnAdLoadFailed;
|
|
175
|
+
rewardedAd.OnAdRewarded += OnAdRewarded;
|
|
176
|
+
rewardedAd.OnAdClosed += OnAdClosed;
|
|
177
|
+
rewardedAd.OnAdDisplayFailed += OnAdDisplayFailed;
|
|
178
|
+
|
|
179
|
+
// Load ad
|
|
180
|
+
rewardedAd.LoadAd();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
void OnDestroy()
|
|
184
|
+
{
|
|
185
|
+
if (rewardedAd != null)
|
|
186
|
+
{
|
|
187
|
+
rewardedAd.OnAdLoaded -= OnAdLoaded;
|
|
188
|
+
rewardedAd.OnAdLoadFailed -= OnAdLoadFailed;
|
|
189
|
+
rewardedAd.OnAdRewarded -= OnAdRewarded;
|
|
190
|
+
rewardedAd.OnAdClosed -= OnAdClosed;
|
|
191
|
+
rewardedAd.OnAdDisplayFailed -= OnAdDisplayFailed;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Public methods for different placements
|
|
196
|
+
public void ShowAdForHints()
|
|
197
|
+
{
|
|
198
|
+
ShowAdWithPlacement("hints");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
public void ShowAdForExtraLives()
|
|
202
|
+
{
|
|
203
|
+
ShowAdWithPlacement("extra_lives");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public void ShowAdForCoins()
|
|
207
|
+
{
|
|
208
|
+
ShowAdWithPlacement("bonus_coins");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private void ShowAdWithPlacement(string placementName)
|
|
212
|
+
{
|
|
213
|
+
if (rewardedAd.IsAdReady())
|
|
214
|
+
{
|
|
215
|
+
// Check if placement is capped
|
|
216
|
+
if (LevelPlayRewardedAd.IsPlacementCapped(placementName))
|
|
217
|
+
{
|
|
218
|
+
Debug.LogWarning($"Placement '{placementName}' is capped");
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
currentPlacement = placementName;
|
|
223
|
+
Debug.Log($"Showing rewarded ad with placement: {placementName}");
|
|
224
|
+
rewardedAd.ShowAd(placementName: placementName);
|
|
225
|
+
}
|
|
226
|
+
else
|
|
227
|
+
{
|
|
228
|
+
Debug.LogWarning("Rewarded ad is not ready");
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private void OnAdLoaded(LevelPlayAdInfo adInfo)
|
|
233
|
+
{
|
|
234
|
+
Debug.Log("Rewarded ad loaded");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private void OnAdLoadFailed(LevelPlayAdError error)
|
|
238
|
+
{
|
|
239
|
+
Debug.LogWarning($"Rewarded ad load failed: {error.ErrorMessage}");
|
|
240
|
+
Invoke(nameof(LoadAd), 30f);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private void OnAdRewarded(LevelPlayAdInfo adInfo, LevelPlayReward reward)
|
|
244
|
+
{
|
|
245
|
+
Debug.Log($"User rewarded: {reward.Amount} {reward.Name} for placement: {currentPlacement}");
|
|
246
|
+
|
|
247
|
+
// Grant placement-specific rewards
|
|
248
|
+
switch (currentPlacement)
|
|
249
|
+
{
|
|
250
|
+
case "hints":
|
|
251
|
+
GrantHints(reward);
|
|
252
|
+
break;
|
|
253
|
+
case "extra_lives":
|
|
254
|
+
GrantExtraLives(reward);
|
|
255
|
+
break;
|
|
256
|
+
case "bonus_coins":
|
|
257
|
+
GrantCoins(reward);
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
private void OnAdClosed(LevelPlayAdInfo adInfo)
|
|
263
|
+
{
|
|
264
|
+
Debug.Log("Rewarded ad closed");
|
|
265
|
+
currentPlacement = null;
|
|
266
|
+
LoadAd();
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private void OnAdDisplayFailed(LevelPlayAdInfo adInfo, LevelPlayAdError error)
|
|
270
|
+
{
|
|
271
|
+
Debug.LogError($"Rewarded ad display failed: {error.ErrorMessage}");
|
|
272
|
+
currentPlacement = null;
|
|
273
|
+
LoadAd();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
private void LoadAd()
|
|
277
|
+
{
|
|
278
|
+
if (rewardedAd != null)
|
|
279
|
+
{
|
|
280
|
+
rewardedAd.LoadAd();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Reward granting methods
|
|
285
|
+
private void GrantHints(LevelPlayReward reward)
|
|
286
|
+
{
|
|
287
|
+
Debug.Log("Granting hints to player");
|
|
288
|
+
// Your hint logic here
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
private void GrantExtraLives(LevelPlayReward reward)
|
|
292
|
+
{
|
|
293
|
+
Debug.Log("Granting extra lives to player");
|
|
294
|
+
// Your lives logic here
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private void GrantCoins(LevelPlayReward reward)
|
|
298
|
+
{
|
|
299
|
+
Debug.Log("Granting bonus coins to player");
|
|
300
|
+
// Your coins logic here
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## API Reference
|
|
306
|
+
|
|
307
|
+
### Constructor
|
|
308
|
+
|
|
309
|
+
#### `new LevelPlayRewardedAd(string adUnitId)`
|
|
310
|
+
Create a rewarded ad object.
|
|
311
|
+
|
|
312
|
+
**Parameters:**
|
|
313
|
+
- `adUnitId`: The ad unit identifier from your LevelPlay dashboard
|
|
314
|
+
|
|
315
|
+
**Returns:** `LevelPlayRewardedAd` object
|
|
316
|
+
|
|
317
|
+
**Usage:**
|
|
318
|
+
```csharp
|
|
319
|
+
LevelPlayRewardedAd rewardedAd = new LevelPlayRewardedAd("your_ad_unit_id");
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Important:** Call this only after `LevelPlay.Init()` has completed successfully (in the `OnInitSuccess` callback).
|
|
323
|
+
|
|
324
|
+
#### `new LevelPlayRewardedAd(string adUnitId, Config config)`
|
|
325
|
+
Create a rewarded ad object with custom configuration.
|
|
326
|
+
|
|
327
|
+
**Parameters:**
|
|
328
|
+
- `adUnitId`: The ad unit identifier
|
|
329
|
+
- `config`: Optional configuration object
|
|
330
|
+
|
|
331
|
+
**Usage:**
|
|
332
|
+
```csharp
|
|
333
|
+
var configBuilder = new LevelPlayRewardedAd.Config.Builder();
|
|
334
|
+
configBuilder.SetBidFloor(1.0); // Minimum bid price in USD
|
|
335
|
+
var config = configBuilder.Build();
|
|
336
|
+
LevelPlayRewardedAd rewardedAd = new LevelPlayRewardedAd("your_ad_unit_id", config);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Configuration Builder
|
|
340
|
+
|
|
341
|
+
#### `LevelPlayRewardedAd.Config.Builder()`
|
|
342
|
+
Create a configuration builder for rewarded ads.
|
|
343
|
+
|
|
344
|
+
**Returns:** `LevelPlayRewardedAd.Config.Builder` object
|
|
345
|
+
|
|
346
|
+
**Usage:**
|
|
347
|
+
```csharp
|
|
348
|
+
var configBuilder = new LevelPlayRewardedAd.Config.Builder();
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**Set minimum bid price:**
|
|
352
|
+
```csharp
|
|
353
|
+
configBuilder.SetBidFloor(1.0); // Minimum bid price in USD ($1.00 CPM)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**When to use:** Set a minimum bid price in USD for ad requests.
|
|
357
|
+
|
|
358
|
+
#### `Build()`
|
|
359
|
+
Build the configuration object.
|
|
360
|
+
|
|
361
|
+
**Returns:** `LevelPlayRewardedAd.Config` object
|
|
362
|
+
|
|
363
|
+
**Usage:**
|
|
364
|
+
```csharp
|
|
365
|
+
var config = configBuilder.Build();
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Core Methods
|
|
369
|
+
|
|
370
|
+
#### `LoadAd()`
|
|
371
|
+
Load a rewarded ad.
|
|
372
|
+
|
|
373
|
+
**Usage:**
|
|
374
|
+
```csharp
|
|
375
|
+
rewardedAd.LoadAd();
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
**When to call:**
|
|
379
|
+
- After SDK initialization completes
|
|
380
|
+
- After showing an ad (to load the next one)
|
|
381
|
+
- After a load or display failure
|
|
382
|
+
|
|
383
|
+
#### `ShowAd()`
|
|
384
|
+
Show the rewarded ad without a placement name.
|
|
385
|
+
|
|
386
|
+
**Usage:**
|
|
387
|
+
```csharp
|
|
388
|
+
if (rewardedAd.IsAdReady())
|
|
389
|
+
{
|
|
390
|
+
rewardedAd.ShowAd();
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
**Important:** Always check `IsAdReady()` before calling `ShowAd()`.
|
|
395
|
+
|
|
396
|
+
#### `ShowAd(placementName: string)`
|
|
397
|
+
Show the rewarded ad with a named placement for analytics tracking.
|
|
398
|
+
|
|
399
|
+
**Parameters:**
|
|
400
|
+
- `placementName`: Placement name configured in LevelPlay dashboard
|
|
401
|
+
|
|
402
|
+
**Usage:**
|
|
403
|
+
```csharp
|
|
404
|
+
rewardedAd.ShowAd(placementName: "extra_lives");
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**When to use:** When tracking multiple placements within the same ad unit for analytics.
|
|
408
|
+
|
|
409
|
+
#### `GetReward(string placementName = null)`
|
|
410
|
+
Get the reward configuration for a placement.
|
|
411
|
+
|
|
412
|
+
**Parameters:**
|
|
413
|
+
- `placementName` (optional): The placement name to query. If null, returns default reward.
|
|
414
|
+
|
|
415
|
+
**Returns:** `LevelPlayReward` object with Name and Amount
|
|
416
|
+
|
|
417
|
+
**Usage:**
|
|
418
|
+
```csharp
|
|
419
|
+
// Get default reward
|
|
420
|
+
LevelPlayReward defaultReward = rewardedAd.GetReward();
|
|
421
|
+
Debug.Log($"Default reward: {defaultReward.Amount} {defaultReward.Name}");
|
|
422
|
+
|
|
423
|
+
// Get placement-specific reward
|
|
424
|
+
LevelPlayReward placementReward = rewardedAd.GetReward("extra_lives");
|
|
425
|
+
Debug.Log($"Extra lives reward: {placementReward.Amount} {placementReward.Name}");
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**When to use:** To display reward information to users before they watch the ad (e.g., "Watch ad to earn 5 coins").
|
|
429
|
+
|
|
430
|
+
#### `IsAdReady()`
|
|
431
|
+
Check if a rewarded ad is loaded and ready to show.
|
|
432
|
+
|
|
433
|
+
**Returns:** `bool` - true if ready, false otherwise
|
|
434
|
+
|
|
435
|
+
**Usage:**
|
|
436
|
+
```csharp
|
|
437
|
+
if (rewardedAd.IsAdReady())
|
|
438
|
+
{
|
|
439
|
+
// Ad is ready to show
|
|
440
|
+
rewardedAd.ShowAd();
|
|
441
|
+
}
|
|
442
|
+
else
|
|
443
|
+
{
|
|
444
|
+
// Ad not ready, maybe disable the button
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**Best practice:** Check this before showing ad UI buttons to users.
|
|
449
|
+
|
|
450
|
+
#### `LevelPlayRewardedAd.IsPlacementCapped(string placementName)` (Static)
|
|
451
|
+
Check if a placement has reached its capping limit.
|
|
452
|
+
|
|
453
|
+
**Parameters:**
|
|
454
|
+
- `placementName`: The placement name to check
|
|
455
|
+
|
|
456
|
+
**Returns:** `bool` - true if capped, false otherwise
|
|
457
|
+
|
|
458
|
+
**Usage:**
|
|
459
|
+
```csharp
|
|
460
|
+
if (LevelPlayRewardedAd.IsPlacementCapped("extra_lives"))
|
|
461
|
+
{
|
|
462
|
+
Debug.Log("Extra lives placement is capped");
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
**When to use:** Before showing an ad to check if the placement frequency cap is reached.
|
|
467
|
+
|
|
468
|
+
### Events
|
|
469
|
+
|
|
470
|
+
All events are properties of the `LevelPlayRewardedAd` object.
|
|
471
|
+
|
|
472
|
+
**Threading:** All ad callbacks run on the Unity main thread, so you can safely call Unity APIs (update UI, access GameObjects, etc.) directly in these callbacks. This is different from the ILRD impression callback (see `references/ilrd-api.md`), which runs on a background thread.
|
|
473
|
+
|
|
474
|
+
#### `OnAdLoaded`
|
|
475
|
+
Fired when a rewarded ad is successfully loaded.
|
|
476
|
+
|
|
477
|
+
**Signature:** `event Action<LevelPlayAdInfo>`
|
|
478
|
+
|
|
479
|
+
**Usage:**
|
|
480
|
+
```csharp
|
|
481
|
+
rewardedAd.OnAdLoaded += (adInfo) =>
|
|
482
|
+
{
|
|
483
|
+
Debug.Log("Rewarded ad loaded");
|
|
484
|
+
// Enable UI button, etc.
|
|
485
|
+
};
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
#### `OnAdLoadFailed`
|
|
489
|
+
Fired when a rewarded ad fails to load.
|
|
490
|
+
|
|
491
|
+
**Signature:** `event Action<LevelPlayAdError>`
|
|
492
|
+
|
|
493
|
+
**Usage:**
|
|
494
|
+
```csharp
|
|
495
|
+
rewardedAd.OnAdLoadFailed += (error) =>
|
|
496
|
+
{
|
|
497
|
+
Debug.LogWarning($"Load failed: {error.ErrorMessage}");
|
|
498
|
+
// Retry loading
|
|
499
|
+
};
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
**Best practice:** Implement retry logic with exponential backoff.
|
|
503
|
+
|
|
504
|
+
#### `OnAdDisplayed`
|
|
505
|
+
Fired when a rewarded ad is displayed on screen.
|
|
506
|
+
|
|
507
|
+
**Signature:** `event Action<LevelPlayAdInfo>`
|
|
508
|
+
|
|
509
|
+
**Usage:**
|
|
510
|
+
```csharp
|
|
511
|
+
rewardedAd.OnAdDisplayed += (adInfo) =>
|
|
512
|
+
{
|
|
513
|
+
Debug.Log("Rewarded ad displayed");
|
|
514
|
+
// Optional: Pause game
|
|
515
|
+
};
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
#### `OnAdDisplayFailed`
|
|
519
|
+
Fired when a rewarded ad fails to display.
|
|
520
|
+
|
|
521
|
+
**Signature:** `event Action<LevelPlayAdInfo, LevelPlayAdError>`
|
|
522
|
+
|
|
523
|
+
**Usage:**
|
|
524
|
+
```csharp
|
|
525
|
+
rewardedAd.OnAdDisplayFailed += (adInfo, error) =>
|
|
526
|
+
{
|
|
527
|
+
Debug.LogError($"Display failed: {error.ErrorMessage}");
|
|
528
|
+
// Load a new ad
|
|
529
|
+
rewardedAd.LoadAd();
|
|
530
|
+
};
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
#### `OnAdRewarded`
|
|
534
|
+
Fired when the user has earned the reward.
|
|
535
|
+
|
|
536
|
+
**Signature:** `event Action<LevelPlayAdInfo, LevelPlayReward>`
|
|
537
|
+
|
|
538
|
+
**Parameters:**
|
|
539
|
+
- `adInfo`: Information about the ad
|
|
540
|
+
- `reward`: The reward object containing `Name` and `Amount`
|
|
541
|
+
|
|
542
|
+
**Usage:**
|
|
543
|
+
```csharp
|
|
544
|
+
rewardedAd.OnAdRewarded += (adInfo, reward) =>
|
|
545
|
+
{
|
|
546
|
+
Debug.Log($"User earned: {reward.Amount} {reward.Name}");
|
|
547
|
+
// Grant the reward to the user
|
|
548
|
+
GrantReward(reward);
|
|
549
|
+
};
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
**Critical:** This is where you grant rewards to the user. Don't wait for `OnAdClosed` - users may close before the ad finishes.
|
|
553
|
+
|
|
554
|
+
#### `OnAdClosed`
|
|
555
|
+
Fired when the rewarded ad is closed.
|
|
556
|
+
|
|
557
|
+
**Signature:** `event Action<LevelPlayAdInfo>`
|
|
558
|
+
|
|
559
|
+
**Usage:**
|
|
560
|
+
```csharp
|
|
561
|
+
rewardedAd.OnAdClosed += (adInfo) =>
|
|
562
|
+
{
|
|
563
|
+
Debug.Log("Rewarded ad closed");
|
|
564
|
+
// Resume game. Whether to call LoadAd() here depends on your load strategy:
|
|
565
|
+
// call it if you preload eagerly; otherwise wait for the player's next load trigger.
|
|
566
|
+
};
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
#### `OnAdClicked`
|
|
570
|
+
Fired when the user clicks on the rewarded ad.
|
|
571
|
+
|
|
572
|
+
**Signature:** `event Action<LevelPlayAdInfo>`
|
|
573
|
+
|
|
574
|
+
**Usage:**
|
|
575
|
+
```csharp
|
|
576
|
+
rewardedAd.OnAdClicked += (adInfo) =>
|
|
577
|
+
{
|
|
578
|
+
Debug.Log("Rewarded ad clicked");
|
|
579
|
+
// Optional analytics tracking
|
|
580
|
+
};
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
#### `OnAdInfoChanged`
|
|
584
|
+
Fired when ad information changes, such as when a new winning ad becomes available after auction.
|
|
585
|
+
|
|
586
|
+
**Signature:** `event Action<LevelPlayAdInfo>`
|
|
587
|
+
|
|
588
|
+
**Usage:**
|
|
589
|
+
```csharp
|
|
590
|
+
rewardedAd.OnAdInfoChanged += (adInfo) =>
|
|
591
|
+
{
|
|
592
|
+
Debug.Log($"Ad info changed - New ad from: {adInfo.AdNetwork}");
|
|
593
|
+
Debug.Log($"Estimated revenue: ${adInfo.Revenue}");
|
|
594
|
+
};
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
**Important:** This event indicates that a new ad with potentially different revenue has become available. The SDK automatically selects the winning ad from the auction when you call `ShowAd()`, but this event lets you know when the ad info has been updated. This is particularly important for revenue optimization as it signals when a new auction winner has loaded.
|
|
598
|
+
|
|
599
|
+
**When it fires:**
|
|
600
|
+
- After a new ad loads with different properties than the previous one
|
|
601
|
+
- When the waterfall selects a different ad network
|
|
602
|
+
- When ad auction results change
|
|
603
|
+
|
|
604
|
+
**Why it matters:** The updated `LevelPlayAdInfo` contains the latest revenue estimates and network information, which directly impacts your monetization. Always use the most recent `adInfo` when logging or analyzing ad performance.
|
|
605
|
+
|
|
606
|
+
**If you're using ILRD** (`references/ilrd-api.md`): the `LevelPlayImpressionData` you receive in the ILRD impression callback already contains the final revenue value, so `OnAdInfoChanged` is mostly useful for in-Editor debugging of the waterfall. Most publishers can leave it as a logging hook.
|
|
607
|
+
|
|
608
|
+
## Data Types
|
|
609
|
+
|
|
610
|
+
### LevelPlayReward
|
|
611
|
+
|
|
612
|
+
Represents the reward earned by the user.
|
|
613
|
+
|
|
614
|
+
**Properties:**
|
|
615
|
+
- `Name` (string): The reward name (e.g., "coins", "life")
|
|
616
|
+
- `Amount` (int): The reward amount (e.g., 10, 1)
|
|
617
|
+
|
|
618
|
+
**Usage:**
|
|
619
|
+
```csharp
|
|
620
|
+
private void OnAdRewarded(LevelPlayAdInfo adInfo, LevelPlayReward reward)
|
|
621
|
+
{
|
|
622
|
+
Debug.Log($"Reward: {reward.Amount} {reward.Name}");
|
|
623
|
+
|
|
624
|
+
if (reward.Name == "coins")
|
|
625
|
+
{
|
|
626
|
+
playerCoins += reward.Amount;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
### LevelPlayAdInfo
|
|
632
|
+
|
|
633
|
+
Contains information about the ad.
|
|
634
|
+
|
|
635
|
+
**Properties:**
|
|
636
|
+
- `AdId` (string): Unique identifier for this specific ad instance
|
|
637
|
+
- `AdUnitId` (string): The ad unit identifier
|
|
638
|
+
- `AdUnitName` (string): The ad unit name
|
|
639
|
+
- `AdSize` (LevelPlayAdSize): The ad size (may be null; banner-relevant)
|
|
640
|
+
- `AdFormat` (string): The ad format (e.g., "REWARDED")
|
|
641
|
+
- `PlacementName` (string): Placement name where ad was shown
|
|
642
|
+
- `AuctionId` (string): Unique auction identifier
|
|
643
|
+
- `CreativeId` (string): Creative identifier
|
|
644
|
+
- `Country` (string): User's country code (ISO 3166-1)
|
|
645
|
+
- `Ab` (string): A/B test segment identifier
|
|
646
|
+
- `SegmentName` (string): User segment name
|
|
647
|
+
- `AdNetwork` (string): Ad network that served the ad
|
|
648
|
+
- `InstanceName` (string): Ad network instance name
|
|
649
|
+
- `InstanceId` (string): Ad network instance identifier
|
|
650
|
+
- `Revenue` (double?): Estimated revenue in USD (nullable - check for null)
|
|
651
|
+
- `Precision` (string): Revenue precision level
|
|
652
|
+
- `EncryptedCPM` (string): Encrypted CPM value
|
|
653
|
+
|
|
654
|
+
### LevelPlayAdError
|
|
655
|
+
|
|
656
|
+
Contains error information when ad operations fail.
|
|
657
|
+
|
|
658
|
+
**Properties:**
|
|
659
|
+
- `ErrorCode` (int): Numeric error code
|
|
660
|
+
- `ErrorMessage` (string): Human-readable error description
|
|
661
|
+
- `AdUnitId` (string): The ad unit identifier where the error occurred
|
|
662
|
+
- `AdId` (string): Unique identifier for the specific ad instance
|
|
663
|
+
|
|
664
|
+
## Best Practices
|
|
665
|
+
|
|
666
|
+
### Loading Strategy
|
|
667
|
+
|
|
668
|
+
Unlike the legacy IronSource rewarded video (where the SDK managed loading automatically), the MADU rewarded API requires `LoadAd()` to be called explicitly. The ad object is created in `OnInitSuccess`, but loading is a separate step triggered by the publisher.
|
|
669
|
+
|
|
670
|
+
**Explicit load pattern (matches official sample):**
|
|
671
|
+
```csharp
|
|
672
|
+
// In OnInitSuccess: create the object and subscribe events only — do not load yet.
|
|
673
|
+
void OnInitSuccess(LevelPlayConfiguration config)
|
|
674
|
+
{
|
|
675
|
+
rewardedAd = new LevelPlayRewardedAd(adUnitId);
|
|
676
|
+
rewardedAd.OnAdLoaded += OnAdLoaded;
|
|
677
|
+
rewardedAd.OnAdClosed += OnAdClosed;
|
|
678
|
+
// LoadAd() is called later, from a publisher-controlled trigger.
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Example trigger: called from a UI button or a scene entry point.
|
|
682
|
+
public void OnPlayerReachesRewardedAdOpportunity()
|
|
683
|
+
{
|
|
684
|
+
rewardedAd.LoadAd();
|
|
685
|
+
}
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
**Eager preload pattern (optional):** If the game always needs a rewarded ad ready the moment the player reaches certain screens, call `LoadAd()` immediately in `OnInitSuccess` after creating the object, and optionally again in `OnAdClosed`. This is a valid choice but makes the manual load requirement less visible — use it consciously, not as a default.
|
|
689
|
+
|
|
690
|
+
```csharp
|
|
691
|
+
void OnInitSuccess(LevelPlayConfiguration config)
|
|
692
|
+
{
|
|
693
|
+
rewardedAd = new LevelPlayRewardedAd(adUnitId);
|
|
694
|
+
rewardedAd.OnAdLoaded += OnAdLoaded;
|
|
695
|
+
rewardedAd.OnAdClosed += OnAdClosed;
|
|
696
|
+
rewardedAd.LoadAd(); // Eager preload — conscious choice, not automatic legacy behavior.
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
void OnAdClosed(LevelPlayAdInfo adInfo)
|
|
700
|
+
{
|
|
701
|
+
rewardedAd.LoadAd(); // Reload immediately so one is ready for the next opportunity.
|
|
702
|
+
}
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
### UI Integration
|
|
706
|
+
|
|
707
|
+
**Show/hide buttons based on ad availability:**
|
|
708
|
+
```csharp
|
|
709
|
+
public Button watchAdButton;
|
|
710
|
+
|
|
711
|
+
void Update()
|
|
712
|
+
{
|
|
713
|
+
// Enable button only if ad is ready
|
|
714
|
+
watchAdButton.interactable = rewardedAd != null && rewardedAd.IsAdReady();
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
void OnAdLoaded(LevelPlayAdInfo adInfo)
|
|
718
|
+
{
|
|
719
|
+
watchAdButton.interactable = true;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
void OnAdLoadFailed(LevelPlayAdError error)
|
|
723
|
+
{
|
|
724
|
+
watchAdButton.interactable = false;
|
|
725
|
+
}
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
### Reward Granting
|
|
729
|
+
|
|
730
|
+
**Grant rewards in `OnAdRewarded`, not `OnAdClosed`:**
|
|
731
|
+
```csharp
|
|
732
|
+
// ✅ CORRECT
|
|
733
|
+
private void OnAdRewarded(LevelPlayAdInfo adInfo, LevelPlayReward reward)
|
|
734
|
+
{
|
|
735
|
+
GrantReward(reward); // Grant immediately
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// ❌ WRONG - user may close ad early
|
|
739
|
+
private void OnAdClosed(LevelPlayAdInfo adInfo)
|
|
740
|
+
{
|
|
741
|
+
// Don't grant reward here!
|
|
742
|
+
}
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
**Note:** `OnAdRewarded` and `OnAdClosed` are asynchronous — `OnAdRewarded` may fire after `OnAdClosed`. Do not write logic in `OnAdClosed` that assumes the reward has already been granted.
|
|
746
|
+
|
|
747
|
+
### Error Handling
|
|
748
|
+
|
|
749
|
+
**Handle ad load failures:**
|
|
750
|
+
```csharp
|
|
751
|
+
private void OnAdLoadFailed(LevelPlayAdError error)
|
|
752
|
+
{
|
|
753
|
+
Debug.LogWarning($"Ad load failed: {error.ErrorMessage}");
|
|
754
|
+
|
|
755
|
+
// Retry loading after a delay
|
|
756
|
+
Invoke(nameof(RetryLoad), 30f);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
private void RetryLoad()
|
|
760
|
+
{
|
|
761
|
+
rewardedAd.LoadAd();
|
|
762
|
+
}
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
### Multiple Placements
|
|
766
|
+
|
|
767
|
+
**Use placements to track different reward contexts:**
|
|
768
|
+
- Create placements in LevelPlay dashboard (e.g., "hints", "extra_lives")
|
|
769
|
+
- Use `ShowAd(placementName: "name")` to track separately
|
|
770
|
+
- Check `IsPlacementCapped()` before showing
|
|
771
|
+
- Handle rewards differently based on placement in `OnAdRewarded`
|
|
772
|
+
|
|
773
|
+
### Memory Management
|
|
774
|
+
|
|
775
|
+
**Always unsubscribe from events:**
|
|
776
|
+
```csharp
|
|
777
|
+
void OnDestroy()
|
|
778
|
+
{
|
|
779
|
+
if (rewardedAd != null)
|
|
780
|
+
{
|
|
781
|
+
rewardedAd.OnAdLoaded -= OnAdLoaded;
|
|
782
|
+
rewardedAd.OnAdLoadFailed -= OnAdLoadFailed;
|
|
783
|
+
rewardedAd.OnAdDisplayed -= OnAdDisplayed;
|
|
784
|
+
rewardedAd.OnAdDisplayFailed -= OnAdDisplayFailed;
|
|
785
|
+
rewardedAd.OnAdRewarded -= OnAdRewarded;
|
|
786
|
+
rewardedAd.OnAdClosed -= OnAdClosed;
|
|
787
|
+
rewardedAd.OnAdClicked -= OnAdClicked;
|
|
788
|
+
rewardedAd.OnAdInfoChanged -= OnAdInfoChanged;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
## Common Issues
|
|
794
|
+
|
|
795
|
+
### Issue: Error 1037 (Load during load)
|
|
796
|
+
|
|
797
|
+
**Cause:** Calling `LoadAd()` repeatedly in `Update()` or other high-frequency loops before the previous load completes.
|
|
798
|
+
|
|
799
|
+
**Common mistake:**
|
|
800
|
+
```csharp
|
|
801
|
+
void Update()
|
|
802
|
+
{
|
|
803
|
+
// WRONG - This will cause error 1037!
|
|
804
|
+
if (!rewardedAd.IsAdReady())
|
|
805
|
+
{
|
|
806
|
+
rewardedAd.LoadAd();
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
**Why this fails:** If the ad is still loading, calling `LoadAd()` again triggers error 1037: "Cannot load while another load is in progress."
|
|
812
|
+
|
|
813
|
+
**Solution:** Track load state manually and only call `LoadAd()` once:
|
|
814
|
+
```csharp
|
|
815
|
+
private bool isLoadingAd = false;
|
|
816
|
+
|
|
817
|
+
void Start()
|
|
818
|
+
{
|
|
819
|
+
LoadRewardedAd();
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
void LoadRewardedAd()
|
|
823
|
+
{
|
|
824
|
+
if (isLoadingAd) return; // Prevent duplicate loads
|
|
825
|
+
|
|
826
|
+
isLoadingAd = true;
|
|
827
|
+
rewardedAd.LoadAd();
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
void OnAdLoaded(LevelPlayAdInfo adInfo)
|
|
831
|
+
{
|
|
832
|
+
isLoadingAd = false;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
void OnAdLoadFailed(LevelPlayAdError error)
|
|
836
|
+
{
|
|
837
|
+
isLoadingAd = false;
|
|
838
|
+
// Optionally retry after delay
|
|
839
|
+
}
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
### Issue: Reward not granted to user
|
|
843
|
+
|
|
844
|
+
**Possible causes:**
|
|
845
|
+
- Granting reward in `OnAdClosed` instead of `OnAdRewarded`
|
|
846
|
+
- User closes ad before completion
|
|
847
|
+
- Reward logic has bugs
|
|
848
|
+
|
|
849
|
+
**Solution:**
|
|
850
|
+
Always grant rewards in `OnAdRewarded`, which fires when the user has earned the reward (typically after watching enough of the ad).
|
|
851
|
+
|
|
852
|
+
### Issue: Ad not loading
|
|
853
|
+
|
|
854
|
+
**Possible causes:**
|
|
855
|
+
- SDK not initialized before creating ad object
|
|
856
|
+
- No internet connection
|
|
857
|
+
- Ad inventory not available in test region
|
|
858
|
+
- Incorrect ad unit ID
|
|
859
|
+
|
|
860
|
+
**Solutions:**
|
|
861
|
+
- Create ad object only after `OnInitSuccess` callback
|
|
862
|
+
- Check network connectivity
|
|
863
|
+
- Verify ad unit ID in LevelPlay dashboard
|
|
864
|
+
- Test on real device with good connection
|
|
865
|
+
|
|
866
|
+
### Issue: Button always disabled
|
|
867
|
+
|
|
868
|
+
**Possible causes:**
|
|
869
|
+
- Not checking `IsAdReady()` correctly
|
|
870
|
+
- Ad failed to load and no retry logic
|
|
871
|
+
- Event subscriptions not working
|
|
872
|
+
|
|
873
|
+
**Solutions:**
|
|
874
|
+
- Implement `OnAdLoaded` callback to enable button
|
|
875
|
+
- Add retry logic in `OnAdLoadFailed`
|
|
876
|
+
- Debug log all callbacks to verify they fire
|
|
877
|
+
|
|
878
|
+
### Issue: Multiple reward grants
|
|
879
|
+
|
|
880
|
+
**Possible causes:**
|
|
881
|
+
- `OnAdRewarded` callback subscribed multiple times
|
|
882
|
+
- Not tracking if reward already granted
|
|
883
|
+
|
|
884
|
+
**Solutions:**
|
|
885
|
+
- Unsubscribe in `OnDestroy()`
|
|
886
|
+
- Only subscribe once in initialization
|
|
887
|
+
- Use flag to track if reward granted for this ad
|
|
888
|
+
|
|
889
|
+
## Testing Checklist
|
|
890
|
+
|
|
891
|
+
- [ ] Ad loads successfully after SDK initialization
|
|
892
|
+
- [ ] `IsAdReady()` returns true when ad is loaded
|
|
893
|
+
- [ ] Ad displays correctly when `ShowAd()` is called
|
|
894
|
+
- [ ] `OnAdRewarded` fires and reward is granted
|
|
895
|
+
- [ ] UI button enables when ad is ready
|
|
896
|
+
- [ ] UI button disables when ad is not ready
|
|
897
|
+
- [ ] Ad reloads automatically after being shown
|
|
898
|
+
- [ ] Retry logic works when ad fails to load
|
|
899
|
+
- [ ] Multiple placements track correctly (if using)
|
|
900
|
+
- [ ] Placement capping works (if configured)
|
|
901
|
+
- [ ] Memory leaks prevented (events unsubscribed)
|
|
902
|
+
- [ ] Tested on multiple devices and network conditions
|