Fix .blend files with quotation marks in filename fail to import
This commit is contained in:
parent
b97110cd30
commit
d244d6f4fe
|
@ -43,6 +43,7 @@ from xmlrpc.server import SimpleXMLRPCServer
|
||||||
req = threading.Condition()
|
req = threading.Condition()
|
||||||
res = threading.Condition()
|
res = threading.Condition()
|
||||||
info = None
|
info = None
|
||||||
|
export_err = None
|
||||||
def xmlrpc_server():
|
def xmlrpc_server():
|
||||||
server = SimpleXMLRPCServer(('127.0.0.1', %d))
|
server = SimpleXMLRPCServer(('127.0.0.1', %d))
|
||||||
server.register_function(export_gltf)
|
server.register_function(export_gltf)
|
||||||
|
@ -54,6 +55,10 @@ def export_gltf(opts):
|
||||||
req.notify()
|
req.notify()
|
||||||
with res:
|
with res:
|
||||||
res.wait()
|
res.wait()
|
||||||
|
if export_err:
|
||||||
|
raise export_err
|
||||||
|
# Important to return a value to prevent the error 'cannot marshal None unless allow_none is enabled'.
|
||||||
|
return 'BLENDER_GODOT_EXPORT_SUCCESSFUL'
|
||||||
if bpy.app.version < (3, 0, 0):
|
if bpy.app.version < (3, 0, 0):
|
||||||
print('Blender 3.0 or higher is required.', file=sys.stderr)
|
print('Blender 3.0 or higher is required.', file=sys.stderr)
|
||||||
threading.Thread(target=xmlrpc_server).start()
|
threading.Thread(target=xmlrpc_server).start()
|
||||||
|
@ -64,12 +69,13 @@ while True:
|
||||||
method, opts = info
|
method, opts = info
|
||||||
if method == 'export_gltf':
|
if method == 'export_gltf':
|
||||||
try:
|
try:
|
||||||
|
export_err = None
|
||||||
bpy.ops.wm.open_mainfile(filepath=opts['path'])
|
bpy.ops.wm.open_mainfile(filepath=opts['path'])
|
||||||
if opts['unpack_all']:
|
if opts['unpack_all']:
|
||||||
bpy.ops.file.unpack_all(method='USE_LOCAL')
|
bpy.ops.file.unpack_all(method='USE_LOCAL')
|
||||||
bpy.ops.export_scene.gltf(**opts['gltf_options'])
|
bpy.ops.export_scene.gltf(**opts['gltf_options'])
|
||||||
except:
|
except Exception as e:
|
||||||
pass
|
export_err = e
|
||||||
info = None
|
info = None
|
||||||
with res:
|
with res:
|
||||||
res.notify()
|
res.notify()
|
||||||
|
@ -184,7 +190,9 @@ Error EditorImportBlendRunner::do_import(const Dictionary &p_options) {
|
||||||
EditorSettings::get_singleton()->set_manually("filesystem/import/blender/rpc_port", 0);
|
EditorSettings::get_singleton()->set_manually("filesystem/import/blender/rpc_port", 0);
|
||||||
rpc_port = 0;
|
rpc_port = 0;
|
||||||
}
|
}
|
||||||
err = do_import_direct(p_options);
|
if (err != ERR_QUERY_FAILED) {
|
||||||
|
err = do_import_direct(p_options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
|
@ -259,6 +267,7 @@ Error EditorImportBlendRunner::do_import_rpc(const Dictionary &p_options) {
|
||||||
|
|
||||||
// Wait for response.
|
// Wait for response.
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
PackedByteArray response;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
status = client->get_status();
|
status = client->get_status();
|
||||||
switch (status) {
|
switch (status) {
|
||||||
|
@ -268,7 +277,10 @@ Error EditorImportBlendRunner::do_import_rpc(const Dictionary &p_options) {
|
||||||
}
|
}
|
||||||
case HTTPClient::STATUS_BODY: {
|
case HTTPClient::STATUS_BODY: {
|
||||||
client->poll();
|
client->poll();
|
||||||
// Parse response here if needed. For now we can just ignore it.
|
response.append_array(client->read_response_body_chunk());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HTTPClient::STATUS_CONNECTED: {
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -278,9 +290,56 @@ Error EditorImportBlendRunner::do_import_rpc(const Dictionary &p_options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String response_text = "No response from Blender.";
|
||||||
|
if (response.size() > 0) {
|
||||||
|
response_text = String::utf8((const char *)response.ptr(), response.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->get_response_code() != HTTPClient::RESPONSE_OK) {
|
||||||
|
ERR_FAIL_V_MSG(ERR_QUERY_FAILED, vformat("Error received from Blender - status code: %s, error: %s", client->get_response_code(), response_text));
|
||||||
|
} else if (response_text.find("BLENDER_GODOT_EXPORT_SUCCESSFUL") < 0) {
|
||||||
|
// Previous versions of Godot used a Python script where the RPC function did not return
|
||||||
|
// a value, causing the error 'cannot marshal None unless allow_none is enabled'.
|
||||||
|
// If an older version of Godot is running and has started Blender with this script,
|
||||||
|
// we will receive the error, but there's a good chance that the import was successful.
|
||||||
|
// We are discarding this error to maintain backward compatibility and prevent situations
|
||||||
|
// where the user needs to close the older version of Godot or kill Blender.
|
||||||
|
if (response_text.find("cannot marshal None unless allow_none is enabled") < 0) {
|
||||||
|
String error_message;
|
||||||
|
if (_extract_error_message_xml(response, error_message)) {
|
||||||
|
ERR_FAIL_V_MSG(ERR_QUERY_FAILED, vformat("Blender exportation failed: %s", error_message));
|
||||||
|
} else {
|
||||||
|
ERR_FAIL_V_MSG(ERR_QUERY_FAILED, vformat("Blender exportation failed: %s", response_text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EditorImportBlendRunner::_extract_error_message_xml(const Vector<uint8_t> &p_response_data, String &r_error_message) {
|
||||||
|
// Based on RPC Xml spec from: https://xmlrpc.com/spec.md
|
||||||
|
Ref<XMLParser> parser = memnew(XMLParser);
|
||||||
|
Error err = parser->open_buffer(p_response_data);
|
||||||
|
if (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
r_error_message = String();
|
||||||
|
while (parser->read() == OK) {
|
||||||
|
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
|
||||||
|
if (parser->get_node_data().size()) {
|
||||||
|
if (r_error_message.size()) {
|
||||||
|
r_error_message += " ";
|
||||||
|
}
|
||||||
|
r_error_message += parser->get_node_data().trim_suffix("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r_error_message.size();
|
||||||
|
}
|
||||||
|
|
||||||
Error EditorImportBlendRunner::do_import_direct(const Dictionary &p_options) {
|
Error EditorImportBlendRunner::do_import_direct(const Dictionary &p_options) {
|
||||||
// Export glTF directly.
|
// Export glTF directly.
|
||||||
String python = vformat(PYTHON_SCRIPT_DIRECT, dict_to_python(p_options));
|
String python = vformat(PYTHON_SCRIPT_DIRECT, dict_to_python(p_options));
|
||||||
|
|
|
@ -47,6 +47,7 @@ class EditorImportBlendRunner : public Node {
|
||||||
void _resources_reimported(const PackedStringArray &p_files);
|
void _resources_reimported(const PackedStringArray &p_files);
|
||||||
void _kill_blender();
|
void _kill_blender();
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
bool _extract_error_message_xml(const Vector<uint8_t> &p_response_data, String &r_error_message);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int rpc_port = 0;
|
int rpc_port = 0;
|
||||||
|
|
|
@ -132,12 +132,10 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
source_global = source_global.c_escape();
|
|
||||||
|
|
||||||
const String blend_basename = p_path.get_file().get_basename();
|
const String blend_basename = p_path.get_file().get_basename();
|
||||||
const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
|
const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
|
||||||
vformat("%s-%s.gltf", blend_basename, p_path.md5_text()));
|
vformat("%s-%s.gltf", blend_basename, p_path.md5_text()));
|
||||||
const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape();
|
const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink);
|
||||||
|
|
||||||
// Handle configuration options.
|
// Handle configuration options.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue