Separating out ads functionality

This commit is contained in:
Eric Froemling 2020-10-17 18:18:21 -07:00
parent d098291948
commit eba70f0c81
16 changed files with 234 additions and 204 deletions

View File

@ -3932,24 +3932,24 @@
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/72/93/a41a9777570bee533ab3259f1597",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/2d/40/964c6b36393b12b459433dcda36c",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e3/d6/e286d413e60a2e6a43b5773d6441",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/20/97/d4a3ccde682ec984a67b3d683f54",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/82/25/c1d9b277444a9aa46be5f1eec44a",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9c/05/36d55f280f9676e3098ed9aa6a78",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8a/8c/0a3d0b30186fec5b189a5f0407cb",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/30/1c/f554338c290026fb45bd52e9e1a7",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/fa/e5/e624e868b0fc00a2413ae4b9432c",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e8/1e/418931e11d12072c869808579592",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/21/21/de5c6e124de4675b11d0c73ceb28",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/11/f3/037c95d8bbb74730bdef686526a5",
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1a/4a/bd980abb5c7078d1e144d19fa63d",
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fd/cd/3397d744c7405740df4d4ae567f0",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/34/c2/24a9ab7d513acdb8ebaa3251611f",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/54/40/8e0cc564f49f8963803834ec7995",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/62/55/765d22f045d0d4d31a02aeffec7b",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4b/76/aa0554648b65da797eb30b9c4699",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/91/dc/c415fc19cfa0395cc200a5a72e2c",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cd/d8/ec9c1c0955cc62ea574a4b42a707"
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/dd/d1/e12c5331256ecffcd7684d6d2963",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c5/35/8d811eec1a47f4e70d4b27eb3bf5",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6f/43/d0f61fb34a76e11b9ebd4334038d",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/56/614e09d8ab86355f0d65c1ce76fe",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f7/c5/f695953295c2d79dfb01555aea89",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7b/19/ff1bba3a148b6e0f0823d7d7c7bf",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/dd/d5e4d872192060d46821d6911c13",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/64/58/962c2e707ee66d310848f375796a",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/db/58/65c487facba1de6ba8ce65f19f01",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/40/cb/afd71350fdc9827ca99baab73001",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f2/05/e9252b68a96ee418da35dd4d2530",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bb/a2/e1f5b3f561a08bb09cc3ffb2492f",
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/66/c9/3b04209f599dea8b8ca4be7d3404",
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0d/3b/b7b46c3131cff8a40dfaa001af38",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/57/40/0c1d88af3ce14e0f8870ab9ac7ad",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8a/72/02b4eddf662001f05f98288d4ad4",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fc/bc/51529aac7531d1a62cf13eb79153",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ea/7b/de9ce5284627cc77b2fffc354a66",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/96/00/78b64146e33ec35dcde9c278328a",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6d/25/0e5918fa1eb7285538d14051761c"
}

View File

@ -29,8 +29,8 @@
<w>achname</w>
<w>achs</w>
<w>acinstance</w>
<w>ack'ed</w>
<w>ack</w>
<w>ack'ed</w>
<w>acked</w>
<w>acks</w>
<w>acnt</w>
@ -152,8 +152,8 @@
<w>bacommon</w>
<w>badguy</w>
<w>bafoundation</w>
<w>ballistica's</w>
<w>ballistica</w>
<w>ballistica's</w>
<w>ballisticacore</w>
<w>ballisticacorecb</w>
<w>bamaster</w>
@ -800,8 +800,8 @@
<w>gamedata</w>
<w>gameinstance</w>
<w>gamemap</w>
<w>gamepad's</w>
<w>gamepad</w>
<w>gamepad's</w>
<w>gamepadadvanced</w>
<w>gamepads</w>
<w>gamepadselect</w>
@ -1189,8 +1189,8 @@
<w>lsqlite</w>
<w>lssl</w>
<w>lstart</w>
<w>lstr's</w>
<w>lstr</w>
<w>lstr's</w>
<w>lstrs</w>
<w>lsval</w>
<w>ltex</w>
@ -1823,8 +1823,8 @@
<w>sessionname</w>
<w>sessionplayer</w>
<w>sessionplayers</w>
<w>sessionteam's</w>
<w>sessionteam</w>
<w>sessionteam's</w>
<w>sessionteams</w>
<w>sessiontype</w>
<w>setactivity</w>
@ -2156,8 +2156,8 @@
<w>txtw</w>
<w>typeargs</w>
<w>typecheck</w>
<w>typechecker's</w>
<w>typechecker</w>
<w>typechecker's</w>
<w>typedval</w>
<w>typeshed</w>
<w>typestr</w>

View File

@ -5,6 +5,7 @@
- Plugin functionality has been consolidated into a PluginSubsystem obj at ba.app.plugins
- Ditto with AccountSubsystem and ba.app.accounts
- Ditto with MetadataSubsystem and ba.app.meta
- Ditto with AdsSubsystem and ba.app.ads
### 1.5.26 (20217)
- Simplified licensing header on python scripts.

View File

@ -6,6 +6,7 @@
"ba_data/python/ba/__pycache__/_activity.cpython-38.opt-1.pyc",
"ba_data/python/ba/__pycache__/_activitytypes.cpython-38.opt-1.pyc",
"ba_data/python/ba/__pycache__/_actor.cpython-38.opt-1.pyc",
"ba_data/python/ba/__pycache__/_ads.cpython-38.opt-1.pyc",
"ba_data/python/ba/__pycache__/_analytics.cpython-38.opt-1.pyc",
"ba_data/python/ba/__pycache__/_app.cpython-38.opt-1.pyc",
"ba_data/python/ba/__pycache__/_appconfig.cpython-38.opt-1.pyc",
@ -67,6 +68,7 @@
"ba_data/python/ba/_activity.py",
"ba_data/python/ba/_activitytypes.py",
"ba_data/python/ba/_actor.py",
"ba_data/python/ba/_ads.py",
"ba_data/python/ba/_analytics.py",
"ba_data/python/ba/_app.py",
"ba_data/python/ba/_appconfig.py",

View File

@ -137,6 +137,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
build/ba_data/python/ba/_activity.py \
build/ba_data/python/ba/_activitytypes.py \
build/ba_data/python/ba/_actor.py \
build/ba_data/python/ba/_ads.py \
build/ba_data/python/ba/_analytics.py \
build/ba_data/python/ba/_app.py \
build/ba_data/python/ba/_appconfig.py \
@ -375,6 +376,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
build/ba_data/python/ba/__pycache__/_activity.cpython-38.opt-1.pyc \
build/ba_data/python/ba/__pycache__/_activitytypes.cpython-38.opt-1.pyc \
build/ba_data/python/ba/__pycache__/_actor.cpython-38.opt-1.pyc \
build/ba_data/python/ba/__pycache__/_ads.cpython-38.opt-1.pyc \
build/ba_data/python/ba/__pycache__/_analytics.cpython-38.opt-1.pyc \
build/ba_data/python/ba/__pycache__/_app.cpython-38.opt-1.pyc \
build/ba_data/python/ba/__pycache__/_appconfig.cpython-38.opt-1.pyc \

View File

@ -40,11 +40,10 @@ class EndSessionActivity(Activity[EmptyPlayer, EmptyTeam]):
def on_begin(self) -> None:
# pylint: disable=cyclic-import
from bastd.mainmenu import MainMenuSession
from ba._apputils import call_after_ad
from ba._general import Call
super().on_begin()
_ba.unlock_all_input()
call_after_ad(Call(_ba.new_host_session, MainMenuSession))
_ba.app.ads.call_after_ad(Call(_ba.new_host_session, MainMenuSession))
class JoinActivity(Activity[EmptyPlayer, EmptyTeam]):

View File

