mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-25 08:23:35 +08:00
Exposing more C++ sources
This commit is contained in:
parent
85296ea6ab
commit
fafd23b673
@ -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/31/9f/f2aa794e452ae380c363dab7744e",
|
||||
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cf/0d/24472a7bce6c6de12493d506ce64",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3b/64/e544f697481ca43b38b3568b8a1e",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/70/f0/5df34ce15aa534d8c42cd7235984",
|
||||
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/62/2c/4ddcde6c2483ab591646c2f49257",
|
||||
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/94/e8/f272b412ca176fde161346bf1363",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/b2/63d02079a0fb191abf8366f64814",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/44/67/c3d7dcb5e16ad5451ba7daf2f9bd",
|
||||
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e0/2f/1665f879dbc7d9241b84990cffaf",
|
||||
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/fe/d6/77e6b6d65a3484e4c264be8dbfab",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/2a/01/3d42c36b2afd5a24d37edc2f6883",
|
||||
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f5/89/558acefe3774686fc10f967e737b",
|
||||
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ba/78/292390a40c1e4b9804d7572d7a04",
|
||||
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4c/a9/568023651355fdd0ce7a865c2872",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/69/cc/a5555af8babdef9948380ede8431",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/42/be/79eec8bc7b2cc914cc6cb8ed0769",
|
||||
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/66/66/063065ddf0a99cb992e936373f53",
|
||||
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/30/6f/27022976202b3886ad4a395f1f06",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/9e/55/2caa189c8674ef770c2ab3a7cd7d",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b2/14/f0e7a95e18c4484cf4a7894a3fbd"
|
||||
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c3/64/d09fa017e267f7239b53ea15e60b",
|
||||
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f2/0a/8923a5a2c428fe3c355eb3e9e024",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8e/da/41e88ab335c7edfa162c4a0de4be",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a0/76/805f87ceafce55784d025a3e9977",
|
||||
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/90/38/615955c8501a8ee201166bf44e36",
|
||||
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1d/2a/01fe857df7ef297a7f7ea3886d26",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0a/f8/59aeb014837f2419d76ee66cb01d",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a2/31/0a4cc16d108f66c9c8f323799103",
|
||||
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1d/4b/d1cdb7ad12c6a9a5ce6fef4e54af",
|
||||
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/69/7b/50ab311eea3401bdecedb322022e",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b5/95/dee668a0080fd9d529bc4d7a6ce8",
|
||||
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/53/b2/0e959273e553034e2d7ff135c8b0",
|
||||
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c4/c0/91eab0d803b753a0a2e1ba46c22f",
|
||||
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cb/72/fcba4049353a8cdbfec9d7065a3b",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e8/25/986296217583b22aaa1652e67086",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/38/1e/6650391748d1410acf7c26f0eb72",
|
||||
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d0/bf/73561ee1722ddce9a98d9a8c9b4f",
|
||||
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fe/1f/13289c985eaefb448c8c9c8e2cfc",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a5/4b/c79bf59874bf83cba38485114851",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e7/3d/d1e07fd3d91655d11787e7b60958"
|
||||
}
|
||||
15
Makefile
15
Makefile
@ -817,14 +817,15 @@ CM_BT_LC = $(shell echo $(CMAKE_BUILD_TYPE) | tr A-Z a-z)
|
||||
ballisticacore-cmake/.clang-format: .clang-format
|
||||
@cd ballisticacore-cmake && ln -sf ../.clang-format .
|
||||
|
||||
# Simple target for CI to build a binary but no assets/etc.
|
||||
_cmake-simple-ci-server-build:
|
||||
rm -rf build/cmake_scsb
|
||||
mkdir -p build/cmake_scsb
|
||||
tools/pcommand update_cmake_prefab_lib server debug build/cmake_scsb
|
||||
cd build/cmake_scsb && \
|
||||
# Simple target for CI to build a binary but not download/assemble assets/etc.
|
||||
_cmake-simple-ci-server-build: code
|
||||
rm -rf build/cmake_simple_ci_server_build
|
||||
mkdir -p build/cmake_simple_ci_server_build
|
||||
tools/pcommand update_cmake_prefab_lib \
|
||||
server debug build/cmake_simple_ci_server_build
|
||||
cd build/cmake_simple_ci_server_build && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DHEADLESS=true ${PWD}/ballisticacore-cmake
|
||||
cd build/cmake_scsb && ${MAKE} -j${CPUS}
|
||||
cd build/cmake_simple_ci_server_build && ${MAKE} -j${CPUS}
|
||||
|
||||
# Tell make which of these targets don't represent files.
|
||||
.PHONY: _cmake-simple-ci-server-build
|
||||
|
||||
@ -154,8 +154,8 @@ auto IsBootstrapped() -> bool;
|
||||
|
||||
/// Internal bits.
|
||||
auto CreateAppInternal() -> AppInternal*;
|
||||
auto AppInternalPythonInit() -> PyObject*;
|
||||
auto AppInternalPythonInit2() -> void;
|
||||
auto AppInternalInitModule() -> void;
|
||||
auto AppInternalHasBlessingHash() -> bool;
|
||||
auto AppInternalPutLog(bool fatal) -> bool;
|
||||
auto AppInternalAwardAdTickets() -> void;
|
||||
|
||||
2714
src/ballistica/python/python.cc
Normal file
2714
src/ballistica/python/python.cc
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,18 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
# This file was generated by tools/update_generated_code_makefile.
|
||||
|
||||
# Dummy generated-src makefile; nothing here for now.
|
||||
all: generated_code
|
||||
|
||||
generated_code:
|
||||
generated_code: ../generated/ballistica/binding.inc \
|
||||
../generated/ballistica/bootstrap.inc
|
||||
|
||||
clean:
|
||||
@rm -rf ../generated
|
||||
|
||||
../generated/ballistica/bootstrap.inc : ballistica/bootstrap.py
|
||||
@../../tools/pcommand gen_flat_data_code $< $@ bootstrap_code
|
||||
|
||||
../generated/ballistica/binding.inc : ballistica/binding.py
|
||||
@../../tools/pcommand gen_binding_code $< $@
|
||||
|
||||
|
||||
126
src/generated_src/ballistica/binding.py
Normal file
126
src/generated_src/ballistica/binding.py
Normal file
@ -0,0 +1,126 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
# Where most of our python-c++ binding happens.
|
||||
# Python objects should be added here along with their associated c++ enum.
|
||||
# Run make update to update the project after editing this..
|
||||
# pylint: disable=missing-module-docstring, missing-function-docstring
|
||||
# pylint: disable=line-too-long
|
||||
def get_binding_values() -> object:
|
||||
from ba import _hooks
|
||||
import _ba
|
||||
import json
|
||||
import copy
|
||||
import ba
|
||||
from ba import _lang
|
||||
from ba import _music
|
||||
from ba import _input
|
||||
from ba import _apputils
|
||||
from ba import _account
|
||||
from ba import _dependency
|
||||
from ba import _enums
|
||||
from ba import _player
|
||||
# FIXME: There should be no bastd in here;
|
||||
# should pull in bases from ba which get overridden by bastd (or other).
|
||||
from bastd.ui.onscreenkeyboard import OnScreenKeyboardWindow
|
||||
from bastd.ui import party
|
||||
return (
|
||||
_ba.client_info_query_response, # kClientInfoQueryResponseCall
|
||||
_hooks.reset_to_main_menu, # kResetToMainMenuCall
|
||||
_hooks.set_config_fullscreen_on, # kSetConfigFullscreenOnCall
|
||||
_hooks.set_config_fullscreen_off, # kSetConfigFullscreenOffCall
|
||||
_hooks.not_signed_in_screen_message, # kNotSignedInScreenMessageCall
|
||||
_hooks.connecting_to_party_message, # kConnectingToPartyMessageCall
|
||||
_hooks.rejecting_invite_already_in_party_message, # kRejectingInviteAlreadyInPartyMessageCall
|
||||
_hooks.connection_failed_message, # kConnectionFailedMessageCall
|
||||
_hooks.temporarily_unavailable_message, # kTemporarilyUnavailableMessageCall
|
||||
_hooks.in_progress_message, # kInProgressMessageCall
|
||||
_hooks.error_message, # kErrorMessageCall
|
||||
_hooks.purchase_not_valid_error, # kPurchaseNotValidErrorCall
|
||||
_hooks.purchase_already_in_progress_error, # kPurchaseAlreadyInProgressErrorCall
|
||||
_hooks.gear_vr_controller_warning, # kGearVRControllerWarningCall
|
||||
_hooks.orientation_reset_cb_message, # kVROrientationResetCBMessageCall
|
||||
_hooks.orientation_reset_message, # kVROrientationResetMessageCall
|
||||
_hooks.on_app_resume, # kHandleAppResumeCall
|
||||
_apputils.handle_log, # kHandleLogCall
|
||||
_hooks.launch_main_menu_session, # kLaunchMainMenuSessionCall
|
||||
_hooks.language_test_toggle, # kLanguageTestToggleCall
|
||||
_hooks.award_in_control_achievement, # kAwardInControlAchievementCall
|
||||
_hooks.award_dual_wielding_achievement, # kAwardDualWieldingAchievementCall
|
||||
_apputils.print_corrupt_file_error, # kPrintCorruptFileErrorCall
|
||||
_hooks.play_gong_sound, # kPlayGongSoundCall
|
||||
_hooks.launch_coop_game, # kLaunchCoopGameCall
|
||||
_hooks.purchases_restored_message, # kPurchasesRestoredMessageCall
|
||||
_hooks.dismiss_wii_remotes_window, # kDismissWiiRemotesWindowCall
|
||||
_hooks.unavailable_message, # kUnavailableMessageCall
|
||||
_hooks.submit_analytics_counts, # kSubmitAnalyticsCountsCall
|
||||
_hooks.set_last_ad_network, # kSetLastAdNetworkCall
|
||||
_hooks.no_game_circle_message, # kNoGameCircleMessageCall
|
||||
_hooks.empty_call, # kEmptyCall
|
||||
_hooks.level_icon_press, # kLevelIconPressCall
|
||||
_hooks.trophy_icon_press, # kTrophyIconPressCall
|
||||
_hooks.coin_icon_press, # kCoinIconPressCall
|
||||
_hooks.ticket_icon_press, # kTicketIconPressCall
|
||||
_hooks.back_button_press, # kBackButtonPressCall
|
||||
_hooks.friends_button_press, # kFriendsButtonPressCall
|
||||
_hooks.print_trace, # kPrintTraceCall
|
||||
_hooks.toggle_fullscreen, # kToggleFullscreenCall
|
||||
_hooks.party_icon_activate, # kPartyIconActivateCall
|
||||
_hooks.read_config, # kReadConfigCall
|
||||
_hooks.ui_remote_press, # kUIRemotePressCall
|
||||
_hooks.quit_window, # kQuitWindowCall
|
||||
_hooks.remove_in_game_ads_message, # kRemoveInGameAdsMessageCall
|
||||
_hooks.telnet_access_request, # kTelnetAccessRequestCall
|
||||
_hooks.on_app_pause, # kOnAppPauseCall
|
||||
_hooks.do_quit, # kQuitCall
|
||||
_hooks.shutdown, # kShutdownCall
|
||||
_hooks.gc_disable, # kGCDisableCall
|
||||
_account.show_post_purchase_message, # kShowPostPurchaseMessageCall
|
||||
_hooks.device_menu_press, # kDeviceMenuPressCall
|
||||
_hooks.show_url_window, # kShowURLWindowCall
|
||||
_hooks.party_invite_revoke, # kHandlePartyInviteRevokeCall
|
||||
_hooks.filter_chat_message, # kFilterChatMessageCall
|
||||
_hooks.local_chat_message, # kHandleLocalChatMessageCall
|
||||
ba.ShouldShatterMessage, # kShouldShatterMessageClass
|
||||
ba.ImpactDamageMessage, # kImpactDamageMessageClass
|
||||
ba.PickedUpMessage, # kPickedUpMessageClass
|
||||
ba.DroppedMessage, # kDroppedMessageClass
|
||||
ba.OutOfBoundsMessage, # kOutOfBoundsMessageClass
|
||||
ba.PickUpMessage, # kPickUpMessageClass
|
||||
ba.DropMessage, # kDropMessageClass
|
||||
ba.app.on_app_launch, # kOnAppLaunchCall
|
||||
_input.get_device_value, # kGetDeviceValueCall
|
||||
_input.get_last_player_name_from_input_device, # kGetLastPlayerNameFromInputDeviceCall
|
||||
copy.deepcopy, # kDeepCopyCall
|
||||
copy.copy, # kShallowCopyCall
|
||||
ba.Activity, # kActivityClass
|
||||
ba.Session, # kSessionClass
|
||||
json.dumps, # kJsonDumpsCall
|
||||
json.loads, # kJsonLoadsCall
|
||||
OnScreenKeyboardWindow, # kOnScreenKeyboardClass
|
||||
party.handle_party_invite, # kHandlePartyInviteCall
|
||||
_music.do_play_music, # kDoPlayMusicCall
|
||||
ba.app.handle_deep_link, # kDeepLinkCall
|
||||
_lang.get_resource, # kGetResourceCall
|
||||
_lang.translate, # kTranslateCall
|
||||
ba.Lstr, # kLStrClass
|
||||
ba.Call, # kCallClass
|
||||
_apputils.garbage_collect, # kGarbageCollectCall
|
||||
ba.ContextError, # kContextError
|
||||
ba.NotFoundError, # kNotFoundError
|
||||
ba.NodeNotFoundError, # kNodeNotFoundError
|
||||
ba.SessionTeamNotFoundError, # kSessionTeamNotFoundError
|
||||
ba.InputDeviceNotFoundError, # kInputDeviceNotFoundError
|
||||
ba.DelegateNotFoundError, # kDelegateNotFoundError
|
||||
ba.SessionPlayerNotFoundError, # kSessionPlayerNotFoundError
|
||||
ba.WidgetNotFoundError, # kWidgetNotFoundError
|
||||
ba.ActivityNotFoundError, # kActivityNotFoundError
|
||||
ba.SessionNotFoundError, # kSessionNotFoundError
|
||||
_dependency.AssetPackage, # kAssetPackageClass
|
||||
_enums.TimeFormat, # kTimeFormatClass
|
||||
_enums.TimeType, # kTimeTypeClass
|
||||
_enums.InputType, # kInputTypeClass
|
||||
_enums.Permission, # kPermissionClass
|
||||
_enums.SpecialChar, # kSpecialCharClass
|
||||
_player.Player, # kPlayerClass
|
||||
_hooks.get_player_icon, # kGetPlayerIconCall
|
||||
_lang.Lstr.from_json, # kLstrFromJsonCall
|
||||
) # yapf: disable
|
||||
147
src/generated_src/ballistica/bootstrap.py
Normal file
147
src/generated_src/ballistica/bootstrap.py
Normal file
@ -0,0 +1,147 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
"""Initial ba bootstrapping."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, TextIO, Callable, List
|
||||
|
||||
|
||||
def _ballistica_bootstrap() -> object:
|
||||
import sys
|
||||
import signal
|
||||
import _ba
|
||||
import threading
|
||||
|
||||
class _BAConsoleRedirect:
|
||||
|
||||
def __init__(self, original: TextIO, call: Callable[[str],
|
||||
None]) -> None:
|
||||
self._lock = threading.Lock()
|
||||
self._linebits: List[str] = []
|
||||
self._original = original
|
||||
self._call = call
|
||||
self._pending_ship = False
|
||||
|
||||
def write(self, sval: Any) -> None:
|
||||
"""Override standard stdout write."""
|
||||
|
||||
self._call(sval)
|
||||
|
||||
# Now do logging:
|
||||
# Add it to our accumulated line.
|
||||
# If the message ends in a newline, we can ship it
|
||||
# immediately as a log entry. Otherwise, schedule a ship
|
||||
# next cycle (if it hasn't yet at that point) so that we
|
||||
# can accumulate subsequent prints.
|
||||
# (so stuff like print('foo', 123, 'bar') will ship as one entry)
|
||||
with self._lock:
|
||||
self._linebits.append(sval)
|
||||
if sval.endswith('\n'):
|
||||
self._shiplog()
|
||||
else:
|
||||
_ba.pushcall(self._shiplog,
|
||||
from_other_thread=True,
|
||||
suppress_other_thread_warning=True)
|
||||
|
||||
def _shiplog(self) -> None:
|
||||
with self._lock:
|
||||
line = ''.join(self._linebits)
|
||||
if not line:
|
||||
return
|
||||
self._linebits = []
|
||||
|
||||
# Log messages aren't expected to have trailing newlines.
|
||||
if line.endswith('\n'):
|
||||
line = line[:-1]
|
||||
_ba.log(line, to_stdout=False)
|
||||
|
||||
def flush(self) -> None:
|
||||
"""Flush the file."""
|
||||
self._original.flush()
|
||||
|
||||
def isatty(self) -> bool:
|
||||
"""Are we a terminal?"""
|
||||
return self._original.isatty()
|
||||
|
||||
sys.stdout = _BAConsoleRedirect( # type: ignore
|
||||
sys.stdout, _ba.print_stdout)
|
||||
sys.stderr = _BAConsoleRedirect( # type: ignore
|
||||
sys.stderr, _ba.print_stderr)
|
||||
|
||||
# Let's lookup mods first (so users can do whatever they want).
|
||||
# and then our bundled scripts last (don't want to encourage dists
|
||||
# overriding proper python functionality)
|
||||
sys.path.insert(0, _ba.env()['python_directory_user'])
|
||||
sys.path.append(_ba.env()['python_directory_app'])
|
||||
sys.path.append(_ba.env()['python_directory_app_site'])
|
||||
|
||||
# Tell Python to not handle SIGINT itself (it normally generates
|
||||
# KeyboardInterrupts which make a mess; we want to do a simple
|
||||
# clean exit). We capture interrupts per-platform in the C++ layer.
|
||||
# I tried creating a handler in Python but it seemed to often have
|
||||
# a delay of up to a second before getting called. (not a huge deal
|
||||
# but I'm picky).
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL) # Do default handling.
|
||||
|
||||
# ..though it turns out we need to set up our C signal handling AFTER
|
||||
# we've told Python to disable its own; otherwise (on Mac at least) it
|
||||
# wipes out our existing C handler.
|
||||
_ba.setup_sigint()
|
||||
|
||||
# Sanity check: we should always be run in UTF-8 mode.
|
||||
if sys.flags.utf8_mode != 1:
|
||||
print('ERROR: Python\'s UTF-8 mode is not set.'
|
||||
' This will likely result in errors.')
|
||||
|
||||
# FIXME: I think we should init Python in the main thread, which should
|
||||
# also avoid these issues. (and also might help us play better with
|
||||
# Python debuggers?)
|
||||
|
||||
# Gloriously hacky workaround here:
|
||||
# Our 'main' Python thread is the game thread (not the app's main
|
||||
# thread) which means it has a small stack compared to the main
|
||||
# thread (at least on apple). Sadly it turns out this causes the
|
||||
# debug build of Python to blow its stack immediately when doing
|
||||
# some big imports.
|
||||
# Normally we'd just give the game thread the same stack size as
|
||||
# the main thread and that'd be the end of it. However
|
||||
# we're using std::threads which it turns out have no way to set
|
||||
# the stack size (as of fall '19). Grumble.
|
||||
#
|
||||
# However python threads *can* take custom stack sizes.
|
||||
# (and it appears they might use the main thread's by default?..)
|
||||
# ...so as a workaround in the debug version, we can run problematic
|
||||
# heavy imports here in another thread and all is well.
|
||||
# If we ever see stack overflows in our release build we'll have
|
||||
# to take more drastic measures like switching from std::threads
|
||||
# to pthreads.
|
||||
|
||||
if _ba.env()['debug_build']:
|
||||
|
||||
def _thread_func() -> None:
|
||||
# pylint: disable=unused-import
|
||||
import json
|
||||
import urllib.request
|
||||
|
||||
testthread = threading.Thread(target=_thread_func)
|
||||
testthread.start()
|
||||
testthread.join()
|
||||
|
||||
# Now spin up our App instance, store it on both _ba and ba,
|
||||
# and return it to the C++ layer.
|
||||
# noinspection PyProtectedMember
|
||||
from ba._app import App
|
||||
import ba
|
||||
app = App()
|
||||
_ba.app = app
|
||||
ba.app = app
|
||||
return app
|
||||
|
||||
|
||||
_app_state = _ballistica_bootstrap()
|
||||
|
||||
# This code runs in the main namespace, so clean up after ourself.
|
||||
del _ballistica_bootstrap, TYPE_CHECKING
|
||||
@ -16,7 +16,7 @@ from efro.error import CleanError
|
||||
from efro.terminal import Clr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import List, Sequence, Optional, Any
|
||||
from typing import List, Sequence, Optional, Any, Dict
|
||||
|
||||
|
||||
# Python pip packages we require for this project.
|
||||
@ -710,3 +710,61 @@ def update_docs_md(check: bool) -> None:
|
||||
with open(docs_hash_path, 'w') as outfile:
|
||||
outfile.write(curhash)
|
||||
print(f'{docs_path} is up to date.')
|
||||
|
||||
|
||||
def cmake_prep_dir(dirname: str) -> None:
|
||||
"""Create a dir, recreating it when cmake/python/etc. version changes.
|
||||
|
||||
Useful to prevent builds from breaking when cmake or other components
|
||||
are updated.
|
||||
"""
|
||||
import json
|
||||
from efrotools import PYVER
|
||||
verfilename = os.path.join(dirname, '.ba_cmake_env')
|
||||
|
||||
versions: Dict[str, str]
|
||||
if os.path.isfile(verfilename):
|
||||
with open(verfilename) as infile:
|
||||
versions = json.loads(infile.read())
|
||||
assert isinstance(versions, dict)
|
||||
else:
|
||||
versions = {}
|
||||
|
||||
# Get version of installed cmake.
|
||||
cmake_ver_output = subprocess.run(['cmake', '--version'],
|
||||
check=True,
|
||||
capture_output=True).stdout.decode()
|
||||
cmake_ver = cmake_ver_output.splitlines()[0].split('cmake version ')[1]
|
||||
|
||||
cmake_ver_existing = versions.get('cmake')
|
||||
assert isinstance(cmake_ver_existing, (str, type(None)))
|
||||
|
||||
# Get specific version of our target python.
|
||||
python_ver_output = subprocess.run([f'python{PYVER}', '--version'],
|
||||
check=True,
|
||||
capture_output=True).stdout.decode()
|
||||
python_ver = python_ver_output.splitlines()[0].split('Python ')[1]
|
||||
|
||||
python_ver_existing = versions.get('python')
|
||||
assert isinstance(python_ver_existing, (str, type(None)))
|
||||
|
||||
# If they don't match, blow away the dir and write the current version.
|
||||
if cmake_ver_existing != cmake_ver or python_ver_existing != python_ver:
|
||||
if (cmake_ver_existing != cmake_ver
|
||||
and cmake_ver_existing is not None):
|
||||
print(f'{Clr.BLU}CMake version changed from {cmake_ver_existing}'
|
||||
f' to {cmake_ver}; clearing existing build at'
|
||||
f' "{dirname}".{Clr.RST}')
|
||||
if (python_ver_existing != python_ver
|
||||
and python_ver_existing is not None):
|
||||
print(f'{Clr.BLU}Python version changed from {python_ver_existing}'
|
||||
f' to {python_ver}; clearing existing build at'
|
||||
f' "{dirname}".{Clr.RST}')
|
||||
subprocess.run(['rm', '-rf', dirname], check=True)
|
||||
os.makedirs(dirname, exist_ok=True)
|
||||
with open(verfilename, 'w') as outfile:
|
||||
outfile.write(
|
||||
json.dumps({
|
||||
'cmake': cmake_ver,
|
||||
'python': python_ver
|
||||
}))
|
||||
|
||||
109
tools/batools/codegen.py
Normal file
109
tools/batools/codegen.py
Normal file
@ -0,0 +1,109 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Functionality related to code generation."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import json
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import List, Sequence, Optional, Any, Dict
|
||||
|
||||
|
||||
def gen_flat_data_code(projroot: str, in_path: str, out_path: str,
|
||||
var_name: str) -> None:
|
||||
"""Generate a C++ include file from a Python file."""
|
||||
|
||||
out_dir = os.path.dirname(out_path)
|
||||
if not os.path.exists(out_dir):
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
with open(in_path, 'rb') as infileb:
|
||||
svalin = infileb.read()
|
||||
|
||||
# JSON should do the trick for us here as far as char escaping/etc.
|
||||
# There's corner cases where it can differ from C strings but in this
|
||||
# simple case we shouldn't run into them.
|
||||
sval_out = f'const char* {var_name} ='
|
||||
|
||||
# Store in ballistica's simple xor encryption to at least
|
||||
# slightly slow down hackers.
|
||||
sval = svalin
|
||||
|
||||
sval1: Optional[bytes]
|
||||
sval1 = sval
|
||||
while sval1:
|
||||
sval_out += ' ' + json.dumps(sval1[:1000].decode())
|
||||
sval1 = sval1[1000:]
|
||||
sval_out += ';\n'
|
||||
|
||||
pretty_path = os.path.abspath(out_path)
|
||||
if pretty_path.startswith(projroot + '/'):
|
||||
pretty_path = pretty_path[len(projroot) + 1:]
|
||||
print(f'Generating code: {pretty_path}')
|
||||
with open(out_path, 'w') as outfile:
|
||||
outfile.write(sval_out)
|
||||
|
||||
|
||||
def gen_binding_code(projroot: str, in_path: str, out_path: str) -> None:
|
||||
"""Generate binding.inc file."""
|
||||
|
||||
out_dir = os.path.dirname(out_path)
|
||||
if not os.path.exists(out_dir):
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
# Pull all lines in the embedded list and split into py and c++ names.
|
||||
with open(in_path) as infile:
|
||||
pycode = infile.read()
|
||||
|
||||
# Double quotes causes errors.
|
||||
if '"' in pycode:
|
||||
raise Exception('bindings file can\'t contain double quotes.')
|
||||
lines = [
|
||||
l.strip().split(', # ') for l in pycode.splitlines()
|
||||
if l.startswith(' ')
|
||||
]
|
||||
if not all(len(l) == 2 for l in lines):
|
||||
raise Exception('malformatted data')
|
||||
|
||||
# Our C++ code first execs our input as a string.
|
||||
ccode = ('{const char* bindcode = ' + repr(pycode).replace("'", '"') + ';')
|
||||
ccode += ('\nint result = PyRun_SimpleString(bindcode);\n'
|
||||
'if (result != 0) {\n'
|
||||
' PyErr_PrintEx(0);\n'
|
||||
' // Use a standard error to avoid a useless stack trace.\n'
|
||||
' throw std::logic_error("Error fetching required Python'
|
||||
' objects.");\n'
|
||||
'}\n')
|
||||
|
||||
# Then it grabs the function that was defined and runs it.
|
||||
ccode += ('PyObject* bindvals = PythonCommand("get_binding_values()",'
|
||||
' "<get_binding_values>")'
|
||||
'.RunReturnObj(true);\n'
|
||||
'if (bindvals == nullptr) {\n'
|
||||
' // Use a standard error to avoid a useless stack trace.\n'
|
||||
' throw std::logic_error("Error binding required Python'
|
||||
' objects.");\n'
|
||||
'}\n')
|
||||
|
||||
# Then it pulls the individual values out of the returned tuple.
|
||||
for i, line in enumerate(lines):
|
||||
ccode += ('SetObjCallable(ObjID::' + line[1] +
|
||||
', PyTuple_GET_ITEM(bindvals, ' + str(i) + '), true);\n')
|
||||
|
||||
# Lastly it cleans up after itself.
|
||||
ccode += ('result = PyRun_SimpleString("del get_binding_values");\n'
|
||||
'if (result != 0) {\n'
|
||||
' PyErr_PrintEx(0);\n'
|
||||
' // Use a standard error to avoid a useless stack trace.\n'
|
||||
' throw std::logic_error("Error cleaning up after Python'
|
||||
' binding.");\n'
|
||||
'}\n'
|
||||
'}\n')
|
||||
pretty_path = os.path.abspath(out_path)
|
||||
if pretty_path.startswith(projroot + '/'):
|
||||
pretty_path = pretty_path[len(projroot) + 1:]
|
||||
print('Generating code: ' + pretty_path)
|
||||
with open(out_path, 'w') as outfile:
|
||||
outfile.write(ccode)
|
||||
@ -731,63 +731,33 @@ def cmake_prep_dir() -> None:
|
||||
Useful to prevent builds from breaking when cmake or other components
|
||||
are updated.
|
||||
"""
|
||||
# pylint: disable=too-many-locals
|
||||
import os
|
||||
import subprocess
|
||||
import json
|
||||
from efro.error import CleanError
|
||||
from efro.terminal import Clr
|
||||
from efrotools import PYVER
|
||||
import batools.build
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
raise CleanError('Expected 1 arg (dir name)')
|
||||
dirname = sys.argv[2]
|
||||
batools.build.cmake_prep_dir(dirname)
|
||||
|
||||
verfilename = os.path.join(dirname, '.ba_cmake_env')
|
||||
|
||||
versions: Dict[str, str]
|
||||
if os.path.isfile(verfilename):
|
||||
with open(verfilename) as infile:
|
||||
versions = json.loads(infile.read())
|
||||
assert isinstance(versions, dict)
|
||||
else:
|
||||
versions = {}
|
||||
def gen_binding_code() -> None:
|
||||
"""Generate binding.inc file."""
|
||||
from efro.error import CleanError
|
||||
import batools.codegen
|
||||
if len(sys.argv) != 4:
|
||||
raise CleanError('Expected 2 args (srcfile, dstfile)')
|
||||
inpath = sys.argv[2]
|
||||
outpath = sys.argv[3]
|
||||
batools.codegen.gen_binding_code(str(PROJROOT), inpath, outpath)
|
||||
|
||||
# Get version of installed cmake.
|
||||
cmake_ver_output = subprocess.run(['cmake', '--version'],
|
||||
check=True,
|
||||
capture_output=True).stdout.decode()
|
||||
cmake_ver = cmake_ver_output.splitlines()[0].split('cmake version ')[1]
|
||||
|
||||
cmake_ver_existing = versions.get('cmake')
|
||||
assert isinstance(cmake_ver_existing, (str, type(None)))
|
||||
|
||||
# Get specific version of our target python.
|
||||
python_ver_output = subprocess.run([f'python{PYVER}', '--version'],
|
||||
check=True,
|
||||
capture_output=True).stdout.decode()
|
||||
python_ver = python_ver_output.splitlines()[0].split('Python ')[1]
|
||||
|
||||
python_ver_existing = versions.get('python')
|
||||
assert isinstance(python_ver_existing, (str, type(None)))
|
||||
|
||||
# If they don't match, blow away the dir and write the current version.
|
||||
if cmake_ver_existing != cmake_ver or python_ver_existing != python_ver:
|
||||
if (cmake_ver_existing != cmake_ver
|
||||
and cmake_ver_existing is not None):
|
||||
print(f'{Clr.BLU}CMake version changed from {cmake_ver_existing}'
|
||||
f' to {cmake_ver}; clearing existing build at'
|
||||
f' "{dirname}".{Clr.RST}')
|
||||
if (python_ver_existing != python_ver
|
||||
and python_ver_existing is not None):
|
||||
print(f'{Clr.BLU}Python version changed from {python_ver_existing}'
|
||||
f' to {python_ver}; clearing existing build at'
|
||||
f' "{dirname}".{Clr.RST}')
|
||||
subprocess.run(['rm', '-rf', dirname], check=True)
|
||||
os.makedirs(dirname, exist_ok=True)
|
||||
with open(verfilename, 'w') as outfile:
|
||||
outfile.write(
|
||||
json.dumps({
|
||||
'cmake': cmake_ver,
|
||||
'python': python_ver
|
||||
}))
|
||||
def gen_flat_data_code() -> None:
|
||||
"""Generate a C++ include file from a Python file."""
|
||||
from efro.error import CleanError
|
||||
import batools.codegen
|
||||
if len(sys.argv) != 5:
|
||||
raise CleanError('Expected 3 args (srcfile, dstfile, varname)')
|
||||
inpath = sys.argv[2]
|
||||
outpath = sys.argv[3]
|
||||
varname = sys.argv[4]
|
||||
batools.codegen.gen_flat_data_code(str(PROJROOT), inpath, outpath, varname)
|
||||
|
||||
@ -38,7 +38,7 @@ from batools.pcommand import (
|
||||
prefab_run_var, make_prefab, update_makebob, lazybuild,
|
||||
android_archive_unstripped_libs, efro_gradle, stage_assets,
|
||||
update_assets_makefile, update_project, update_cmake_prefab_lib,
|
||||
cmake_prep_dir)
|
||||
cmake_prep_dir, gen_binding_code, gen_flat_data_code)
|
||||
# pylint: enable=unused-import
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user