diff --git a/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake index f653a54505..7d33a65bc7 100644 --- a/AutomatedTesting/Gem/Code/enabled_gems.cmake +++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake @@ -54,5 +54,6 @@ set(ENABLED_GEMS AWSMetrics PrefabBuilder AudioSystem + Terrain Profiler ) diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt index fd3222ba83..d2b7075e22 100644 --- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt @@ -56,6 +56,9 @@ add_subdirectory(streaming) ## Smoke ## add_subdirectory(smoke) +## Terrain ## +add_subdirectory(Terrain) + ## AWS ## add_subdirectory(AWS) diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Terrain/CMakeLists.txt new file mode 100644 index 0000000000..9f8ba06829 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) + + ly_add_pytest( + NAME AutomatedTesting::TerrainTests_Main + TEST_SUITE main + TEST_SERIAL + PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py + RUNTIME_DEPENDENCIES + Legacy::Editor + AZ::AssetProcessor + AutomatedTesting.Assets + COMPONENT + Terrain + ) + +endif() diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges.py b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges.py new file mode 100644 index 0000000000..aba506ea20 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges.py @@ -0,0 +1,90 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +#fmt: off +class Tests(): + create_test_entity = ("Entity created successfully", "Failed to create Entity") + add_axis_aligned_box_shape = ("Axis Aligned Box Shape component added", "Failed to add Axis Aligned Box Shape component") + add_terrain_collider = ("Terrain Physics Heightfield Collider component added", "Failed to add a Terrain Physics Heightfield Collider component") + box_dimensions_changed = ("Aabb dimensions changed successfully", "Failed change Aabb dimensions") + configuration_changed = ("Terrain size changed successfully", "Failed terrain size change") + no_errors_and_warnings_found = ("No errors and warnings found", "Found errors and warnings") +#fmt: on + +def TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges(): + """ + Summary: + Test aspects of the TerrainHeightGradientList through the BehaviorContext and the Property Tree. + + Test Steps: + Expected Behavior: + The Editor is stable there are no warnings or errors. + + Test Steps: + 1) Load the base level + 2) Create test entity + 3) Start the Tracer to catch any errors and warnings + 4) Add the Axis Aligned Box Shape and Terrain Physics Heightfield Collider components + 5) Change the Axis Aligned Box Shape dimensions + 6) Check the Heightfield provider is returning the correct size + 7) Verify there are no errors and warnings in the logs + + + :return: None + """ + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer + import azlmbr.legacy.general as general + import azlmbr.physics as physics + import azlmbr.math as azmath + import azlmbr.bus as bus + import sys + import math + + SET_BOX_X_SIZE = 5.0 + SET_BOX_Y_SIZE = 6.0 + EXPECTED_COLUMN_SIZE = SET_BOX_X_SIZE + 1 + EXPECTED_ROW_SIZE = SET_BOX_Y_SIZE + 1 + helper.init_idle() + + # 1) Load the level + helper.open_level("", "Base") + + # 2) Create test entity + test_entity = EditorEntity.create_editor_entity("TestEntity") + Report.result(Tests.create_test_entity, test_entity.id.IsValid()) + + # 3) Start the Tracer to catch any errors and warnings + with Tracer() as section_tracer: + # 4) Add the Axis Aligned Box Shape and Terrain Physics Heightfield Collider components + aaBoxShape_component = test_entity.add_component("Axis Aligned Box Shape") + Report.result(Tests.add_axis_aligned_box_shape, test_entity.has_component("Axis Aligned Box Shape")) + terrainPhysics_component = test_entity.add_component("Terrain Physics Heightfield Collider") + Report.result(Tests.add_terrain_collider, test_entity.has_component("Terrain Physics Heightfield Collider")) + + # 5) Change the Axis Aligned Box Shape dimensions + aaBoxShape_component.set_component_property_value("Axis Aligned Box Shape|Box Configuration|Dimensions", azmath.Vector3(SET_BOX_X_SIZE, SET_BOX_Y_SIZE, 1.0)) + add_check = aaBoxShape_component.get_component_property_value("Axis Aligned Box Shape|Box Configuration|Dimensions") == azmath.Vector3(SET_BOX_X_SIZE, SET_BOX_Y_SIZE, 1.0) + Report.result(Tests.box_dimensions_changed, add_check) + + # 6) Check the Heightfield provider is returning the correct size + columns = physics.HeightfieldProviderRequestsBus(bus.Broadcast, "GetHeightfieldGridColumns") + rows = physics.HeightfieldProviderRequestsBus(bus.Broadcast, "GetHeightfieldGridRows") + Report.result(Tests.configuration_changed, math.isclose(columns, EXPECTED_COLUMN_SIZE) and math.isclose(rows, EXPECTED_ROW_SIZE)) + + helper.wait_for_condition(lambda: section_tracer.has_errors or section_tracer.has_asserts, 1.0) + for error_info in section_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in section_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges) diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py new file mode 100644 index 0000000000..620d84d7db --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py @@ -0,0 +1,25 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT + +""" + +# This suite consists of all test cases that are passing and have been verified. + +import pytest +import os +import sys + +from ly_test_tools import LAUNCHERS +from ly_test_tools.o3de.editor_test import EditorTestSuite, EditorSingleTest + +@pytest.mark.SUITE_main +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(EditorTestSuite): + #global_extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"] + + class test_AxisAlignedBoxShape_ConfigurationWorks(EditorSingleTest): + from .EditorScripts import TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/__init__.py b/AutomatedTesting/Gem/PythonTests/Terrain/__init__.py new file mode 100644 index 0000000000..f5193b300e --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/__init__.py @@ -0,0 +1,6 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" diff --git a/AutomatedTesting/Levels/Base/Base.prefab b/AutomatedTesting/Levels/Base/Base.prefab new file mode 100644 index 0000000000..f7e42e7731 --- /dev/null +++ b/AutomatedTesting/Levels/Base/Base.prefab @@ -0,0 +1,53 @@ +{ + "ContainerEntity": { + "Id": "Entity_[1146574390643]", + "Name": "Level", + "Components": { + "Component_[10641544592923449938]": { + "$type": "EditorInspectorComponent", + "Id": 10641544592923449938 + }, + "Component_[12039882709170782873]": { + "$type": "EditorOnlyEntityComponent", + "Id": 12039882709170782873 + }, + "Component_[12265484671603697631]": { + "$type": "EditorPendingCompositionComponent", + "Id": 12265484671603697631 + }, + "Component_[14126657869720434043]": { + "$type": "EditorEntitySortComponent", + "Id": 14126657869720434043 + }, + "Component_[15230859088967841193]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 15230859088967841193, + "Parent Entity": "" + }, + "Component_[16239496886950819870]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 16239496886950819870 + }, + "Component_[5688118765544765547]": { + "$type": "EditorEntityIconComponent", + "Id": 5688118765544765547 + }, + "Component_[6545738857812235305]": { + "$type": "SelectionComponent", + "Id": 6545738857812235305 + }, + "Component_[7247035804068349658]": { + "$type": "EditorPrefabComponent", + "Id": 7247035804068349658 + }, + "Component_[9307224322037797205]": { + "$type": "EditorLockComponent", + "Id": 9307224322037797205 + }, + "Component_[9562516168917670048]": { + "$type": "EditorVisibilityComponent", + "Id": 9562516168917670048 + } + } + } +} \ No newline at end of file diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index 323e834413..b6b09148eb 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include "Application.h" #include @@ -318,6 +319,8 @@ namespace AzFramework AzFramework::SurfaceData::SurfaceTagWeight::Reflect(context); AzFramework::SurfaceData::SurfacePoint::Reflect(context); AzFramework::Terrain::TerrainDataRequests::Reflect(context); + Physics::HeightfieldProviderRequests::Reflect(context); + Physics::HeightMaterialPoint::Reflect(context); if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) { diff --git a/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.cpp b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.cpp new file mode 100644 index 0000000000..38fac9655c --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include "HeightfieldProviderBus.h" +#include +#include +#include + +namespace Physics +{ + void HeightfieldProviderRequests::Reflect(AZ::ReflectContext* context) + { + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("HeightfieldProviderRequestsBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Module, "physics") + ->Attribute(AZ::Script::Attributes::Category, "PhysX") + ->Event("GetHeightfieldGridSpacing", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridSpacing) + ->Event("GetHeightfieldAabb", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldAabb) + ->Event("GetHeightfieldTransform", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldTransform) + ->Event("GetMaterialList", &Physics::HeightfieldProviderRequestsBus::Events::GetMaterialList) + ->Event("GetHeights", &Physics::HeightfieldProviderRequestsBus::Events::GetHeights) + ->Event("GetHeightsAndMaterials", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightsAndMaterials) + ->Event("GetHeightfieldMinHeight", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldMinHeight) + ->Event("GetHeightfieldMaxHeight", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldMaxHeight) + ->Event("GetHeightfieldGridColumns", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridColumns) + ->Event("GetHeightfieldGridRows", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridRows) + ; + } + } + + void HeightMaterialPoint::Reflect(AZ::ReflectContext* context) + { + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class()->Attribute(AZ::Script::Attributes::Category, "Physics"); + } + } + +} // namespace Physics diff --git a/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h index 73523ee1ba..da361f0a2b 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h @@ -26,10 +26,25 @@ namespace Physics struct HeightMaterialPoint { + HeightMaterialPoint( + float height = 0.0f, QuadMeshType type = QuadMeshType::SubdivideUpperLeftToBottomRight, uint8_t index = 0) + : m_height(height) + , m_quadMeshType(type) + , m_materialIndex(index) + , m_padding(0) + { + } + + virtual ~HeightMaterialPoint() = default; + + static void Reflect(AZ::ReflectContext* context); + + AZ_RTTI(HeightMaterialPoint, "{DF167ED4-24E6-4F7B-8AB7-42622F7DBAD3}"); float m_height{ 0.0f }; //!< Holds the height of this point in the heightfield relative to the heightfield entity location. QuadMeshType m_quadMeshType{ QuadMeshType::SubdivideUpperLeftToBottomRight }; //!< By default, create two triangles like this |\|, where this point is in the upper left corner. uint8_t m_materialIndex{ 0 }; //!< The surface material index for the upper left corner of this quad. uint16_t m_padding{ 0 }; //!< available for future use. + }; //! An interface to provide heightfield values. @@ -37,6 +52,8 @@ namespace Physics : public AZ::ComponentBus { public: + static void Reflect(AZ::ReflectContext* context); + //! Returns the distance between each height in the map. //! @return Vector containing Column Spacing, Rows Spacing. virtual AZ::Vector2 GetHeightfieldGridSpacing() const = 0; @@ -46,11 +63,27 @@ namespace Physics //! @param numRows contains the size of the grid in the y direction. virtual void GetHeightfieldGridSize(int32_t& numColumns, int32_t& numRows) const = 0; + //! Returns the height field gridsize columns. + //! @return the size of the grid in the x direction. + virtual int32_t GetHeightfieldGridColumns() const = 0; + + //! Returns the height field gridsize rows. + //! @return the size of the grid in the y direction. + virtual int32_t GetHeightfieldGridRows() const = 0; + //! Returns the height field min and max height bounds. //! @param minHeightBounds contains the minimum height that the heightfield can contain. //! @param maxHeightBounds contains the maximum height that the heightfield can contain. virtual void GetHeightfieldHeightBounds(float& minHeightBounds, float& maxHeightBounds) const = 0; + //! Returns the height field min height bounds. + //! @return the minimum height that the heightfield can contain. + virtual float GetHeightfieldMinHeight() const = 0; + + //! Returns the height field max height bounds. + //! @return the maximum height that the heightfield can contain. + virtual float GetHeightfieldMaxHeight() const = 0; + //! Returns the AABB of the heightfield. //! This is provided separately from the shape AABB because the heightfield might choose to modify the AABB bounds. //! @return AABB of the heightfield. diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp index 222bc48dda..d78d4e0943 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp @@ -360,6 +360,11 @@ namespace Physics ->Field("MaterialId", &Physics::MaterialId::m_id) ; } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class()->Attribute(AZ::Script::Attributes::Category, "Physics"); + } } MaterialId MaterialId::Create() diff --git a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake index e03d166cfc..13d9003031 100644 --- a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake +++ b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake @@ -229,6 +229,7 @@ set(FILES Physics/Configuration/SystemConfiguration.h Physics/Configuration/SystemConfiguration.cpp Physics/HeightfieldProviderBus.h + Physics/HeightfieldProviderBus.cpp Physics/SimulatedBodies/RigidBody.h Physics/SimulatedBodies/RigidBody.cpp Physics/SimulatedBodies/StaticRigidBody.h diff --git a/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h b/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h index 7e500881c0..d462c30158 100644 --- a/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h +++ b/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h @@ -69,6 +69,10 @@ namespace UnitTest MOCK_CONST_METHOD1(UpdateHeights, AZStd::vector(const AZ::Aabb& dirtyRegion)); MOCK_CONST_METHOD1(UpdateHeightsAndMaterials, AZStd::vector(const AZ::Aabb& dirtyRegion)); MOCK_CONST_METHOD0(GetHeightfieldAabb, AZ::Aabb()); + MOCK_CONST_METHOD0(GetHeightfieldMinHeight, float()); + MOCK_CONST_METHOD0(GetHeightfieldMaxHeight, float()); + MOCK_CONST_METHOD0(GetHeightfieldGridColumns, int32_t()); + MOCK_CONST_METHOD0(GetHeightfieldGridRows, int32_t()); }; } // namespace UnitTest diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp index 9262937317..6c76e90fd0 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp @@ -193,6 +193,22 @@ namespace Terrain minHeightBounds = -maxHeightBounds; } + float TerrainPhysicsColliderComponent::GetHeightfieldMinHeight() const + { + float minHeightBounds{ 0.0f }; + float maxHeightBounds{ 0.0f }; + GetHeightfieldHeightBounds(minHeightBounds, maxHeightBounds); + return minHeightBounds; + } + + float TerrainPhysicsColliderComponent::GetHeightfieldMaxHeight() const + { + float minHeightBounds{ 0.0f }; + float maxHeightBounds{ 0.0f }; + GetHeightfieldHeightBounds(minHeightBounds, maxHeightBounds); + return maxHeightBounds; + } + AZ::Transform TerrainPhysicsColliderComponent::GetHeightfieldTransform() const { // We currently don't support rotation of terrain heightfields. @@ -296,6 +312,24 @@ namespace Terrain numRows = aznumeric_cast((bounds.GetMax().GetY() - bounds.GetMin().GetY()) / gridResolution.GetY()); } + int32_t TerrainPhysicsColliderComponent::GetHeightfieldGridColumns() const + { + int32_t numColumns{ 0 }; + int32_t numRows{ 0 }; + + GetHeightfieldGridSize(numColumns, numRows); + return numColumns; + } + + int32_t TerrainPhysicsColliderComponent::GetHeightfieldGridRows() const + { + int32_t numColumns{ 0 }; + int32_t numRows{ 0 }; + + GetHeightfieldGridSize(numColumns, numRows); + return numRows; + } + AZStd::vector TerrainPhysicsColliderComponent::GetMaterialList() const { return AZStd::vector(); diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h index e268223689..6462909c89 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h @@ -58,7 +58,11 @@ namespace Terrain // HeightfieldProviderRequestsBus AZ::Vector2 GetHeightfieldGridSpacing() const override; void GetHeightfieldGridSize(int32_t& numColumns, int32_t& numRows) const override; + int32_t GetHeightfieldGridColumns() const override; + int32_t GetHeightfieldGridRows() const override; void GetHeightfieldHeightBounds(float& minHeightBounds, float& maxHeightBounds) const override; + float GetHeightfieldMinHeight() const override; + float GetHeightfieldMaxHeight() const override; AZ::Aabb GetHeightfieldAabb() const override; AZ::Transform GetHeightfieldTransform() const override; AZStd::vector GetMaterialList() const override; diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py index 781977cf33..392838d180 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py @@ -634,6 +634,7 @@ class EditorTestSuite(): else: test_result = Result.Fail.create(test_spec, output, editor_log_content) except WaitTimeoutError: + output = editor.get_output() editor.kill() editor_log_content = editor_utils.retrieve_editor_log_content(run_id, log_name, workspace) test_result = Result.Timeout.create(test_spec, output, test_spec.timeout, editor_log_content) diff --git a/system_windows_pc.cfg b/system_windows_pc.cfg index aa53ed9323..e34c35e581 100644 --- a/system_windows_pc.cfg +++ b/system_windows_pc.cfg @@ -15,3 +15,4 @@ r_ShadersAllowCompilation = 1 -- Localization Settings sys_localization_format=0 +log_RemoteConsoleAllowedAddresses=127.0.0.1