@ -0,0 +1,186 @@
# Released under the MIT License. See LICENSE for details.
#
"""Functionality related to ads."""
from __future__ import annotations
import time
from typing import TYPE_CHECKING
import _ba
if TYPE_CHECKING:
from typing import Optional, Callable, Any
class AdsSubsystem:
"""Subsystem for ads functionality in the app.
Category: App Classes
Access the single shared instance of this class at 'ba.app.ads'.
"""
def __init__(self) -> None:
self.last_ad_network = 'unknown'
self.last_ad_network_set_time = time.time()
self.ad_amt: Optional[float] = None
self.last_ad_purpose = 'invalid'
self.attempted_first_ad = False
self.last_in_game_ad_remove_message_show_time: Optional[float] = None
self.last_ad_completion_time: Optional[float] = None
self.last_ad_was_short = False
def do_remove_in_game_ads_message(self) -> None:
"""(internal)"""
from ba._language import Lstr
from ba._enums import TimeType
# Print this message once every 10 minutes at most.
tval = _ba.time(TimeType.REAL)
if (self.last_in_game_ad_remove_message_show_time is None or
(tval - self.last_in_game_ad_remove_message_show_time > 60 * 10)):
self.last_in_game_ad_remove_message_show_time = tval
with _ba.Context('ui'):
_ba.timer(
1.0,
lambda: _ba.screenmessage(Lstr(
resource='removeInGameAdsText',
subs=[('${PRO}',
Lstr(resource='store.bombSquadProNameText')),
('${APP_NAME}', Lstr(resource='titleText'))]),
color=(1, 1, 0)),
timetype=TimeType.REAL)
def show_ad(self,
purpose: str,
on_completion_call: Callable[[], Any] = None) -> None:
"""(internal)"""
self.last_ad_purpose = purpose
_ba.show_ad(purpose, on_completion_call)
def show_ad_2(self,
purpose: str,
on_completion_call: Callable[[bool], Any] = None) -> None:
"""(internal)"""
self.last_ad_purpose = purpose
_ba.show_ad_2(purpose, on_completion_call)
def call_after_ad(self, call: Callable[[], Any]) -> None:
"""Run a call after potentially showing an ad."""
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
from ba._enums import TimeType
app = _ba.app
show = True
# No ads without net-connections, etc.
if not _ba.can_show_ad():
show = False
if app.accounts.have_pro():
show = False # Pro disables interstitials.
try:
session = _ba.get_foreground_host_session()
assert session is not None
is_tournament = session.tournament_id is not None
except Exception:
is_tournament = False
if is_tournament:
show = False # Never show ads during tournaments.
if show:
interval: Optional[float]
launch_count = app.config.get('launchCount', 0)
# If we're seeing short ads we may want to space them differently.
interval_mult = (_ba.get_account_misc_read_val(
'ads.shortIntervalMult', 1.0)
if self.last_ad_was_short else 1.0)
if self.ad_amt is None:
if launch_count <= 1:
self.ad_amt = _ba.get_account_misc_read_val(
'ads.startVal1', 0.99)
else:
self.ad_amt = _ba.get_account_misc_read_val(
'ads.startVal2', 1.0)
interval = None
else:
# So far we're cleared to show; now calc our
# ad-show-threshold and see if we should *actually* show
# (we reach our threshold faster the longer we've been
# playing).
base = 'ads' if _ba.has_video_ads() else 'ads2'
min_lc = _ba.get_account_misc_read_val(base + '.minLC', 0.0)
max_lc = _ba.get_account_misc_read_val(base + '.maxLC', 5.0)
min_lc_scale = (_ba.get_account_misc_read_val(
base + '.minLCScale', 0.25))
max_lc_scale = (_ba.get_account_misc_read_val(
base + '.maxLCScale', 0.34))
min_lc_interval = (_ba.get_account_misc_read_val(
base + '.minLCInterval', 360))
max_lc_interval = (_ba.get_account_misc_read_val(
base + '.maxLCInterval', 300))
if launch_count < min_lc:
lc_amt = 0.0
elif launch_count > max_lc:
lc_amt = 1.0
else:
lc_amt = ((float(launch_count) - min_lc) /
(max_lc - min_lc))
incr = (1.0 - lc_amt) * min_lc_scale + lc_amt * max_lc_scale
interval = ((1.0 - lc_amt) * min_lc_interval +
lc_amt * max_lc_interval)
self.ad_amt += incr
assert self.ad_amt is not None
if self.ad_amt >= 1.0:
self.ad_amt = self.ad_amt % 1.0
self.attempted_first_ad = True
# After we've reached the traditional show-threshold once,
# try again whenever its been INTERVAL since our last successful
# show.
elif (
self.attempted_first_ad and
(self.last_ad_completion_time is None or
(interval is not None
and _ba.time(TimeType.REAL) - self.last_ad_completion_time >
(interval * interval_mult)))):
# Reset our other counter too in this case.
self.ad_amt = 0.0
else:
show = False
# If we're *still* cleared to show, actually tell the system to show.
if show:
# As a safety-check, set up an object that will run
# the completion callback if we've returned and sat for 10 seconds
# (in case some random ad network doesn't properly deliver its
# completion callback).
class _Payload:
def __init__(self, pcall: Callable[[], Any]):
self._call = pcall
self._ran = False
def run(self, fallback: bool = False) -> None:
"""Run fallback call (and issue a warning about it)."""
if not self._ran:
if fallback:
print(
('ERROR: relying on fallback ad-callback! '
'last network: ' + app.ads.last_ad_network +
' (set ' + str(
int(time.time() -
app.ads.last_ad_network_set_time)) +
's ago); purpose=' + app.ads.last_ad_purpose))
_ba.pushcall(self._call)
self._ran = True
payload = _Payload(call)
with _ba.Context('ui'):
_ba.timer(5.0,
lambda: payload.run(fallback=True),
timetype=TimeType.REAL)
self.show_ad('between_game', on_completion_call=payload.run)
else:
_ba.pushcall(call) # Just run the callback without the ad.

