Merge pull request #57489 from akien-mga/3.4-cherrypicks

This commit is contained in:
Rémi Verschelde 2022-01-31 22:54:02 +01:00 committed by GitHub
commit caaa648e86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 157 additions and 83 deletions

View File

@ -8,8 +8,8 @@
See also [AudioStreamGenerator] for procedurally generating sounds. See also [AudioStreamGenerator] for procedurally generating sounds.
</description> </description>
<tutorials> <tutorials>
<link title="https://godotengine.org/asset-library/asset/528">Audio Spectrum Demo</link> <link title="Audio Spectrum Demo">https://godotengine.org/asset-library/asset/528</link>
<link title="https://godotengine.org/article/godot-32-will-get-new-audio-features">Godot 3.2 will get new audio features</link> <link title="Godot 3.2 will get new audio features">https://godotengine.org/article/godot-32-will-get-new-audio-features</link>
</tutorials> </tutorials>
<methods> <methods>
</methods> </methods>

View File

@ -10,7 +10,7 @@
</description> </description>
<tutorials> <tutorials>
<link title="Audio Generator Demo">https://godotengine.org/asset-library/asset/526</link> <link title="Audio Generator Demo">https://godotengine.org/asset-library/asset/526</link>
<link title="https://godotengine.org/article/godot-32-will-get-new-audio-features">Godot 3.2 will get new audio features</link> <link title="Godot 3.2 will get new audio features">https://godotengine.org/article/godot-32-will-get-new-audio-features</link>
</tutorials> </tutorials>
<methods> <methods>
</methods> </methods>

View File

@ -8,7 +8,7 @@
</description> </description>
<tutorials> <tutorials>
<link title="Audio Generator Demo">https://godotengine.org/asset-library/asset/526</link> <link title="Audio Generator Demo">https://godotengine.org/asset-library/asset/526</link>
<link title="https://godotengine.org/article/godot-32-will-get-new-audio-features">Godot 3.2 will get new audio features</link> <link title="Godot 3.2 will get new audio features">https://godotengine.org/article/godot-32-will-get-new-audio-features</link>
</tutorials> </tutorials>
<methods> <methods>
<method name="can_push_buffer" qualifiers="const"> <method name="can_push_buffer" qualifiers="const">

View File

@ -47,6 +47,7 @@
</member> </member>
<member name="max_distance" type="float" setter="set_max_distance" getter="get_max_distance" default="0.0"> <member name="max_distance" type="float" setter="set_max_distance" getter="get_max_distance" default="0.0">
The maximum distance away from the [ReflectionProbe] an object can be before it is culled. Decrease this to improve performance, especially when using the [constant UPDATE_ALWAYS] [member update_mode]. The maximum distance away from the [ReflectionProbe] an object can be before it is culled. Decrease this to improve performance, especially when using the [constant UPDATE_ALWAYS] [member update_mode].
[b]Note:[/b] The maximum reflection distance is always at least equal to the [member extents]. This means that decreasing [member max_distance] will not always cull objects from reflections, especially if the reflection probe's [member extents] are already large.
</member> </member>
<member name="origin_offset" type="Vector3" setter="set_origin_offset" getter="get_origin_offset" default="Vector3( 0, 0, 0 )"> <member name="origin_offset" type="Vector3" setter="set_origin_offset" getter="get_origin_offset" default="Vector3( 0, 0, 0 )">
Sets the origin offset to be used when this [ReflectionProbe] is in [member box_projection] mode. This can be set to a non-zero value to ensure a reflection fits a rectangle-shaped room, while reducing the amount of objects that "get in the way" of the reflection. Sets the origin offset to be used when this [ReflectionProbe] is in [member box_projection] mode. This can be set to a non-zero value to ensure a reflection fits a rectangle-shaped room, while reducing the amount of objects that "get in the way" of the reflection.

View File

@ -77,7 +77,7 @@ void SkeletonEditor::create_physical_skeleton() {
if (!bones_infos[parent].physical_bone) { if (!bones_infos[parent].physical_bone) {
bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos); bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos);
ur->create_action(TTR("Create physical bones")); ur->create_action(TTR("Create physical bones"), UndoRedo::MERGE_ALL);
ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone); ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone);
ur->add_do_reference(bones_infos[parent].physical_bone); ur->add_do_reference(bones_infos[parent].physical_bone);
ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone); ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone);

View File

