getting make spinoff-test-base working

This commit is contained in:
Eric 2023-06-02 22:00:25 -07:00
parent 91cfa632c8
commit 4ae76a45f6
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
20 changed files with 417 additions and 151 deletions

View File

@ -4072,26 +4072,26 @@
"build/assets/workspace/ninjafightplug.py": "https://files.ballistica.net/cache/ba1/c5/09/4f10b8a21ba87aa5509cff7a164b",
"build/assets/workspace/onslaughtplug.py": "https://files.ballistica.net/cache/ba1/ff/0a/a354984f9c074dab0676ac7e4877",
"build/assets/workspace/runaroundplug.py": "https://files.ballistica.net/cache/ba1/2a/1c/9ee5db6d1bceca7fa6638fb8abde",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/4f/46/80f41faa8a51075c2472d7429b77",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/30/cb/93ac10daaf9475d01f5d1064d358",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/34/4e/e2bf216edcd7d6a9a1bee3b55b69",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/5e/2b/c22b17ffa90f65bc906ae9e477d6",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/cf/ac/1485911ed48dac0c430b18687917",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/0d/99/2b9a15fa962b5ea354f8de27fe6c",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/03/e1/e795c72de227173711da1a162632",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/80/26/b82964ce5a5bb8509ca6d7516b71",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/2e/c8/67482dedb186c9dbca2dc66f7699",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/18/fa/c42a603705d7453279689706d2ee",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/bc/d2/89526b59dee86888c628028a406c",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/1d/e5/7425978a2c0112a46192a76563ce",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/ff/cd/21d36a06bbc2322d8e944f392ef0",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/97/ee/e2c3b4a6ee9abb170bd98f38c7de",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/be/13/229e4c027d0ca4b037dbf67134bd",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/53/bb/acf5f4b58a156c53e6ff8f0b58ad",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/f3/d7/426c5cd3ec71438a98474f39ba2c",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/90/79/74d6111711d655963a1e9a2728c5",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/c1/f7/95ff199637a86fe138309e3a5275",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/61/f0/9447fe7637ed96ce1840aa277271",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/b0/77/0fb608a5a11844433c94237b80fd",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/6b/37/9122b03565ee2d08d9fc6d30a221",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/a4/11/0f7c0fe6af5d5e46795f33b53f8e",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/59/f4/7e5d155abb264a76b633d6f4225f",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/dc/0a/131caf082f3877e5878ae349746d",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/fb/46/34eada1e570cce2107cb55a033e8",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/1d/3e/be779b3740cda2a7d98418d4007a",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/18/b7/4389f6000decbcde1044180b134a",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/4a/91/2c3bf6cca0baecc16138db7fe7ff",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/01/b4/31635bc46cbda94cc73fc019d28c",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/13/3d/50286e4d2fe1fc7507ba20b45ca2",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/d7/17/7f186bd856ea7bd18b2fc8d64639",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/b9/63/640aa2e767450800ff481c51b665",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/19/ca/ae8153fb5fd0ea1045d386c31134",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/70/e8/796d18c51690f54efcb3df22c048",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/e2/8a/0ae529b92bcf4afe5d1c9c797e96",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/a3/d7/f415b115cd0e348be8aa75e28101",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/58/77/7244f67e35fcb0ab4047d5cc6f5e",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/91/de/bef5f0a5b9a0c6d50f4e2922a959",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/75/a5/42ad0f7c2944b1033e5b12395743",
"build/prefab/lib/linux_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/d4/6a/dd303a200b98a56ba3b100277057",
"build/prefab/lib/linux_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/fc/2c/2996c558fb408a548fdd37398c9a",
"build/prefab/lib/linux_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/ed/28/b7a72be7ae1bd2b58dda4b6902a0",
@ -4108,14 +4108,14 @@
"build/prefab/lib/mac_x86_64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/71/f6/691482915ad58ea1e953cc23d74c",
"build/prefab/lib/mac_x86_64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/b8/2b/6ec8c78980a62e3e0ee4b36ece04",
"build/prefab/lib/mac_x86_64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/4e/56/a95c987b2a371759896b037fea86",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/2d/55/0b7f8677e535082c9224259aa9d7",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/63/2f/b4b402d2f3a47dad74a077db036c",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/b6/e4/fffa1b46696ecc804b5a66896359",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/ca/70/e5eec4f437e387d61ceba7f9fffe",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/47/8c/0142dfbee4871619a8d404898eef",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/f8/d9/9facb83ac8c0ef39c97c3211ebd2",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/4d/90/79a005d72aa7a4277d06571dcdb5",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/ff/3a/e319ce586b9cb93ac29282569184",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/60/31/7c82d61f768515a6f5f8f20a967b",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/ba/38/d98a316972f47a5509be6ab28a96",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/a5/8d/8120340f79d9f9244013ef24c9da",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/84/47/90ccac6eb182c16a973855a160ee",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/5f/7b/ea3d74c27c2272084b459814986f",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/f6/a9/a780cd9b23e680a9f5cc87e5ac21",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/8c/9e/3902170e5e8662ec1fccc720ed48",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/c9/d4/5fa5dc68d04b906ef22a10eae5ae",
"src/assets/ba_data/python/babase/_mgen/__init__.py": "https://files.ballistica.net/cache/ba1/52/c6/c11130af7b10d6c0321add5518fa",
"src/assets/ba_data/python/babase/_mgen/enums.py": "https://files.ballistica.net/cache/ba1/38/c3/1dedd5e74f2508efc5974c8815a1",
"src/ballistica/base/mgen/pyembed/binding_base.inc": "https://files.ballistica.net/cache/ba1/d5/4a/0e480a855ce83709bd7f6761107d",