View File

@ -3,7 +3,6 @@
"""Functionality related to the high level state of the app."""
from __future__ import annotations
import time
import random
from typing import TYPE_CHECKING
@ -173,6 +172,7 @@ class App:
from ba._plugin import PluginSubsystem
from ba._account import AccountSubsystem
from ba._meta import MetadataSubsystem
from ba._ads import AdsSubsystem
# Config.
self.config_file_healthy = False
@ -199,12 +199,9 @@ class App:
# Misc.
self.tips: List[str] = []
self.stress_test_reset_timer: Optional[ba.Timer] = None
self.last_ad_completion_time: Optional[float] = None
self.last_ad_was_short = False
self.did_weak_call_warning = False
self.ran_on_app_launch = False
self.last_in_game_ad_remove_message_show_time: Optional[float] = None
self.log_have_new = False
self.log_upload_timer_started = False
self._config: Optional[ba.AppConfig] = None
@ -223,13 +220,6 @@ class App:
# Server Mode.
self.server: Optional[ba.ServerController] = None
# Ads.
self.last_ad_network = 'unknown'
self.last_ad_network_set_time = time.time()
self.ad_amt: Optional[float] = None
self.last_ad_purpose = 'invalid'
self.attempted_first_ad = False
self.meta = MetadataSubsystem()
self.accounts = AccountSubsystem()
self.plugins = PluginSubsystem()
@ -237,6 +227,7 @@ class App:
self.lang = LanguageSubsystem()
self.ach = AchievementSubsystem()
self.ui = UISubsystem()
self.ads = AdsSubsystem()
# Lobby.
self.lobby_random_profile_index: int = 1
@ -552,27 +543,6 @@ class App:
_ba.fade_screen(False, endcall=_fade_end)
return True
def do_remove_in_game_ads_message(self) -> None:
"""(internal)"""
from ba._language import Lstr
from ba._enums import TimeType
# Print this message once every 10 minutes at most.
tval = _ba.time(TimeType.REAL)
if (self.last_in_game_ad_remove_message_show_time is None or
(tval - self.last_in_game_ad_remove_message_show_time > 60 * 10)):
self.last_in_game_ad_remove_message_show_time = tval
with _ba.Context('ui'):
_ba.timer(
1.0,
lambda: _ba.screenmessage(Lstr(
resource='removeInGameAdsText',
subs=[('${PRO}',
Lstr(resource='store.bombSquadProNameText')),
('${APP_NAME}', Lstr(resource='titleText'))]),
color=(1, 1, 0)),
timetype=TimeType.REAL)
def on_app_shutdown(self) -> None:
"""(internal)"""
self.music.on_app_shutdown()

View File

@ -225,133 +225,3 @@ def print_corrupt_file_error() -> None:
_ba.timer(2.0,
Call(_ba.playsound, _ba.getsound('error')),
timetype=TimeType.REAL)
def show_ad(purpose: str,
on_completion_call: Callable[[], Any] = None) -> None:
"""(internal)"""
_ba.app.last_ad_purpose = purpose
_ba.show_ad(purpose, on_completion_call)
def show_ad_2(purpose: str,
on_completion_call: Callable[[bool], Any] = None) -> None:
"""(internal)"""
_ba.app.last_ad_purpose = purpose
_ba.show_ad_2(purpose, on_completion_call)
def call_after_ad(call: Callable[[], Any]) -> None:
"""Run a call after potentially showing an ad."""
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
from ba._enums import TimeType
import time
app = _ba.app
show = True
# No ads without net-connections, etc.
if not _ba.can_show_ad():
show = False
if app.accounts.have_pro():
show = False # Pro disables interstitials.
try:
session = _ba.get_foreground_host_session()
assert session is not None
is_tournament = session.tournament_id is not None
except Exception:
is_tournament = False
if is_tournament:
show = False # Never show ads during tournaments.
if show:
interval: Optional[float]
launch_count = app.config.get('launchCount', 0)
# If we're seeing short ads we may want to space them differently.
interval_mult = (_ba.get_account_misc_read_val(
'ads.shortIntervalMult', 1.0) if app.last_ad_was_short else 1.0)
if app.ad_amt is None:
if launch_count <= 1:
app.ad_amt = _ba.get_account_misc_read_val(
'ads.startVal1', 0.99)
else:
app.ad_amt = _ba.get_account_misc_read_val(
'ads.startVal2', 1.0)
interval = None
else:
# So far we're cleared to show; now calc our ad-show-threshold and
# see if we should *actually* show (we reach our threshold faster
# the longer we've been playing).
base = 'ads' if _ba.has_video_ads() else 'ads2'
min_lc = _ba.get_account_misc_read_val(base + '.minLC', 0.0)
max_lc = _ba.get_account_misc_read_val(base + '.maxLC', 5.0)
min_lc_scale = (_ba.get_account_misc_read_val(
base + '.minLCScale', 0.25))
max_lc_scale = (_ba.get_account_misc_read_val(
base + '.maxLCScale', 0.34))
min_lc_interval = (_ba.get_account_misc_read_val(
base + '.minLCInterval', 360))
max_lc_interval = (_ba.get_account_misc_read_val(
base + '.maxLCInterval', 300))
if launch_count < min_lc:
lc_amt = 0.0
elif launch_count > max_lc:
lc_amt = 1.0
else:
lc_amt = ((float(launch_count) - min_lc) / (max_lc - min_lc))
incr = (1.0 - lc_amt) * min_lc_scale + lc_amt * max_lc_scale
interval = ((1.0 - lc_amt) * min_lc_interval +
lc_amt * max_lc_interval)
app.ad_amt += incr
assert app.ad_amt is not None
if app.ad_amt >= 1.0:
app.ad_amt = app.ad_amt % 1.0
app.attempted_first_ad = True
# After we've reached the traditional show-threshold once,
# try again whenever its been INTERVAL since our last successful show.
elif (app.attempted_first_ad
and (app.last_ad_completion_time is None or
(interval is not None
and _ba.time(TimeType.REAL) - app.last_ad_completion_time >
(interval * interval_mult)))):
# Reset our other counter too in this case.
app.ad_amt = 0.0
else:
show = False
# If we're *still* cleared to show, actually tell the system to show.
if show:
# As a safety-check, set up an object that will run
# the completion callback if we've returned and sat for 10 seconds
# (in case some random ad network doesn't properly deliver its
# completion callback).
class _Payload:
def __init__(self, pcall: Callable[[], Any]):
self._call = pcall
self._ran = False
def run(self, fallback: bool = False) -> None:
"""Run the fallback call (and issues a warning about it)."""
if not self._ran:
if fallback:
print((
'ERROR: relying on fallback ad-callback! '
'last network: ' + app.last_ad_network + ' (set ' +
str(int(time.time() -
app.last_ad_network_set_time)) +
's ago); purpose=' + app.last_ad_purpose))
_ba.pushcall(self._call)
self._ran = True
payload = _Payload(call)
with _ba.Context('ui'):
_ba.timer(5.0,
lambda: payload.run(fallback=True),
timetype=TimeType.REAL)
show_ad('between_game', on_completion_call=payload.run)
else:
_ba.pushcall(call) # Just run the callback without the ad.