@ -164,11 +164,12 @@ const char *godot_so_name = "libgodot_android.so";
void *mono_dl_handle = NULL; void *mono_dl_handle = NULL;
void *godot_dl_handle = NULL; void *godot_dl_handle = NULL;
void *try_dlopen(const String &p_so_path, int p_flags) { void *_try_dlopen_file_path(const String &p_so_path, int p_flags) {
if (!FileAccess::exists(p_so_path)) { if (!FileAccess::exists(p_so_path)) {
if (OS::get_singleton()->is_stdout_verbose()) if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Cannot find shared library: '%s'\n", p_so_path.utf8().get_data()); OS::get_singleton()->print("Cannot find shared library: '%s'\n", p_so_path.utf8().get_data());
return NULL; }
return nullptr;
} }
int lflags = gd_mono_convert_dl_flags(p_flags); int lflags = gd_mono_convert_dl_flags(p_flags);
@ -176,13 +177,48 @@ void *try_dlopen(const String &p_so_path, int p_flags) {
void *handle = dlopen(p_so_path.utf8().get_data(), lflags); void *handle = dlopen(p_so_path.utf8().get_data(), lflags);
if (!handle) { if (!handle) {
if (OS::get_singleton()->is_stdout_verbose()) if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Failed to open shared library: '%s'. Error: '%s'\n", p_so_path.utf8().get_data(), dlerror()); OS::get_singleton()->print("Failed to open shared library: '%s'. Error: '%s'\n", p_so_path.utf8().get_data(), dlerror());
return NULL; }
return nullptr;
} }
if (OS::get_singleton()->is_stdout_verbose()) if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Successfully loaded shared library: '%s'\n", p_so_path.utf8().get_data()); OS::get_singleton()->print("Successfully loaded shared library: '%s'\n", p_so_path.utf8().get_data());
}
return handle;
}
void *try_dlopen(const String &p_so_path, int p_flags) {
void *handle = _try_dlopen_file_path(p_so_path, p_flags);
if (handle) {
return handle;
}
// Try only with the file name, without specifying the location.
// This is needed when installing from Android App Bundles, as the native
// libraries are not extracted. They are loaded directly from the APK.
// See: https://stackoverflow.com/a/56551499
// If we pass only the file name to dlopen without the location, it should
// search the native libraries in all locations, including inside the apk.
String so_name = p_so_path.get_file();
int lflags = gd_mono_convert_dl_flags(p_flags);
handle = dlopen(so_name.utf8().get_data(), lflags);
if (!handle) {
if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Failed to open shared library: '%s'. Error: '%s'\n", so_name.utf8().get_data(), dlerror());
}
return nullptr;
}
if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Successfully loaded shared library: '%s'\n", so_name.utf8().get_data());
}
return handle; return handle;
} }
@ -196,6 +232,7 @@ void *gd_mono_android_dlopen(const char *p_name, int p_flags, char **r_err, void
String so_path = path::join(app_native_lib_dir, mono_so_name); String so_path = path::join(app_native_lib_dir, mono_so_name);
mono_dl_handle = try_dlopen(so_path, p_flags); mono_dl_handle = try_dlopen(so_path, p_flags);
ERR_FAIL_COND_V_MSG(!mono_dl_handle, nullptr, "Failed to load Mono native library from path");
} }
return mono_dl_handle; return mono_dl_handle;
@ -371,7 +408,7 @@ void initialize() {
String so_path = path::join(app_native_lib_dir, godot_so_name); String so_path = path::join(app_native_lib_dir, godot_so_name);
godot_dl_handle = try_dlopen(so_path, gd_mono_convert_dl_flags(MONO_DL_LAZY)); godot_dl_handle = try_dlopen(so_path, gd_mono_convert_dl_flags(MONO_DL_LAZY));
ERR_FAIL_COND(!godot_dl_handle); ERR_FAIL_COND_MSG(!godot_dl_handle, "Failed to load Godot native library");
} }
void cleanup() { void cleanup() {

View File

@ -185,8 +185,8 @@ void AudioStreamOGGVorbis::set_data(const PoolVector<uint8_t> &p_data) {
w.release(); w.release();
alloc_try *= 2; alloc_try *= 2;
} else { } else {
ERR_FAIL_COND(alloc_try == MAX_TEST_MEM); ERR_FAIL_COND_MSG(alloc_try == MAX_TEST_MEM, "Failed allocating memory for OGG Vorbis stream.");
ERR_FAIL_COND(ogg_stream == nullptr); ERR_FAIL_COND_MSG(!ogg_stream, "OGG Vorbis decoding failed. Check that your data is a valid OGG Vorbis audio stream.");
stb_vorbis_info info = stb_vorbis_get_info(ogg_stream); stb_vorbis_info info = stb_vorbis_get_info(ogg_stream);

View File

@ -91,7 +91,7 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin
ogg_stream.instance(); ogg_stream.instance();
ogg_stream->set_data(data); ogg_stream->set_data(data);
ERR_FAIL_COND_V(!ogg_stream->get_data().size(), ERR_FILE_CORRUPT); ERR_FAIL_COND_V_MSG(!ogg_stream->get_data().size(), ERR_FILE_CORRUPT, "Couldn't import file as AudioStreamOGGVorbis: " + p_source_file);
ogg_stream->set_loop(loop); ogg_stream->set_loop(loop);
ogg_stream->set_loop_offset(loop_offset); ogg_stream->set_loop_offset(loop_offset);

View File

@ -987,14 +987,14 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
if (tname == "meta-data" && attrname == "name" && value == "xr_mode_metadata_name") { if (tname == "meta-data" && attrname == "name" && value == "xr_mode_metadata_name") {
// Update the meta-data 'android:name' attribute based on the selected XR mode. // Update the meta-data 'android:name' attribute based on the selected XR mode.
if (xr_mode_index == XR_MODE_OVR || xr_mode_index == XR_MODE_OPENXR) { if (xr_mode_index == XR_MODE_OVR) {
string_table.write[attr_value] = "com.samsung.android.vr.application.mode"; string_table.write[attr_value] = "com.samsung.android.vr.application.mode";
} }
} }
if (tname == "meta-data" && attrname == "value" && value == "xr_mode_metadata_value") { if (tname == "meta-data" && attrname == "value" && value == "xr_mode_metadata_value") {
// Update the meta-data 'android:value' attribute based on the selected XR mode. // Update the meta-data 'android:value' attribute based on the selected XR mode.
if (xr_mode_index == XR_MODE_OVR || xr_mode_index == XR_MODE_OPENXR) { if (xr_mode_index == XR_MODE_OVR) {
string_table.write[attr_value] = "vr_only"; string_table.write[attr_value] = "vr_only";
} }
} }

View File

@ -287,7 +287,9 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_
bool_to_string(p_has_storage_permission)); bool_to_string(p_has_storage_permission));
if (uses_xr) { if (uses_xr) {
manifest_application_text += " <meta-data tools:node=\"replace\" android:name=\"com.samsung.android.vr.application.mode\" android:value=\"vr_only\" />\n"; if (xr_mode_index == XR_MODE_OVR) {
manifest_application_text += " <meta-data tools:node=\"replace\" android:name=\"com.samsung.android.vr.application.mode\" android:value=\"vr_only\" />\n";
}
bool hand_tracking_enabled = (int)(p_preset->get("xr_features/hand_tracking")) > XR_HAND_TRACKING_NONE; bool hand_tracking_enabled = (int)(p_preset->get("xr_features/hand_tracking")) > XR_HAND_TRACKING_NONE;
if (hand_tracking_enabled) { if (hand_tracking_enabled) {
@ -297,6 +299,8 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_
" <meta-data tools:node=\"replace\" android:name=\"com.oculus.handtracking.frequency\" android:value=\"%s\" />\n", " <meta-data tools:node=\"replace\" android:name=\"com.oculus.handtracking.frequency\" android:value=\"%s\" />\n",
hand_tracking_frequency); hand_tracking_frequency);
} }
} else {
manifest_application_text += " <meta-data tools:node=\"remove\" android:name=\"com.oculus.supportedDevices\" />\n";
} }
manifest_application_text += _get_activity_tag(p_preset); manifest_application_text += _get_activity_tag(p_preset);
manifest_application_text += " </application>\n"; manifest_application_text += " </application>\n";