View File

@ -1,4 +1,4 @@
### 1.7.20 (build 21041, api 8, 2023-06-02)
### 1.7.20 (build 21042, api 8, 2023-06-02)
- This seems like a good time for a `refactoring` release in anticipation of
changes coming in 1.8. Basically this means that a lot of things will be

View File

@ -13,3 +13,5 @@ from batools.featureset import FeatureSet
fset = FeatureSet.get_active()
fset.requirements = {'core'}
fset.soft_requirements = {'classic', 'plus'}

View File

@ -13,3 +13,9 @@ from batools.featureset import FeatureSet
fset = FeatureSet.get_active()
fset.requirements = {'base', 'scene_v1', 'ui_v1'}
# We provide 'babase.app.classic'.
fset.has_python_app_subsystem = True
# We want things to work without us.
fset.allow_as_soft_requirement = True

View File

@ -14,3 +14,9 @@ fset = FeatureSet.get_active()
fset.requirements = {'base'}
fset.internal = True
# We provide 'babase.app.plus'.
fset.has_python_app_subsystem = True
# We want things to work without us.
fset.allow_as_soft_requirement = True

View File

@ -98,13 +98,27 @@ ctx.src_unchecked_paths = {
'ballisticakit-android/BallisticaKit/src/*/assets',
}
# Files at or under these paths are considered 'project' files.
# Paths/names/suffixes we consider 'project' files.
# These files are synced after all other files and go through
# batools.project.Updater class as part of their filtering.
# This allows them to update themselves in the same way as they
# do when running 'make update' for the project; adding the final
# filtered set of project source files to themself, etc.
ctx.project_file_paths = set()
ctx.project_file_paths = {'src/assets/ba_data/python/babase/_app.py'}
ctx.project_file_names = {
'Makefile',
'CMakeLists.txt',
'.meta_manifest_public.json',
'.meta_manifest_private.json',
'.asset_manifest_public.json',
'.asset_manifest_private.json',
}
ctx.project_file_suffixes = {
'.vcxproj',
'.vcxproj.filters',
'.pbxproj',
}
# Everything actually synced into dst will use the following filter rules:

View File