View File

@ -178,8 +178,8 @@ def submit_analytics_counts(sval: str) -> None:
def set_last_ad_network(sval: str) -> None:
import time
_ba.app.last_ad_network = sval
_ba.app.last_ad_network_set_time = time.time()
_ba.app.ads.last_ad_network = sval
_ba.app.ads.last_ad_network_set_time = time.time()
def no_game_circle_message() -> None:
@ -263,7 +263,7 @@ def quit_window() -> None:
def remove_in_game_ads_message() -> None:
_ba.app.do_remove_in_game_ads_message()
_ba.app.ads.do_remove_in_game_ads_message()
def telnet_access_request() -> None:

View File

@ -612,7 +612,7 @@ class Session:
def transitioning_out_activity_was_freed(
self, can_show_ad_on_death: bool) -> None:
"""(internal)"""
from ba._apputils import garbage_collect, call_after_ad
from ba._apputils import garbage_collect
# Since things should be generally still right now, it's a good time
# to run garbage collection to clear out any circular dependency
@ -622,7 +622,7 @@ class Session:
with _ba.Context(self):
if can_show_ad_on_death:
call_after_ad(self.begin_next_activity)
_ba.app.ads.call_after_ad(self.begin_next_activity)
else:
_ba.pushcall(self.begin_next_activity)

View File

@ -18,7 +18,7 @@ from ba._input import (get_device_value, get_input_map_hash,
from ba._general import getclass, json_prep, get_type_name
from ba._activitytypes import JoinActivity, ScoreScreenActivity
from ba._apputils import (is_browser_likely_available, get_remote_app_name,
should_submit_debug_info, show_ad, show_ad_2)
should_submit_debug_info)
from ba._benchmark import (run_gpu_benchmark, run_cpu_benchmark,
run_media_reload_benchmark, run_stress_test)
from ba._campaign import getcampaign

View File

@ -551,7 +551,6 @@ class GetCurrencyWindow(ba.Window):
# actually start the purchase locally..
def _do_purchase(self, item: str) -> None:
from ba.internal import show_ad
if item == 'ad':
import datetime
# if ads are disabled until some time, error..
@ -568,7 +567,7 @@ class GetCurrencyWindow(ba.Window):
resource='getTicketsWindow.unavailableTemporarilyText'),
color=(1, 0, 0))
elif self._enable_ad_button:
show_ad('tickets')
_ba.app.ads.show_ad('tickets')
else:
_ba.purchase(item)

View File

@ -434,8 +434,9 @@ def show_offer() -> bool:
# Space things out a bit so we don't hit the poor user with an ad and
# then an in-game offer.
has_been_long_enough_since_ad = True
if (app.last_ad_completion_time is not None and
(ba.time(ba.TimeType.REAL) - app.last_ad_completion_time < 30.0)):
if (app.ads.last_ad_completion_time is not None and
(ba.time(ba.TimeType.REAL) - app.ads.last_ad_completion_time <
30.0)):
has_been_long_enough_since_ad = False
if app.special_offer is not None and has_been_long_enough_since_ad:

View File

@ -525,7 +525,6 @@ class TournamentEntryWindow(popup.PopupWindow):
self._launch()
def _on_pay_with_ad_press(self) -> None:
from ba.internal import show_ad_2
# If we're already entering, ignore.
if self._entering:
@ -547,8 +546,9 @@ class TournamentEntryWindow(popup.PopupWindow):
cur_time = ba.time(ba.TimeType.REAL)
if cur_time - self._last_ad_press_time > 5.0:
self._last_ad_press_time = cur_time
show_ad_2('tournament_entry',
on_completion_call=ba.WeakCall(self._on_ad_complete))
_ba.app.ads.show_ad_2('tournament_entry',
on_completion_call=ba.WeakCall(
self._on_ad_complete))
def _on_ad_complete(self, actually_showed: bool) -> None:

View File

@ -1,5 +1,5 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<h4><em>last updated on 2020-10-16 for Ballistica version 1.5.27 build 20219</em></h4>
<h4><em>last updated on 2020-10-17 for Ballistica version 1.5.27 build 20223</em></h4>
<p>This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
<hr>