View File

@ -50,6 +50,12 @@
android:name="xr_hand_tracking_metadata_name" android:name="xr_hand_tracking_metadata_name"
android:value="xr_hand_tracking_metadata_value"/> android:value="xr_hand_tracking_metadata_value"/>
<!-- Supported Meta devices -->
<!-- This is removed by the exporter if the xr mode is not VR. -->
<meta-data
android:name="com.oculus.supportedDevices"
android:value="all" />
<activity <activity
android:name=".GodotApp" android:name=".GodotApp"
android:label="@string/godot_project_name_string" android:label="@string/godot_project_name_string"

View File

@ -225,33 +225,34 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused-
*/ */
Config.prototype.update = function (opts) { Config.prototype.update = function (opts) {
const config = opts || {}; const config = opts || {};
function parse(key, def) { const me = this;
function parse(key) {
if (typeof (config[key]) === 'undefined') { if (typeof (config[key]) === 'undefined') {
return def; return me[key];
} }
return config[key]; return config[key];
} }
// Module config // Module config
this.unloadAfterInit = parse('unloadAfterInit', this.unloadAfterInit); this.unloadAfterInit = parse('unloadAfterInit');
this.onPrintError = parse('onPrintError', this.onPrintError); this.onPrintError = parse('onPrintError');
this.onPrint = parse('onPrint', this.onPrint); this.onPrint = parse('onPrint');
this.onProgress = parse('onProgress', this.onProgress); this.onProgress = parse('onProgress');
// Godot config // Godot config
this.canvas = parse('canvas', this.canvas); this.canvas = parse('canvas');
this.executable = parse('executable', this.executable); this.executable = parse('executable');
this.mainPack = parse('mainPack', this.mainPack); this.mainPack = parse('mainPack');
this.locale = parse('locale', this.locale); this.locale = parse('locale');
this.canvasResizePolicy = parse('canvasResizePolicy', this.canvasResizePolicy); this.canvasResizePolicy = parse('canvasResizePolicy');
this.persistentPaths = parse('persistentPaths', this.persistentPaths); this.persistentPaths = parse('persistentPaths');
this.persistentDrops = parse('persistentDrops', this.persistentDrops); this.persistentDrops = parse('persistentDrops');
this.experimentalVK = parse('experimentalVK', this.experimentalVK); this.experimentalVK = parse('experimentalVK');
this.focusCanvas = parse('focusCanvas', this.focusCanvas); this.focusCanvas = parse('focusCanvas');
this.gdnativeLibs = parse('gdnativeLibs', this.gdnativeLibs); this.gdnativeLibs = parse('gdnativeLibs');
this.fileSizes = parse('fileSizes', this.fileSizes); this.fileSizes = parse('fileSizes');
this.args = parse('args', this.args); this.args = parse('args');
this.onExecute = parse('onExecute', this.onExecute); this.onExecute = parse('onExecute');
this.onExit = parse('onExit', this.onExit); this.onExit = parse('onExit');
}; };
/** /**

View File

@ -87,7 +87,7 @@ const GodotInputGamepads = {
}, },
init: function (onchange) { init: function (onchange) {
GodotEventListeners.samples = []; GodotInputGamepads.samples = [];
function add(pad) { function add(pad) {
const guid = GodotInputGamepads.get_guid(pad); const guid = GodotInputGamepads.get_guid(pad);
const c_id = GodotRuntime.allocString(pad.id); const c_id = GodotRuntime.allocString(pad.id);

View File

@ -140,6 +140,11 @@ __declspec(dllexport) int widechar_main(int argc, wchar_t **argv) {
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
#ifndef TOOLS_ENABLED
// Workaround to prevent LTCG (MSVC LTO) from removing "pck" section
char *dummy_guard = dummy;
#endif
char **argv_utf8 = new char *[argc]; char **argv_utf8 = new char *[argc];
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {

View File

@ -170,7 +170,7 @@ uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) {
id = shapes.back()->key() + 1; id = shapes.back()->key() + 1;
} }
sd.owner = p_owner; sd.owner_id = p_owner ? p_owner->get_instance_id() : 0;
shapes[id] = sd; shapes[id] = sd;
@ -283,7 +283,7 @@ Transform2D CollisionObject2D::shape_owner_get_transform(uint32_t p_owner) const
Object *CollisionObject2D::shape_owner_get_owner(uint32_t p_owner) const { Object *CollisionObject2D::shape_owner_get_owner(uint32_t p_owner) const {
ERR_FAIL_COND_V(!shapes.has(p_owner), nullptr); ERR_FAIL_COND_V(!shapes.has(p_owner), nullptr);
return shapes[p_owner].owner; return ObjectDB::get_instance(shapes[p_owner].owner_id);
} }
void CollisionObject2D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape) { void CollisionObject2D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape) {

View File

@ -45,7 +45,7 @@ class CollisionObject2D : public Node2D {
bool pickable; bool pickable;
struct ShapeData { struct ShapeData {
Object *owner; ObjectID owner_id;
Transform2D xform; Transform2D xform;
struct Shape { struct Shape {
Ref<Shape2D> shape; Ref<Shape2D> shape;
@ -61,7 +61,7 @@ class CollisionObject2D : public Node2D {
disabled = false; disabled = false;
one_way_collision = false; one_way_collision = false;
one_way_collision_margin = 0; one_way_collision_margin = 0;
owner = nullptr; owner_id = 0;
} }
}; };

View File

@ -363,7 +363,7 @@ uint32_t CollisionObject::create_shape_owner(Object *p_owner) {
id = shapes.back()->key() + 1; id = shapes.back()->key() + 1;
} }
sd.owner = p_owner; sd.owner_id = p_owner ? p_owner->get_instance_id() : 0;
shapes[id] = sd; shapes[id] = sd;
@ -442,7 +442,7 @@ Transform CollisionObject::shape_owner_get_transform(uint32_t p_owner) const {
Object *CollisionObject::shape_owner_get_owner(uint32_t p_owner) const { Object *CollisionObject::shape_owner_get_owner(uint32_t p_owner) const {
ERR_FAIL_COND_V(!shapes.has(p_owner), nullptr); ERR_FAIL_COND_V(!shapes.has(p_owner), nullptr);
return shapes[p_owner].owner; return ObjectDB::get_instance(shapes[p_owner].owner_id);
} }
void CollisionObject::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &p_shape) { void CollisionObject::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &p_shape) {

View File

@ -45,7 +45,7 @@ class CollisionObject : public Spatial {
RID rid; RID rid;
struct ShapeData { struct ShapeData {
Object *owner; ObjectID owner_id;
Transform xform; Transform xform;
struct ShapeBase { struct ShapeBase {
RID debug_shape; RID debug_shape;
@ -58,7 +58,7 @@ class CollisionObject : public Spatial {
ShapeData() { ShapeData() {
disabled = false; disabled = false;
owner = nullptr; owner_id = 0;
} }
}; };

View File

@ -168,6 +168,12 @@ void TextureButton::_notification(int p_what) {
Point2 ofs; Point2 ofs;
Size2 size; Size2 size;
bool draw_focus = (has_focus() && focused.is_valid());
// If no other texture is valid, try using focused texture.
if (!texdraw.is_valid() && draw_focus) {
texdraw = focused;
}
if (texdraw.is_valid()) { if (texdraw.is_valid()) {
size = texdraw->get_size(); size = texdraw->get_size();
@ -224,7 +230,9 @@ void TextureButton::_notification(int p_what) {
size.width *= hflip ? -1.0f : 1.0f; size.width *= hflip ? -1.0f : 1.0f;
size.height *= vflip ? -1.0f : 1.0f; size.height *= vflip ? -1.0f : 1.0f;
if (_tile) { if (texdraw == focused) {
// Do nothing, we only needed to calculate the rectangle.
} else if (_tile) {
draw_texture_rect(texdraw, Rect2(ofs, size), _tile); draw_texture_rect(texdraw, Rect2(ofs, size), _tile);
} else { } else {
draw_texture_rect_region(texdraw, Rect2(ofs, size), _texture_region); draw_texture_rect_region(texdraw, Rect2(ofs, size), _texture_region);
@ -233,7 +241,7 @@ void TextureButton::_notification(int p_what) {
_position_rect = Rect2(); _position_rect = Rect2();
} }
if (has_focus() && focused.is_valid()) { if (draw_focus) {
draw_texture_rect(focused, Rect2(ofs, size), false); draw_texture_rect(focused, Rect2(ofs, size), false);
}; };
} break; } break;

View File

@ -109,7 +109,7 @@ void PortalGameplayMonitor::unload(PortalRenderer &p_portal_renderer) {
for (int n = 0; n < _active_room_ids_prev->size(); n++) { for (int n = 0; n < _active_room_ids_prev->size(); n++) {
int room_id = (*_active_room_ids_prev)[n]; int room_id = (*_active_room_ids_prev)[n];
VSRoom &room = p_portal_renderer.get_room(room_id); VSRoom &room = p_portal_renderer.get_room(room_id);
room.last_gameplay_tick_hit = 0; room.last_room_tick_hit = 0;
VisualServerCallbacks::Message msg; VisualServerCallbacks::Message msg;
msg.object_id = room._godot_instance_ID; msg.object_id = room._godot_instance_ID;
@ -121,7 +121,7 @@ void PortalGameplayMonitor::unload(PortalRenderer &p_portal_renderer) {
for (int n = 0; n < _active_roomgroup_ids_prev->size(); n++) { for (int n = 0; n < _active_roomgroup_ids_prev->size(); n++) {
int roomgroup_id = (*_active_roomgroup_ids_prev)[n]; int roomgroup_id = (*_active_roomgroup_ids_prev)[n];
VSRoomGroup &roomgroup = p_portal_renderer.get_roomgroup(roomgroup_id); VSRoomGroup &roomgroup = p_portal_renderer.get_roomgroup(roomgroup_id);
roomgroup.last_gameplay_tick_hit = 0; roomgroup.last_room_tick_hit = 0;
VisualServerCallbacks::Message msg; VisualServerCallbacks::Message msg;
msg.object_id = roomgroup._godot_instance_ID; msg.object_id = roomgroup._godot_instance_ID;
@ -133,7 +133,7 @@ void PortalGameplayMonitor::unload(PortalRenderer &p_portal_renderer) {
for (int n = 0; n < _active_sghost_ids_prev->size(); n++) { for (int n = 0; n < _active_sghost_ids_prev->size(); n++) {
int id = (*_active_sghost_ids_prev)[n]; int id = (*_active_sghost_ids_prev)[n];
VSStaticGhost &ghost = p_portal_renderer.get_static_ghost(id); VSStaticGhost &ghost = p_portal_renderer.get_static_ghost(id);
ghost.last_gameplay_tick_hit = 0; ghost.last_room_tick_hit = 0;
VisualServerCallbacks::Message msg; VisualServerCallbacks::Message msg;
msg.object_id = ghost.object_id; msg.object_id = ghost.object_id;
@ -185,6 +185,9 @@ void PortalGameplayMonitor::update_gameplay(PortalRenderer &p_portal_renderer, c
// if there is no change in the source room IDs, then we can optimize out a lot of the checks // if there is no change in the source room IDs, then we can optimize out a lot of the checks
// (anything not to do with roamers) // (anything not to do with roamers)
bool source_rooms_changed = _source_rooms_changed(p_source_room_ids, p_num_source_rooms); bool source_rooms_changed = _source_rooms_changed(p_source_room_ids, p_num_source_rooms);
if (source_rooms_changed) {
_room_tick++;
}
// lock output // lock output
VisualServerCallbacks *callbacks = VSG::scene->get_callbacks(); VisualServerCallbacks *callbacks = VSG::scene->get_callbacks();
@ -249,7 +252,7 @@ void PortalGameplayMonitor::update_gameplay(PortalRenderer &p_portal_renderer, c
const VSRoom &room = p_portal_renderer.get_room(room_id); const VSRoom &room = p_portal_renderer.get_room(room_id);
// gone out of view // gone out of view
if (room.last_gameplay_tick_hit != _gameplay_tick) { if (room.last_room_tick_hit != _room_tick) {
VisualServerCallbacks::Message msg; VisualServerCallbacks::Message msg;
msg.object_id = room._godot_instance_ID; msg.object_id = room._godot_instance_ID;
msg.type = _exit_callback_type; msg.type = _exit_callback_type;
@ -264,7 +267,7 @@ void PortalGameplayMonitor::update_gameplay(PortalRenderer &p_portal_renderer, c
const VSRoomGroup &roomgroup = p_portal_renderer.get_roomgroup(roomgroup_id); const VSRoomGroup &roomgroup = p_portal_renderer.get_roomgroup(roomgroup_id);
// gone out of view // gone out of view
if (roomgroup.last_gameplay_tick_hit != _gameplay_tick) { if (roomgroup.last_room_tick_hit != _room_tick) {
VisualServerCallbacks::Message msg; VisualServerCallbacks::Message msg;
msg.object_id = roomgroup._godot_instance_ID; msg.object_id = roomgroup._godot_instance_ID;
msg.type = _exit_callback_type; msg.type = _exit_callback_type;
@ -279,7 +282,7 @@ void PortalGameplayMonitor::update_gameplay(PortalRenderer &p_portal_renderer, c
VSStaticGhost &ghost = p_portal_renderer.get_static_ghost(id); VSStaticGhost &ghost = p_portal_renderer.get_static_ghost(id);
// gone out of view // gone out of view
if (ghost.last_gameplay_tick_hit != _gameplay_tick) { if (ghost.last_room_tick_hit != _room_tick) {
VisualServerCallbacks::Message msg; VisualServerCallbacks::Message msg;
msg.object_id = ghost.object_id; msg.object_id = ghost.object_id;
msg.type = VisualServerCallbacks::CALLBACK_NOTIFICATION_EXIT_GAMEPLAY; msg.type = VisualServerCallbacks::CALLBACK_NOTIFICATION_EXIT_GAMEPLAY;
@ -293,7 +296,7 @@ void PortalGameplayMonitor::update_gameplay(PortalRenderer &p_portal_renderer, c
callbacks->unlock(); callbacks->unlock();
// swap the current and previous lists // swap the current and previous lists
_swap(); _swap(source_rooms_changed);
} }
void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_renderer, int p_room_id, bool p_source_rooms_changed) { void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_renderer, int p_room_id, bool p_source_rooms_changed) {
@ -367,14 +370,14 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende
// later tests only relevant if a room has just come into play // later tests only relevant if a room has just come into play
bool room_came_into_play = false; bool room_came_into_play = false;
if (room.last_gameplay_tick_hit != _gameplay_tick) { if (room.last_room_tick_hit != _room_tick) {
room_came_into_play = true; room_came_into_play = true;
// add the room to the active list // add the room to the active list
_active_room_ids_curr->push_back(p_room_id); _active_room_ids_curr->push_back(p_room_id);
// if wasn't present in the tick before, add the notification to enter // if wasn't present in the tick before, add the notification to enter
if (room.last_gameplay_tick_hit != (_gameplay_tick - 1)) { if (room.last_room_tick_hit != (_room_tick - 1)) {
VisualServerCallbacks::Message msg; VisualServerCallbacks::Message msg;
msg.object_id = room._godot_instance_ID; msg.object_id = room._godot_instance_ID;
msg.type = _enter_callback_type; msg.type = _enter_callback_type;
@ -383,7 +386,7 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende
} }
// mark as done // mark as done
room.last_gameplay_tick_hit = _gameplay_tick; room.last_room_tick_hit = _room_tick;
} }
// no need to do later tests // no need to do later tests
@ -398,12 +401,12 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende
VSRoomGroup &roomgroup = p_portal_renderer.get_roomgroup(roomgroup_id); VSRoomGroup &roomgroup = p_portal_renderer.get_roomgroup(roomgroup_id);
if (roomgroup.last_gameplay_tick_hit != _gameplay_tick) { if (roomgroup.last_room_tick_hit != _room_tick) {
// add the room to the active list // add the room to the active list
_active_roomgroup_ids_curr->push_back(roomgroup_id); _active_roomgroup_ids_curr->push_back(roomgroup_id);
// if wasn't present in the tick before, add the notification to enter // if wasn't present in the tick before, add the notification to enter
if (roomgroup.last_gameplay_tick_hit != (_gameplay_tick - 1)) { if (roomgroup.last_room_tick_hit != (_room_tick - 1)) {
VisualServerCallbacks::Message msg; VisualServerCallbacks::Message msg;
msg.object_id = roomgroup._godot_instance_ID; msg.object_id = roomgroup._godot_instance_ID;
msg.type = _enter_callback_type; msg.type = _enter_callback_type;
@ -412,7 +415,7 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende
} }
// mark as done // mark as done
roomgroup.last_gameplay_tick_hit = _gameplay_tick; roomgroup.last_room_tick_hit = _room_tick;
} }
} // for through roomgroups } // for through roomgroups
@ -425,14 +428,14 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende
VSStaticGhost &ghost = p_portal_renderer.get_static_ghost(id); VSStaticGhost &ghost = p_portal_renderer.get_static_ghost(id);
// done already? // done already?
if (ghost.last_gameplay_tick_hit == _gameplay_tick) if (ghost.last_room_tick_hit == _room_tick)
continue; continue;
// add to the active list // add to the active list
_active_sghost_ids_curr->push_back(id); _active_sghost_ids_curr->push_back(id);
// if wasn't present in the tick before, add the notification to enter // if wasn't present in the tick before, add the notification to enter
if (ghost.last_gameplay_tick_hit != (_gameplay_tick - 1)) { if (ghost.last_room_tick_hit != (_room_tick - 1)) {
VisualServerCallbacks::Message msg; VisualServerCallbacks::Message msg;
msg.object_id = ghost.object_id; msg.object_id = ghost.object_id;
msg.type = VisualServerCallbacks::CALLBACK_NOTIFICATION_ENTER_GAMEPLAY; msg.type = VisualServerCallbacks::CALLBACK_NOTIFICATION_ENTER_GAMEPLAY;
@ -441,11 +444,11 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende
} }
// mark as done // mark as done
ghost.last_gameplay_tick_hit = _gameplay_tick; ghost.last_room_tick_hit = _room_tick;
} }
} }
void PortalGameplayMonitor::_swap() { void PortalGameplayMonitor::_swap(bool p_source_rooms_changed) {
LocalVector<uint32_t, int32_t> *temp = _active_moving_pool_ids_curr; LocalVector<uint32_t, int32_t> *temp = _active_moving_pool_ids_curr;
_active_moving_pool_ids_curr = _active_moving_pool_ids_prev; _active_moving_pool_ids_curr = _active_moving_pool_ids_prev;
_active_moving_pool_ids_prev = temp; _active_moving_pool_ids_prev = temp;
@ -456,18 +459,20 @@ void PortalGameplayMonitor::_swap() {
_active_rghost_pool_ids_prev = temp; _active_rghost_pool_ids_prev = temp;
_active_rghost_pool_ids_curr->clear(); _active_rghost_pool_ids_curr->clear();
temp = _active_room_ids_curr; if (p_source_rooms_changed) {
_active_room_ids_curr = _active_room_ids_prev; temp = _active_room_ids_curr;
_active_room_ids_prev = temp; _active_room_ids_curr = _active_room_ids_prev;
_active_room_ids_curr->clear(); _active_room_ids_prev = temp;
_active_room_ids_curr->clear();
temp = _active_roomgroup_ids_curr; temp = _active_roomgroup_ids_curr;
_active_roomgroup_ids_curr = _active_roomgroup_ids_prev; _active_roomgroup_ids_curr = _active_roomgroup_ids_prev;
_active_roomgroup_ids_prev = temp; _active_roomgroup_ids_prev = temp;
_active_roomgroup_ids_curr->clear(); _active_roomgroup_ids_curr->clear();
temp = _active_sghost_ids_curr; temp = _active_sghost_ids_curr;
_active_sghost_ids_curr = _active_sghost_ids_prev; _active_sghost_ids_curr = _active_sghost_ids_prev;
_active_sghost_ids_prev = temp; _active_sghost_ids_prev = temp;
_active_sghost_ids_curr->clear(); _active_sghost_ids_curr->clear();
}
} }

View File

@ -52,10 +52,17 @@ public:
private: private:
void _update_gameplay_room(PortalRenderer &p_portal_renderer, int p_room_id, bool p_source_rooms_changed); void _update_gameplay_room(PortalRenderer &p_portal_renderer, int p_room_id, bool p_source_rooms_changed);
bool _source_rooms_changed(const int *p_source_room_ids, int p_num_source_rooms); bool _source_rooms_changed(const int *p_source_room_ids, int p_num_source_rooms);
void _swap(); void _swap(bool p_source_rooms_changed);
// gameplay ticks happen every physics tick
uint32_t _gameplay_tick = 1; uint32_t _gameplay_tick = 1;
// Room ticks only happen when the rooms the cameras are within change.
// This is an optimization. This tick needs to be maintained separately from _gameplay_tick
// because testing against the previous tick is used to determine whether to send enter or exit
// gameplay notifications, and this must be synchronized differently for rooms, roomgroups and static ghosts.
uint32_t _room_tick = 1;
// we need two version, current and previous // we need two version, current and previous
LocalVector<uint32_t, int32_t> _active_moving_pool_ids[2]; LocalVector<uint32_t, int32_t> _active_moving_pool_ids[2];
LocalVector<uint32_t, int32_t> *_active_moving_pool_ids_curr; LocalVector<uint32_t, int32_t> *_active_moving_pool_ids_curr;

View File

@ -68,7 +68,7 @@ struct VSStaticGhost {
ObjectID object_id; ObjectID object_id;
uint32_t last_tick_hit = 0; uint32_t last_tick_hit = 0;
uint32_t last_gameplay_tick_hit = 0; uint32_t last_room_tick_hit = 0;
}; };
class PortalRenderer { class PortalRenderer {

View File

@ -227,7 +227,7 @@ struct VSRoomGroup {
} }
// used for calculating gameplay notifications // used for calculating gameplay notifications
uint32_t last_gameplay_tick_hit = 0; uint32_t last_room_tick_hit = 0;
ObjectID _godot_instance_ID = 0; ObjectID _godot_instance_ID = 0;
@ -257,7 +257,7 @@ struct VSRoom {
_secondary_pvs_size = 0; _secondary_pvs_size = 0;
_priority = 0; _priority = 0;
_contains_internal_rooms = false; _contains_internal_rooms = false;
last_gameplay_tick_hit = 0; last_room_tick_hit = 0;
} }
void cleanup_after_conversion() { void cleanup_after_conversion() {
@ -354,7 +354,7 @@ struct VSRoom {
uint16_t _secondary_pvs_size = 0; uint16_t _secondary_pvs_size = 0;
// used for calculating gameplay notifications // used for calculating gameplay notifications
uint32_t last_gameplay_tick_hit = 0; uint32_t last_room_tick_hit = 0;
// convex hull of the room, either determined by geometry or manual bound // convex hull of the room, either determined by geometry or manual bound
LocalVector<Plane, int32_t> _planes; LocalVector<Plane, int32_t> _planes;