feat(web): persist advanced Main capability overrides
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-08-29 04:36:13 +08:00
parent 58c2ae046d
commit e9b9d343a1
7 changed files with 132 additions and 12 deletions

View File

@@ -41,6 +41,7 @@
#include "BKE_object_deform.h"
#include "BKE_packedFile.hh"
#include "BKE_scene.hh"
#include "BKE_text.h"
#include "BKE_vfont.hh"
#include "BKE_volume.hh"
#include "BKE_fcurve.hh"
@@ -72,6 +73,7 @@
#include "DNA_particle_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_text_types.h"
#include "DNA_world_types.h"
#include "DNA_userdef_enums.h"
#include "DNA_vfont_types.h"
@@ -134,6 +136,75 @@ std::string id_name(const ID &id)
return id.name[0] != '\0' && id.name[1] != '\0' ? std::string(id.name + 2) : std::string();
}
constexpr char WEB_ENGINE_GEOMETRY_OVERRIDE_TEXT[] = "WBV2 Geometry Node Overrides";
constexpr char WEB_ENGINE_PHYSICS_OVERRIDE_TEXT[] = "WBV2 Physics Simulation Override";
std::string text_contents(Text &text)
{
size_t length = 0;
char *buffer = txt_to_buf(&text, &length);
if (buffer == nullptr) return {};
std::string result(buffer, length);
MEM_delete(buffer);
return result;
}
Text *find_text(Main *main, const char *name)
{
if (main == nullptr || name == nullptr) return nullptr;
for (Text &text : main->texts) {
if (id_name(text.id) == name) return &text;
}
return nullptr;
}
bool write_text(Main *main, const char *name, const std::string &contents)
{
if (main == nullptr || name == nullptr || contents.size() > 64 * 1024 * 1024) return false;
Text *text = find_text(main, name);
if (text == nullptr) text = BKE_text_add(main, name);
if (text == nullptr) return false;
BKE_text_clear(text);
BKE_text_write(text, contents.c_str(), int(contents.size()));
return true;
}
void load_persisted_geometry_overrides(WebBlendMainState *state)
{
if (state == nullptr || state->main == nullptr) return;
Text *text = find_text(state->main, WEB_ENGINE_GEOMETRY_OVERRIDE_TEXT);
if (text == nullptr) return;
try {
const json payload = json::parse(text_contents(*text));
if (!payload.is_object()) return;
for (const auto &[graph_id, graph] : payload.items()) {
if (graph.is_object()) state->geometry_node_graph_overrides[graph_id] = graph.dump();
}
}
catch (...) {
/* Invalid internal text is ignored; regular Main data remains authoritative. */
}
}
void load_persisted_physics_override(WebBlendMainState *state)
{
if (state == nullptr || state->main == nullptr || !state->physics_simulation_override.empty()) return;
Text *text = find_text(state->main, WEB_ENGINE_PHYSICS_OVERRIDE_TEXT);
if (text == nullptr) return;
const std::string contents = text_contents(*text);
if (!contents.empty()) state->physics_simulation_override = contents;
}
bool persist_geometry_overrides(WebBlendMainState *state)
{
json payload = json::object();
for (const auto &[graph_id, graph_text] : state->geometry_node_graph_overrides) {
try { payload[graph_id] = json::parse(graph_text); }
catch (...) { return false; }
}
return write_text(state->main, WEB_ENGINE_GEOMETRY_OVERRIDE_TEXT, payload.dump());
}
Object *find_object(Main *main, const char *object_id)
{
if (main == nullptr || object_id == nullptr || strncmp(object_id, "object:", 7) != 0) {
@@ -869,6 +940,8 @@ WebBlendMainState *web_engine_blend_main_open(const uint8_t *data,
for (blender::ViewLayer &candidate : state->scene->view_layers) {
blender::BKE_view_layer_synced_ensure(*state->main, state->scene, &candidate);
}
load_persisted_geometry_overrides(state);
load_persisted_physics_override(state);
return state;
}
@@ -4344,7 +4417,17 @@ bool web_engine_blend_main_set_geometry_node_graph(WebBlendMainState *state,
error = "GN_INVALID_GRAPH: Geometry Node graph schema or bounds are invalid";
return false;
}
state->geometry_node_graph_overrides[graph_id] = graph.dump();
const std::string graph_text = graph.dump();
const auto previous = state->geometry_node_graph_overrides.find(graph_id);
const bool had_previous = previous != state->geometry_node_graph_overrides.end();
const std::string previous_text = had_previous ? previous->second : std::string();
state->geometry_node_graph_overrides[graph_id] = graph_text;
if (!persist_geometry_overrides(state)) {
if (!had_previous) state->geometry_node_graph_overrides.erase(graph_id);
else state->geometry_node_graph_overrides[graph_id] = previous_text;
error = "GN_INVALID_GRAPH: Geometry Node graph could not be persisted in Main";
return false;
}
return true;
}
catch (const std::exception &exception) {
@@ -4508,7 +4591,12 @@ bool web_engine_blend_main_set_physics_simulation(WebBlendMainState *state,
return false;
}
}
state->physics_simulation_override = manifest.dump();
const std::string manifest_text = manifest.dump();
if (!write_text(state->main, WEB_ENGINE_PHYSICS_OVERRIDE_TEXT, manifest_text)) {
error = "PHYSICS_MANIFEST_INVALID: physics manifest could not be persisted in Main";
return false;
}
state->physics_simulation_override = manifest_text;
return true;
}
catch (const std::exception &exception) {