@ -33,12 +33,13 @@ if TYPE_CHECKING:
from babase._appintent import AppIntent
from babase._appmode import AppMode
# WOULD-AUTOGEN-BEGIN
# __FEATURESET_APP_SUBSYSTEM_IMPORTS_BEGIN__
# This section autogenerated by project-update.
from baclassic import ClassicSubsystem
from baplus import PlusSubsystem
# WOULD-AUTOGEN-END
# __FEATURESET_APP_SUBSYSTEM_IMPORTS_END__
class App:
@ -301,18 +302,6 @@ class App:
# some of this stuff might try importing babase.app and that doesn't
# exist yet as of our __init__() call.
# Init classic if present.
# classic_subsystem_type: type[ClassicSubsystem] | None
# try:
# from baclassic import ClassicSubsystem
# classic_subsystem_type = ClassicSubsystem
# except ImportError:
# classic_subsystem_type = None
# if classic_subsystem_type is not None:
# self._classic = classic_subsystem_type()
def _threadpool_no_wait_done(self, fut: Future) -> None:
try:
fut.result()
@ -330,7 +319,8 @@ class App:
fut = self.threadpool.submit(call)
fut.add_done_callback(self._threadpool_no_wait_done)
# WOULD-AUTOGEN-BEGIN
# __FEATURESET_APP_SUBSYSTEM_PROPERTIES_BEGIN__
# This section autogenerated by project-update.
@cached_property
def classic(self) -> ClassicSubsystem | None:
@ -343,7 +333,7 @@ class App:
except ImportError:
return None
except Exception:
logging.exception('Error importing baclassic')
logging.exception('Error importing baclassic.')
return None
@cached_property
@ -357,10 +347,10 @@ class App:
except ImportError:
return None
except Exception:
logging.exception('Error importing baplus')
logging.exception('Error importing baplus.')
return None
# WOULD-AUTOGEN-END
# __FEATURESET_APP_SUBSYSTEM_PROPERTIES_END__
def set_intent(self, intent: AppIntent) -> None:
"""Set the intent for the app.
@ -514,13 +504,14 @@ class App:
"""Decides which app modes to use to handle intents."""
def app_mode_for_intent(self, intent: AppIntent) -> type[AppMode]:
# WOULD-AUTOGEN-BEGIN
# __DEFAULT_APP_MODE_SELECTION_BEGIN__
# This section autogenerated by project-update.
import bascenev1
return bascenev1.SceneV1AppMode
# WOULD-AUTOGEN-END
# __DEFAULT_APP_MODE_SELECTION_END__
def on_app_running(self) -> None:
"""Called when initially entering the running state."""

View File

@ -30,7 +30,7 @@ if TYPE_CHECKING:
# Build number and version of the ballistica binary we expect to be
# using.
TARGET_BALLISTICA_BUILD = 21041
TARGET_BALLISTICA_BUILD = 21042
TARGET_BALLISTICA_VERSION = '1.7.20'
_g_env_config: EnvConfig | None = None

View File

@ -37,6 +37,7 @@ class UIV1SoftInterface {
virtual void OnLanguageChange() = 0;
virtual auto GetRootWidget() -> ui_v1::Widget* = 0;
virtual auto SendWidgetMessage(const WidgetMessage& m) -> int = 0;
virtual void ApplyAppConfig() = 0;
};
} // namespace ballistica::base

View File

@ -8,12 +8,10 @@
#include "ballistica/base/input/input.h"
#include "ballistica/base/logic/logic.h"
#include "ballistica/base/python/base_python.h"
#include "ballistica/base/support/ui_v1_soft.h"
#include "ballistica/base/ui/console.h"
#include "ballistica/shared/foundation/event_loop.h"
#include "ballistica/shared/generic/utils.h"
#include "ballistica/ui_v1/widget/root_widget.h"
#include "ballistica/ui_v1/widget/stack_widget.h"
#include "ballistica/ui_v1/widget/text_widget.h"
namespace ballistica::base {
@ -87,9 +85,9 @@ void UI::OnAppShutdown() { assert(g_base->InLogicThread()); }
void UI::ApplyAppConfig() {
assert(g_base->InLogicThread());
ui_v1::TextWidget::set_always_use_internal_keyboard(
g_base->app_config->Resolve(
AppConfig::BoolID::kAlwaysUseInternalKeyboard));
if (g_base->HaveUIV1()) {
g_base->ui_v1()->ApplyAppConfig();
}
}
auto UI::MainMenuVisible() const -> bool {
@ -227,16 +225,6 @@ auto UI::SendWidgetMessage(const WidgetMessage& m) -> int {
return false;
}
void UI::DeleteWidget(ui_v1::Widget* widget) {
assert(widget);
if (widget) {
ui_v1::ContainerWidget* parent = widget->parent_widget();
if (parent) {
parent->DeleteWidget(widget);
}
}
}
void UI::OnScreenSizeChange() {
if (g_base->HaveUIV1()) {
g_base->ui_v1()->OnScreenSizeChange();

View File

@ -84,9 +84,6 @@ class UI {
// Send message to the active widget.
auto SendWidgetMessage(const WidgetMessage& msg) -> int;
// Use this to destroy any named widget (even those in containers).
void DeleteWidget(ui_v1::Widget* widget);
void SetUIInputDevice(InputDevice* input_device);
// Returns the input-device that currently owns the menu; otherwise nullptr.

View File

@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
namespace ballistica {
// These are set automatically via script; don't modify them here.
const int kEngineBuildNumber = 21041;
const int kEngineBuildNumber = 21042;
const char* kEngineVersion = "1.7.20";
auto MonolithicMain(const core::CoreConfig& core_config) -> int {

View File

@ -2,6 +2,7 @@
#include "ballistica/ui_v1/ui_v1.h"
#include "ballistica/base/app/app_config.h"
#include "ballistica/base/app/app_mode.h"
#include "ballistica/base/graphics/component/empty_component.h"
#include "ballistica/base/graphics/graphics.h"
@ -12,6 +13,7 @@
#include "ballistica/ui_v1/widget/container_widget.h"
#include "ballistica/ui_v1/widget/root_widget.h"
#include "ballistica/ui_v1/widget/stack_widget.h"
#include "ballistica/ui_v1/widget/text_widget.h"
namespace ballistica::ui_v1 {
@ -74,7 +76,7 @@ void UIV1FeatureSet::DoHandleDeviceMenuPress(base::InputDevice* device) {
void UIV1FeatureSet::DoShowURL(const std::string& url) { python->ShowURL(url); }
void UIV1FeatureSet::DoQuitWindow() {
g_ui_v1->python->objs().Get(ui_v1::UIV1Python::ObjID::kQuitWindowCall).Call();
g_ui_v1->python->objs().Get(UIV1Python::ObjID::kQuitWindowCall).Call();
}
RootUI* UIV1FeatureSet::NewRootUI() { return new RootUI(); }
@ -195,7 +197,7 @@ void UIV1FeatureSet::Reset() {
screen_root_widget_.Clear();
// (Re)create our screen-root widget.
auto sw(Object::New<ui_v1::StackWidget>());
auto sw(Object::New<StackWidget>());
sw->set_is_main_window_stack(true);
sw->SetWidth(g_base->graphics->screen_virtual_width());
sw->SetHeight(g_base->graphics->screen_virtual_height());
@ -203,7 +205,7 @@ void UIV1FeatureSet::Reset() {
screen_root_widget_ = sw;
// (Re)create our screen-overlay widget.
auto ow(Object::New<ui_v1::StackWidget>());
auto ow(Object::New<StackWidget>());
ow->set_is_overlay_window_stack(true);
ow->SetWidth(g_base->graphics->screen_virtual_width());
ow->SetHeight(g_base->graphics->screen_virtual_height());
@ -211,7 +213,7 @@ void UIV1FeatureSet::Reset() {
overlay_root_widget_ = ow;
// (Re)create our abs-root widget.
auto rw(Object::New<ui_v1::RootWidget>());
auto rw(Object::New<RootWidget>());
root_widget_ = rw;
rw->SetWidth(g_base->graphics->screen_virtual_width());
rw->SetHeight(g_base->graphics->screen_virtual_height());
@ -267,4 +269,19 @@ auto UIV1FeatureSet::SendWidgetMessage(const base::WidgetMessage& m) -> int {
return root_widget_->HandleMessage(m);
}
void UIV1FeatureSet::DeleteWidget(Widget* widget) {
assert(widget);
if (widget) {
ContainerWidget* parent = widget->parent_widget();
if (parent) {
parent->DeleteWidget(widget);
}
}
}
void UIV1FeatureSet::ApplyAppConfig() {
TextWidget::set_always_use_internal_keyboard(g_base->app_config->Resolve(
base::AppConfig::BoolID::kAlwaysUseInternalKeyboard));
}
} // namespace ballistica::ui_v1

View File

@ -95,10 +95,13 @@ class UIV1FeatureSet : public FeatureSetNativeComponent,
// If a parent is provided, the widget is added to it; otherwise it is added
// to the root widget.
void AddWidget(Widget* w, ContainerWidget* to);
void DeleteWidget(Widget* widget);
void OnScreenSizeChange() override;
void OnLanguageChange() override;
auto GetRootWidget() -> ui_v1::Widget* override;
auto SendWidgetMessage(const base::WidgetMessage& m) -> int override;
void ApplyAppConfig() override;
private:
UIV1FeatureSet();

View File

@ -820,7 +820,9 @@ void ContainerWidget::Draw(base::RenderPass* pass, bool draw_transparent) {
Object::WeakRef<Widget> weakref(this);
g_base->logic->event_loop()->PushCall([weakref] {
Widget* w = weakref.Get();
if (w) g_base->ui->DeleteWidget(w);
if (w) {
g_ui_v1->DeleteWidget(w);
}
});
return;
}
@ -875,7 +877,9 @@ void ContainerWidget::Draw(base::RenderPass* pass, bool draw_transparent) {
Object::WeakRef<Widget> weakref(this);
g_base->logic->event_loop()->PushCall([weakref] {
Widget* w = weakref.Get();
if (w) g_base->ui->DeleteWidget(w);
if (w) {
g_ui_v1->DeleteWidget(w);
}
});
return;
}

View File

@ -57,6 +57,7 @@ def _get_targets(
def _get_py_targets(
projroot: str,
meta_manifests: dict[str, str],
explicit_sources: set[str],
src: str,
dst: str,
py_targets: list[str],
@ -66,14 +67,17 @@ def _get_py_targets(
) -> None:
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
# pylint: disable=too-many-statements
py_generated_root = f'{ASSETS_SRC}/ba_data/python/babase/_mgen'
def _do_get_targets(proot: str, fnames: list[str]) -> None:
def _do_get_targets(
proot: str, fnames: list[str], is_explicit: bool = False
) -> None:
# Special case: ignore temp py files in data src.
if proot == f'{ASSETS_SRC}/ba_data/data/maps':
return
assert proot.startswith(src)
assert proot.startswith(src), f'{proot} does not start with {src}'
assert dst.startswith(BUILD_DIR)
dstrootvar = (
'$(BUILD_DIR)'
@ -90,6 +94,16 @@ def _get_py_targets(
):
continue
# Ignore any files in the list of explicit sources we got;
# we explicitly add those at the end and don't want to do it
# twice (since we don't know if this one will always exist
# anyway).
if (
os.path.join(proot, fname) in explicit_sources
and not is_explicit
):
continue
if proot.startswith(f'{ASSETS_SRC}/ba_data/python-site-packages'):
in_subset = 'private-common'
elif proot.startswith(f'{ASSETS_SRC}/ba_data') or proot.startswith(
@ -122,7 +136,9 @@ def _get_py_targets(
# gamedata pass includes only data; otherwise do all else
# .py:
all_targets.add(os.path.join(dstfin, fname))
targetpath = os.path.join(dstfin, fname)
assert targetpath not in all_targets
all_targets.add(targetpath)
py_targets.append(os.path.join(dstrootvar, fname))
# and .pyc:
@ -173,14 +189,25 @@ def _get_py_targets(
proot=os.path.dirname(target), fnames=[os.path.basename(target)]
)
# Now create targets for any explicitly passed paths.
for expsrc in explicit_sources:
if expsrc.startswith(f'{src}/'):
_do_get_targets(
proot=os.path.dirname(expsrc),
fnames=[os.path.basename(expsrc)],
is_explicit=True,
)
def _get_py_targets_subset(
projroot: str,
meta_manifests: dict[str, str],
explicit_sources: set[str],
all_targets: set[str],
subset: str,
suffix: str,
) -> str:
# pylint: disable=too-many-locals
if subset == 'public_tools':
src = 'tools'
dst = f'{BUILD_DIR}/ba_data/python'
@ -197,6 +224,7 @@ def _get_py_targets_subset(
_get_py_targets(
projroot,
meta_manifests,
explicit_sources,
src,
dst,
py_targets,
@ -368,6 +396,7 @@ def generate_assets_makefile(
fname: str,
existing_data: str,
meta_manifests: dict[str, str],
explicit_sources: set[str],
) -> dict[str, str]:
"""Main script entry point."""
# pylint: disable=too-many-locals
@ -377,8 +406,6 @@ def generate_assets_makefile(
public = getconfig(Path(projroot))['public']
assert isinstance(public, bool)
# with open(fname, encoding='utf-8') as infile:
# original = infile.read()
original = existing_data
lines = original.splitlines()
@ -395,6 +422,7 @@ def generate_assets_makefile(
_get_py_targets_subset(
projroot,
meta_manifests,
explicit_sources,
all_targets_public,
subset='public',
suffix='_PUBLIC',
@ -402,6 +430,7 @@ def generate_assets_makefile(
_get_py_targets_subset(
projroot,
meta_manifests,
explicit_sources,
all_targets_public,
subset='public_tools',
suffix='_PUBLIC_TOOLS',
@ -416,6 +445,7 @@ def generate_assets_makefile(
_get_py_targets_subset(
projroot,
meta_manifests,
explicit_sources,
all_targets_private,
subset='private-apple',
suffix='_PRIVATE_APPLE',
@ -423,6 +453,7 @@ def generate_assets_makefile(
_get_py_targets_subset(
projroot,
meta_manifests,
explicit_sources,
all_targets_private,
subset='private-android',
suffix='_PRIVATE_ANDROID',
@ -430,6 +461,7 @@ def generate_assets_makefile(
_get_py_targets_subset(
projroot,
meta_manifests,
explicit_sources,
all_targets_private,
subset='private-common',
suffix='_PRIVATE_COMMON',
@ -437,6 +469,7 @@ def generate_assets_makefile(
_get_py_targets_subset(
projroot,
meta_manifests,
explicit_sources,
all_targets_private,
subset='private-windows-Win32',
suffix='_PRIVATE_WIN_WIN32',
@ -444,6 +477,7 @@ def generate_assets_makefile(
_get_py_targets_subset(
projroot,
meta_manifests,
explicit_sources,
all_targets_private,
subset='private-windows-x64',
suffix='_PRIVATE_WIN_X64',
@ -470,7 +504,11 @@ def generate_assets_makefile(
all_targets_private,
),
_get_targets(
projroot, 'PEM_TARGETS', '.pem', '.pem', all_targets_private
projroot,
'PEM_TARGETS',
'.pem',
'.pem',
all_targets_private,
),
_get_targets(
projroot,
@ -481,7 +519,11 @@ def generate_assets_makefile(
limit_to_prefix='ba_data/data',
),
_get_targets(
projroot, 'AUDIO_TARGETS', '.wav', '.ogg', all_targets_private
projroot,
'AUDIO_TARGETS',
'.wav',
'.ogg',
all_targets_private,
),
_get_targets(
projroot,

View File

@ -28,49 +28,50 @@ class FeatureSet:
_active_feature_set: FeatureSet | None = None
@classmethod
def get_all_for_project(cls, project_root: str) -> list[FeatureSet]:
"""Return all feature-sets for the current project."""
project_root_abs = os.path.abspath(project_root)
# Only do this once per project.
if project_root_abs not in _g_feature_sets:
_g_feature_sets[project_root_abs] = _build_feature_set_list(
project_root_abs
)
return _g_feature_sets[project_root_abs]
@classmethod
def resolve_requirements(
cls, featuresets: list[FeatureSet], reqs: set[str]
) -> set[str]:
"""Resolve all required feature-sets based on a given set of them.
Throws descriptive CleanErrors if any are missing.
"""
fsets = {f.name: f for f in featuresets}
reqs_out = set[str]()
for req in reqs:
cls._resolve_requirements(fsets, reqs_out, req)
return reqs_out
@classmethod
def _resolve_requirements(
cls, featuresets: dict[str, FeatureSet], reqs_out: set[str], req: str
) -> None:
if req in reqs_out:
return
featureset = featuresets.get(req)
if featureset is None:
raise CleanError(f"Required featureset '{req}' not found.")
reqs_out.add(req)
for sub_req in featureset.requirements:
cls._resolve_requirements(featuresets, reqs_out, sub_req)
def __init__(self, name: str):
self.requirements = set[str]()
# (internal; don't set this)
self.internal = False
# Other feature-sets this one requires. Any spinoff project this
# feature-set is included in will implicitly include these as
# well.
self.requirements = set[str]()
# Feature-sets this one can use but can survive without. Note
# that each of these requirements must have
# 'allow_as_soft_requirement' enabled. While it is possible to
# programmatically check for the presence of *any* feature-set,
# officially listing soft-requirements ensures that any expected
# python-app-subsystems are in place even for feature-sets not
# included in the spinoff project (though be aware their type
# annotations will be 'Any | None' in that case instead of the
# usual 'FooBarSubsystem | None' due to 'FooBarSubsystem' not
# actually existing).
self.soft_requirements = set[str]()
# Whether this featureset defines a native Python module within
# its C++ code. The build process will try to create dummy
# modules for all native modules you must tell it if you don't
# have one.
self.has_native_python_module = True
# If True, for feature-set 'foo_bar', the build system will
# define a 'babase.app.foo_bar' attr which points to a lazy
# loaded instance of type 'bafoobar.FooBarSubsystem'.
self.has_python_app_subsystem = False
# If True, feature-set 'foo_bar', will be allowed to be listed
# as a soft-requirement of other feature sets and its
# python-app-subsystem will be annotated as type
# 'bafoobar.FooBarSubsystem | None' instead of simply
# 'bafoobar.FooBarSubsystem'. This forces type-checked code to
# account for the possibility that it will not be present. Note
# that this currently requires has_python_app_subsystem to be
# True (because if a soft-required feature-set is missing we
# must assume that is the case anyway because there's no way to
# know).
self.allow_as_soft_requirement = False
self.validate_name(name)
# Paths of files we should disable c++ namespace checks for.
@ -228,6 +229,45 @@ class FeatureSet:
assert type(self)._active_feature_set is self
type(self)._active_feature_set = None
@classmethod
def get_all_for_project(cls, project_root: str) -> list[FeatureSet]:
"""Return all feature-sets for the current project."""
project_root_abs = os.path.abspath(project_root)
# Only do this once per project.
if project_root_abs not in _g_feature_sets:
_g_feature_sets[project_root_abs] = _build_feature_set_list(
project_root_abs
)
return _g_feature_sets[project_root_abs]
@classmethod
def resolve_requirements(
cls, featuresets: list[FeatureSet], reqs: set[str]
) -> set[str]:
"""Resolve all required feature-sets based on a given set of them.
Throws descriptive CleanErrors if any are missing.
"""
fsets = {f.name: f for f in featuresets}
reqs_out = set[str]()
for req in reqs:
cls._resolve_requirements(fsets, reqs_out, req)
return reqs_out
@classmethod
def _resolve_requirements(
cls, featuresets: dict[str, FeatureSet], reqs_out: set[str], req: str
) -> None:
if req in reqs_out:
return
featureset = featuresets.get(req)
if featureset is None:
raise CleanError(f"Required featureset '{req}' not found.")
reqs_out.add(req)
for sub_req in featureset.requirements:
cls._resolve_requirements(featuresets, reqs_out, sub_req)
def _build_feature_set_list(project_root: str) -> list[FeatureSet]:
featuresets: list[FeatureSet] = []
@ -246,28 +286,56 @@ def _build_feature_set_list(project_root: str) -> list[FeatureSet]:
featureset.apply_config(os.path.join(fsdir, filename))
featuresets.append(featureset)
# Run some sanity checks to make sure our featuresets don't have
# clashing names/etc. (for instance, foo_v1 and foov_1 would resolve
# to the same foov1 py module name).
# Run some sanity checks to make sure our full set of featuresets
# don't have clashing names/etc. (for instance, foo_v1 and foov_1
# would resolve to the same foov1 py module name).
fsnames = {f.name for f in featuresets}
assert len(fsnames) == len(featuresets)
featuresets_by_name = {f.name: f for f in featuresets}
assert len(featuresets_by_name) == len(featuresets)
assert len({f.name_compact for f in featuresets}) == len(featuresets)
assert len({f.name_compact for f in featuresets}) == len(featuresets)
for featureset in featuresets:
# Require soft-req-enabled feature-sets to have app subsystems
# enabled (see above for explanation).
if featureset.allow_as_soft_requirement:
if not featureset.has_python_app_subsystem:
raise CleanError(
f"Feature-set '{featureset.name}'"
" has 'allow_as_soft_requirement' set to True but"
" 'has_python_app_subsystem' set to False;"
' soft-requireable feature-sets currently MUST'
' provide a subsystem.'
)
for req in featureset.requirements:
if req == featureset.name:
raise CleanError(
f"Feature-set '{featureset.name}'"
f' lists itself as a requirement; this is not allowed.'
)
if req not in fsnames:
if req not in featuresets_by_name:
raise CleanError(
f"Undefined feature-set '{req}'"
f' listed as a requirement of feature-set'
f" '{featureset.name}'."
)
for req in featureset.soft_requirements:
if req == featureset.name:
raise CleanError(
f"Feature-set '{featureset.name}'"
f' lists itself as a soft-requirement; this is not allowed.'
)
if (
req in featuresets_by_name
and not featuresets_by_name[req].allow_as_soft_requirement
):
raise CleanError(
f"Feature-set '{req}'"
f' is listed as a soft-requirement of feature-set'
f" '{featureset.name}' but is not allowed to be soft"
' required.'
)
return featuresets

View File

@ -111,6 +111,7 @@ class ProjectUpdater:
self._update_cmake_files()
self._update_visual_studio_projects()
self._update_xcode_projects()
self._update_app_module()
@property
def source_files(self) -> list[str]:
@ -401,6 +402,8 @@ class ProjectUpdater:
self._generate_resources_makefile(path, existing_data)
elif path == 'src/meta/Makefile':
self._generate_meta_makefile(existing_data)
elif path == 'src/assets/ba_data/python/babase/_app.py':
self._generate_app_module(path, existing_data)
elif path.startswith('src/meta/.meta_manifest_'):
# These are always generated as a side-effect of the
# meta Makefile.
@ -414,6 +417,9 @@ class ProjectUpdater:
assert path in self._generated_files
return self._generated_files[path]
def _update_app_module(self) -> None:
self.enqueue_update('src/assets/ba_data/python/babase/_app.py')
def _update_xcode_projects(self) -> None:
# from batools.xcode import update_xcode_project
@ -652,7 +658,7 @@ class ProjectUpdater:
def _generate_assets_makefile(self, path: str, existing_data: str) -> None:
from batools.assetsmakefile import generate_assets_makefile
# We need to now what files meta will be creating (since they
# We need to know what files meta will be creating (since they
# can be asset sources).
meta_manifests: dict[str, str] = {}
for mantype in ['public', 'private']:
@ -661,8 +667,17 @@ class ProjectUpdater:
manifest_file_name
)
# Special case; the app module file in the base feature set
# is created/updated here as a project file. It may or may not
# exist on disk, but we want to ignore it if it does and add it
# explicitly similarly to meta-manifests.
if 'base' in self.feature_sets:
explicit_sources = {'src/assets/ba_data/python/babase/_app.py'}
else:
explicit_sources = set()
outfiles = generate_assets_makefile(
self.projroot, path, existing_data, meta_manifests
self.projroot, path, existing_data, meta_manifests, explicit_sources
)
for out_path, out_contents in outfiles.items():
@ -680,6 +695,120 @@ class ProjectUpdater:
self.projroot, existing_data
)
def _generate_app_module(self, path: str, existing_data: str) -> None:
# pylint: disable=too-many-locals
import textwrap
from efrotools import replace_section
fsets = self.feature_sets
out = existing_data
info = '# This section autogenerated by project-update.'
indent = ' '
# Import modules we need for feature-set subsystems.
contents = ''
for _fsname, fset in sorted(fsets.items()):
if fset.has_python_app_subsystem:
modname = fset.name_python_package
classname = f'{fset.name_camel}Subsystem'
contents += f'from {modname} import {classname}\n'
out = replace_section(
out,
f'{indent}# __FEATURESET_APP_SUBSYSTEM_IMPORTS_BEGIN__\n',
f'{indent}# __FEATURESET_APP_SUBSYSTEM_IMPORTS_END__\n',
textwrap.indent(f'{info}\n\n{contents}\n', indent),
keep_markers=True,
)
# Calc which feature-sets are soft-required by any of the ones here
# but not included here. For those we'll expose app-subsystems that
# always return None.
missing_soft_fset_names = set[str]()
for fset in fsets.values():
for softreq in fset.soft_requirements:
if softreq not in fsets:
missing_soft_fset_names.add(softreq)
all_fset_names = missing_soft_fset_names | fsets.keys()
# Add properties to instantiate feature-set subsystems.
contents = ''
for fsetname in sorted(all_fset_names):
# for _fsname, fset in sorted(fsets.items()):
if fsetname in missing_soft_fset_names:
contents += (
f'\n'
f'@cached_property\n'
f'def {fsetname}(self) -> Any | None:\n'
f' """Our {fsetname} subsystem (not available)."""\n'
f'\n'
f' return None\n'
)
else:
fset = fsets[fsetname]
if fset.has_python_app_subsystem:
if not fset.allow_as_soft_requirement:
raise CleanError(
f'allow_as_soft_requirement is False for'
f' feature-set {fset.name};'
f' this is not yet supported.'
)
modname = fset.name_python_package
classname = f'{fset.name_camel}Subsystem'
contents += (
f'\n'
f'@cached_property\n'
f'def {fset.name}(self) -> {classname} | None:\n'
f' """Our {fset.name} subsystem (if available)."""\n'
f'\n'
f' try:\n'
f' from {modname} import {classname}\n'
f'\n'
f' return {classname}()\n'
f' except ImportError:\n'
f' return None\n'
f' except Exception:\n'
f" logging.exception('Error importing"
f" {modname}.')\n"
f' return None\n'
)
out = replace_section(
out,
f'{indent}# __FEATURESET_APP_SUBSYSTEM_PROPERTIES_BEGIN__\n',
f'{indent}# __FEATURESET_APP_SUBSYSTEM_PROPERTIES_END__\n',
textwrap.indent(f'{info}\n{contents}\n', indent),
keep_markers=True,
)
# Set default app-mode-selection logic.
# TEMP - fill this out with proper logic/options.
if 'scene_v1' in fsets:
contents = 'import bascenev1\n\nreturn bascenev1.SceneV1AppMode\n'
else:
contents = "raise RuntimeError('FIXME: unimplemented.')\n"
indent = ' '
out = replace_section(
out,
f'{indent}# __DEFAULT_APP_MODE_SELECTION_BEGIN__\n',
f'{indent}# __DEFAULT_APP_MODE_SELECTION_END__\n',
textwrap.indent(f'{info}\n\n{contents}\n', indent),
keep_markers=True,
)
# Note: we *should* format this string, but because this code
# runs with every project update I'm just gonna try to keep the
# formatting correct manually for now to save a bit of time.
# (project update time jumps from 0.3 to 0.5 seconds if I format
# thie one file).
self._generated_files[path] = out
def _update_meta_makefile(self) -> None:
self.enqueue_update('src/meta/Makefile')

View File

@ -129,20 +129,10 @@ class SpinoffContext:
self._execution_error = False
self._project_file_names = {
'Makefile',
'CMakeLists.txt',
'.meta_manifest_public.json',
'.meta_manifest_private.json',
'.asset_manifest_public.json',
'.asset_manifest_private.json',
}
self.project_file_paths = set[str]()
self.project_file_names = set[str]()
self.project_file_suffixes = set[str]()
self._project_file_suffixes = {
'.vcxproj',
'.vcxproj.filters',
'.pbxproj',
}
# Set of files/symlinks in src.
self._src_entities: dict[str, SrcEntity] = {}
@ -1300,8 +1290,10 @@ class SpinoffContext:
if path.startswith('tools/') or path.startswith('src/external'):
return False
bname = os.path.basename(path)
return bname in self._project_file_names or any(
bname.endswith(s) for s in self._project_file_suffixes
return (
path in self.project_file_paths
or bname in self.project_file_names
or any(bname.endswith(s) for s in self.project_file_suffixes)
)
def _update(self) -> None:
@ -1401,6 +1393,7 @@ class SpinoffContext:
print_individual_updates: bool,
is_project_file: bool = False,
) -> None:
# pylint: disable=too-many-locals
src_entity = self._src_entities[src_path]
dst_path = src_entity.dst
src_path_full = os.path.join(self._src_root, src_path)
@ -1465,10 +1458,12 @@ class SpinoffContext:
f'{Clr.RED}Error removing failed dst file: {exc2}{Clr.RST}'
)
self._execution_error = True
verbose_note = (
'' if self._verbose else ' (use --verbose for full traceback)'
)
print(
f'{Clr.RED}Error copying/filtering file:'
f" '{src_path_full}'{Clr.RST}: {exc}"
' (use --verbose for full traceback)',
f" '{src_path_full}'{Clr.RST}: {exc}{verbose_note}",
file=sys.stderr,
)
if self._verbose:

View File

@ -136,6 +136,7 @@ def replace_section(
begin_marker: str,
end_marker: str,
replace_text: str = '',
keep_markers: bool = False,
error_if_missing: bool = True,
) -> str:
"""Replace all text between two marker strings (including the markers)."""
@ -157,7 +158,9 @@ def replace_section(
f'; found {text.count(end_marker)}.'
)
_before_end, after_end = splits
return before_begin + replace_text + after_end
if keep_markers:
replace_text = f'{begin_marker}{replace_text}{end_marker}'
return f'{before_begin}{replace_text}{after_end}'
def get_public_license(style: str) -> str: