Browse Source

Script only game runtime (#16903)

* Script-only-mode continuation

* A generic launcher is built when building without targets
* The generic launcher is used as the launcher in script only mode
* Script Only projects now include a package.sh / package.bat
* Script only projects now include an example seed and "start" level
* Script only projects auto start the "start" level.
* When building an installer, we generate 3rd party cmake files that
  can be used to copy the missing dependencies from the installer
  into script-only projects.  These scripts are only used in
  script-only projects.

Signed-off-by: Nicholas Lawson <[email protected]>

* Fixes for the launcher due to conflicts

Signed-off-by: Nicholas Lawson <[email protected]>

* Fixes for the script-only mode feature (Due to PR)

* Fixes comments from the PR
* Adds the exported project folder to AP ignores so that generating
  a project using the package script doesn't cause the next run
  of the engine to add those generated package files into the cache.
* Adds a check for using 'o3de' as a project name

Signed-off-by: Nicholas Lawson <[email protected]>

* Fix the fatal error message

Signed-off-by: Nicholas Lawson <[email protected]>

* Update for PR code comments

Signed-off-by: Nicholas Lawson <[email protected]>

* PR Comments addressed.

Signed-off-by: Nicholas Lawson <[email protected]>

* Updates to make it work with the new development branch

I had to resolve conflicts, and found that there is no longer a
need for a separate export script compared to a source build project.

Signed-off-by: Nicholas Lawson <[email protected]>

* Fix a problem that only happens when building engine-centric
with a project specified.

Signed-off-by: Nicholas Lawson <[email protected]>

* Fix for AR failure

Signed-off-by: Nicholas Lawson <[email protected]>

* What a spelling mistake!

Signed-off-by: Nicholas Lawson <[email protected]>

---------

Signed-off-by: Nicholas Lawson <[email protected]>
Nicholas Lawson 1 year ago
parent
commit
5aea1a28f7

+ 21 - 2
Code/LauncherUnified/Launcher.cpp

@@ -411,7 +411,26 @@ namespace O3DELauncher
             // Settings registry must be available at this point in order to continue
             return ReturnCode::ErrValidation;
         }
-        const AZStd::string_view buildTargetName = GetBuildTargetName();
+
+        // Save the build target name (usually myprojectname_gamelauncher, or myprojectname_serverlauncher, etc)
+        // into the specialization list, so that the regset files for xxxxx.myprojectname_gamelauncher are included in the loaded set.
+        // in generic mode, this needs to be updated to a name based on the project name, so it is not a string view, here.
+        AZ::SettingsRegistryInterface::FixedValueString buildTargetName(GetBuildTargetName());
+
+        // retrieve the project name as specified by the actual project.json (or updated from command line)
+        AZ::SettingsRegistryInterface::FixedValueString updatedProjectName = AZ::Utils::GetProjectName();
+        if (IsGenericLauncher())
+        {
+            constexpr AZStd::string_view O3DEPrefix = "O3DE_";
+            // this will always be the value O3DE_xxxxx where xxxxx is the type of target ("GameLauncher/ServerLauncher/UnifiedLauncher/etc")
+            // and O3DE is a placeholder for the project name.  Replace the "O3DE_" part with "{ProjectName}_" (keeping the underscore).
+            if (buildTargetName.starts_with(O3DEPrefix))
+            {
+                auto replacementName = AZ::SettingsRegistryInterface::FixedValueString::format(
+                    "%.*s_", aznumeric_cast<int>(updatedProjectName.size()), updatedProjectName.data());
+                buildTargetName.replace(0, O3DEPrefix.size(), replacementName);
+            }
+        }
         AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(*settingsRegistry, buildTargetName);
 
         //Store the launcher type to the Settings Registry
@@ -432,7 +451,7 @@ namespace O3DELauncher
         AZ_TracePrintf("Launcher", R"(Running project "%.*s")" "\n"
             R"(The project name has been successfully set in the Settings Registry at key "%s/project_name")"
             R"( for Launcher target "%.*s")" "\n",
-            aznumeric_cast<int>(launcherProjectName.size()), launcherProjectName.data(),
+            aznumeric_cast<int>(updatedProjectName.size()), updatedProjectName.data(),
             AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey,
             aznumeric_cast<int>(buildTargetName.size()), buildTargetName.data());
 

+ 3 - 0
Code/LauncherUnified/Launcher.h

@@ -91,6 +91,9 @@ namespace O3DELauncher
     //! This function returns the build system target name
     AZStd::string_view GetBuildTargetName();
 
+    //! This function returns whether its the Generic launcher or not (for Script-Only mode)
+    bool IsGenericLauncher();
+
     //////////////////////////////////////////////////////////////////////////
     // The following functions are defined per launcher type (e.g. Client/Server/Unified)
     //////////////////////////////////////////////////////////////////////////

+ 15 - 0
Code/LauncherUnified/LauncherProject.cpp

@@ -6,6 +6,12 @@
  *
  */
 
+// note that this is the only file pulled into a launcher target that has the
+// defines set such as LY_CMAKE_TARGET, and LY_PROJECT_NAME, other files come from a static library
+// which do not provide those defines.
+// note that the tests use a mock implementation of this file, see Tests/Test.cpp
+// If you modify this file or the interface launcher.h, make sure to update the mock implementation as well.
+
 #include <AzCore/std/string/string_view.h>
 
 #if defined(AZ_MONOLITHIC_BUILD)
@@ -32,4 +38,13 @@ namespace O3DELauncher
 #endif
         return { LY_PROJECT_NAME };
     }
+
+    bool IsGenericLauncher()
+    {
+#if defined(O3DE_IS_GENERIC_LAUNCHER)
+        return true;
+#else
+        return false;
+#endif
+    }
 }

+ 9 - 0
Code/LauncherUnified/Tests/Test.cpp

@@ -8,6 +8,10 @@
 
 #include <AzCore/std/string/string_view.h>
 
+// this is a mock O3DE Launcher implementation for unit tests and is used
+// instead of LauncherProject.cpp.  If you modify LauncherProject.cpp or the interface launcher.h, make sure
+// to update this file as well.
+
 namespace O3DELauncher
 {
     bool WaitForAssetProcessorConnect()
@@ -47,4 +51,9 @@ namespace O3DELauncher
     {
         return { "Tests" };
     }
+
+    bool IsGenericLauncher()
+    {
+        return false;
+    }
 }

+ 72 - 34
Code/LauncherUnified/launcher_generator.cmake

@@ -27,46 +27,62 @@ set(SERVER_VARIANT_HeadlessServerLauncher HeadlessServers)
 # and allow them to be overridden to "INTERFACE" in script-only mode.
 set(LAUNCHER_TARGET_PROPERTY_TYPE "PRIVATE")
 
-# in script_only_mode, generate interface targets.  If a real 'generic launcher' is added, this would
-# also be an opportunity to add imported exectables.
-if (O3DE_SCRIPT_ONLY)
-    set(PAL_TRAIT_LAUNCHERUNIFIED_LAUNCHER_TYPE INTERFACE)
-    set(SERVER_LAUNCHERTYPE_ServerLauncher INTERFACE)
-    set(SERVER_LAUNCHERTYPE_HeadlessServerLauncher INTERFACE)
-    set(LAUNCHER_TARGET_PROPERTY_TYPE INTERFACE) # you can only set interface properties on interfaces.
-endif()
-
 # Launcher targets for a project need to be generated when configuring a project.
 # When building the engine source, this file will be included by LauncherUnified's CMakeLists.txt
 # When using an installed engine, this file will be included by the FindLauncherGenerator.cmake script
 get_property(SERVER_LAUNCHER_TYPES GLOBAL PROPERTY SERVER_LAUNCHER_TYPES)
 get_property(O3DE_PROJECTS_NAME GLOBAL PROPERTY O3DE_PROJECTS_NAME)
-foreach(project_name project_path IN ZIP_LISTS O3DE_PROJECTS_NAME LY_PROJECTS)
 
-    # Computes the realpath to the project
-    # If the project_path is relative, it is evaluated relative to the ${LY_ROOT_FOLDER}
-    # Otherwise the the absolute project_path is returned with symlinks resolved
-    file(REAL_PATH ${project_path} project_real_path BASE_DIRECTORY ${LY_ROOT_FOLDER})
+# when NO project is specified, for example, when creating a pre-built version of the engine,
+# create a generic launcher that can be shipped with the engine
+
+set(launcher_generator_LY_PROJECTS ${LY_PROJECTS})
+
+# the following generates "generic" launchers when no project is specified
+# this cannot happen in script only mode, since scripts-only mode requires a prebuilt installer
+# and the prebuilt installer always operates on a project, so will generally only happen
+# when building an installer from the o3de source code, or just compiling O3DE itself with no
+# project specified.
+if (NOT launcher_generator_LY_PROJECTS)
+    set(launcher_generator_LY_PROJECTS ":PROJECT_PATH_ONLY_FOR_GENERIC_LAUNCHER")
+    set(O3DE_PROJECTS_NAME "O3DE")
+    set(launcher_generator_BUILD_GENERIC TRUE) # used to skip the asset processing step
+    
+    # set a compile definition on the launchers themselves to let them know they are generic launchers
+    # they can use this in their code and logic to avoid doing things like loading the burned-in
+    # registry keys.
+    set(GENERIC_LAUNCHER_COMPILE_DEFINITION "O3DE_IS_GENERIC_LAUNCHER")
+endif()
 
-    ################################################################################
-    # Assets
-    ################################################################################
-    if(PAL_TRAIT_BUILD_HOST_TOOLS)
-        add_custom_target(${project_name}.Assets
-            COMMENT "Processing ${project_name} assets..."
-            COMMAND "${CMAKE_COMMAND}"
-                -DLY_LOCK_FILE=$<GENEX_EVAL:$<TARGET_FILE_DIR:AZ::AssetProcessorBatch>>/project_assets.lock
-                -P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
-                    EXEC_COMMAND $<GENEX_EVAL:$<TARGET_FILE:AZ::AssetProcessorBatch>>
-                        --zeroAnalysisMode
-                        --project-path=${project_real_path}
-                        --platforms=${LY_ASSET_DEPLOY_ASSET_TYPE}
-        )
-        set_target_properties(${project_name}.Assets
-            PROPERTIES
-                EXCLUDE_FROM_ALL TRUE
-                FOLDER ${project_name}
-        )
+
+foreach(project_name project_path IN ZIP_LISTS O3DE_PROJECTS_NAME launcher_generator_LY_PROJECTS)
+
+    if (NOT launcher_generator_BUILD_GENERIC) # generic launcher does not build assets.
+        # Computes the realpath to the project.  Only used in building assets.
+        # If the project_path is relative, it is evaluated relative to the ${LY_ROOT_FOLDER}
+        # Otherwise the the absolute project_path is returned with symlinks resolved
+        file(REAL_PATH ${project_path} project_real_path BASE_DIRECTORY ${LY_ROOT_FOLDER})
+
+        ################################################################################
+        # Assets
+        ################################################################################
+        if(PAL_TRAIT_BUILD_HOST_TOOLS)
+            add_custom_target(${project_name}.Assets
+                COMMENT "Processing ${project_name} assets..."
+                COMMAND "${CMAKE_COMMAND}"
+                    -DLY_LOCK_FILE=$<GENEX_EVAL:$<TARGET_FILE_DIR:AZ::AssetProcessorBatch>>/project_assets.lock
+                    -P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake
+                        EXEC_COMMAND $<GENEX_EVAL:$<TARGET_FILE:AZ::AssetProcessorBatch>>
+                            --zeroAnalysisMode
+                            --project-path=${project_real_path}
+                            --platforms=${LY_ASSET_DEPLOY_ASSET_TYPE}
+            )
+            set_target_properties(${project_name}.Assets
+                PROPERTIES
+                    EXCLUDE_FROM_ALL TRUE
+                    FOLDER ${project_name}
+            )
+        endif()
     endif()
 
     ################################################################################
@@ -109,16 +125,35 @@ foreach(project_name project_path IN ZIP_LISTS O3DE_PROJECTS_NAME LY_PROJECTS)
             Legacy::CrySystem
         )
 
+        # in script only mode, which can only happen when building a project
+        # that is using a prebuilt installer, add the generic gamelauncher as a run time dependency
+        # of the project launcher.  The project launcher is "fake" and will not get actually compiled,
+        # but this will cause the generic game launcher and its dependencies to get deployed into the bin folder
+        # since they are all dependencies of this fake target.
+        
+        if (O3DE_SCRIPT_ONLY)
+            set(game_runtime_dependencies ${game_runtime_dependencies} O3DE.GameLauncher)
+        endif()
+
         if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
             set(server_runtime_dependencies
                 Legacy::CrySystem
             )
+
+            if (O3DE_SCRIPT_ONLY)
+                foreach(server_launcher_type ${SERVER_LAUNCHER_TYPES})
+                    set(SERVER_RUNTIME_DEPENDENCIES_${server_launcher_type} "${SERVER_RUNTIME_DEPENDENCIES_${server_launcher_type}}" O3DE.${server_launcher_type})
+                endforeach()
+            endif()
         endif()
 
         if(PAL_TRAIT_BUILD_UNIFIED_SUPPORTED)
             set(unified_runtime_dependencies
                 Legacy::CrySystem
             )
+            if (O3DE_SCRIPT_ONLY)
+                set(unified_runtime_dependencies ${unified_runtime_dependencies} O3DE.UnifiedLauncher)
+            endif()
         endif()
 
     endif()
@@ -141,6 +176,7 @@ foreach(project_name project_path IN ZIP_LISTS O3DE_PROJECTS_NAME LY_PROJECTS)
                 # when loading .setreg file specializations
                 # This is needed so that only gems for the project game launcher are loaded
                 LY_CMAKE_TARGET="${project_name}_GameLauncher"
+                "${GENERIC_LAUNCHER_COMPILE_DEFINITION}" # this is empty if its not a generic launcher
         INCLUDE_DIRECTORIES
             ${LAUNCHER_TARGET_PROPERTY_TYPE}
                 .
@@ -201,6 +237,7 @@ foreach(project_name project_path IN ZIP_LISTS O3DE_PROJECTS_NAME LY_PROJECTS)
                         # when loading .setreg file specializations
                         # This is needed so that only gems for the project server launcher are loaded
                         LY_CMAKE_TARGET="${project_name}_${server_launcher_type}"
+                        "${GENERIC_LAUNCHER_COMPILE_DEFINITION}" # this is empty if its not a generic launcher
 
                 INCLUDE_DIRECTORIES
                     ${LAUNCHER_TARGET_PROPERTY_TYPE}
@@ -210,7 +247,7 @@ foreach(project_name project_path IN ZIP_LISTS O3DE_PROJECTS_NAME LY_PROJECTS)
                     ${LAUNCHER_TARGET_PROPERTY_TYPE}
                         ${SERVER_BUILD_DEPENDENCIES_${server_launcher_type}}
                 RUNTIME_DEPENDENCIES
-                    ${server_runtime_dependencies}
+                    ${SERVER_RUNTIME_DEPENDENCIES_${server_launcher_type}}
             )
             # Needs to be set manually after ly_add_target to prevent the default location overriding it
             set_target_properties(${project_name}.${server_launcher_type}
@@ -265,6 +302,7 @@ foreach(project_name project_path IN ZIP_LISTS O3DE_PROJECTS_NAME LY_PROJECTS)
                     # when loading .setreg file specializations
                     # This is needed so that only gems for the project unified launcher are loaded
                     LY_CMAKE_TARGET="${project_name}_UnifiedLauncher"
+                    "${GENERIC_LAUNCHER_COMPILE_DEFINITION}" # this is empty if its not a generic launcher
             INCLUDE_DIRECTORIES
                 ${LAUNCHER_TARGET_PROPERTY_TYPE}
                     .

+ 3 - 0
Registry/AssetProcessorPlatformConfig.setreg

@@ -206,6 +206,9 @@
                 "Exclude Install": {
                     "glob": "install/*"
                 },
+                "Exclude ProjectPackages": {
+                    "glob": "ProjectPackages/*"
+                },
                 // Exclude Gems inside Projects, their Assets folders will still be included
                 "Exclude Gems": {
                     "glob": "Gems/*"

+ 15 - 0
Templates/ScriptOnlyProject/Template/AssetBundling/SeedLists/Example.seed

@@ -0,0 +1,15 @@
+{
+    "Type": "JsonSerialization",
+    "Version": 1,
+    "ClassName": "AZStd::vector<SeedInfo, allocator>",
+    "ClassData": [
+        {
+            "assetId": {
+                "guid": "{B3C48432-037D-5AA5-BB1B-6D7AE19E89DF}",
+                "subId": 204440690
+            },
+            "platformFlags": 2,
+            "pathHint": "levels/start/start.spawnable"
+        }
+    ]
+}

+ 557 - 0
Templates/ScriptOnlyProject/Template/Levels/start/start.prefab

@@ -0,0 +1,557 @@
+{
+    "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,
+                "Child Entity Order": [
+                    "Entity_[1176639161715]"
+                ]
+            },
+            "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_[7247035804068349658]": {
+                "$type": "EditorPrefabComponent",
+                "Id": 7247035804068349658
+            },
+            "Component_[9307224322037797205]": {
+                "$type": "EditorLockComponent",
+                "Id": 9307224322037797205
+            },
+            "Component_[9562516168917670048]": {
+                "$type": "EditorVisibilityComponent",
+                "Id": 9562516168917670048
+            },
+            "LocalViewBookmarkComponent": {
+                "$type": "LocalViewBookmarkComponent",
+                "Id": 1290452037346922644,
+                "LocalBookmarkFileName": "start_1697236353301802388.setreg"
+            }
+        }
+    },
+    "Entities": {
+        "Entity_[1155164325235]": {
+            "Id": "Entity_[1155164325235]",
+            "Name": "Sun",
+            "Components": {
+                "Component_[13620450453324765907]": {
+                    "$type": "EditorLockComponent",
+                    "Id": 13620450453324765907
+                },
+                "Component_[2134313378593666258]": {
+                    "$type": "EditorInspectorComponent",
+                    "Id": 2134313378593666258
+                },
+                "Component_[234010807770404186]": {
+                    "$type": "EditorVisibilityComponent",
+                    "Id": 234010807770404186
+                },
+                "Component_[2970359110423865725]": {
+                    "$type": "EditorEntityIconComponent",
+                    "Id": 2970359110423865725
+                },
+                "Component_[3722854130373041803]": {
+                    "$type": "EditorOnlyEntityComponent",
+                    "Id": 3722854130373041803
+                },
+                "Component_[5992533738676323195]": {
+                    "$type": "EditorDisabledCompositionComponent",
+                    "Id": 5992533738676323195
+                },
+                "Component_[7378860763541895402]": {
+                    "$type": "AZ::Render::EditorDirectionalLightComponent",
+                    "Id": 7378860763541895402,
+                    "Controller": {
+                        "Configuration": {
+                            "Intensity": 1.0,
+                            "CameraEntityId": "",
+                            "ShadowFilterMethod": 1
+                        }
+                    }
+                },
+                "Component_[7892834440890947578]": {
+                    "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+                    "Id": 7892834440890947578,
+                    "Parent Entity": "Entity_[1176639161715]",
+                    "Transform Data": {
+                        "Translate": [
+                            0.0,
+                            0.0,
+                            13.487043380737305
+                        ],
+                        "Rotate": [
+                            -76.13099670410156,
+                            -0.847000002861023,
+                            -15.8100004196167
+                        ]
+                    }
+                },
+                "Component_[8599729549570828259]": {
+                    "$type": "EditorEntitySortComponent",
+                    "Id": 8599729549570828259
+                },
+                "Component_[952797371922080273]": {
+                    "$type": "EditorPendingCompositionComponent",
+                    "Id": 952797371922080273
+                }
+            }
+        },
+        "Entity_[1159459292531]": {
+            "Id": "Entity_[1159459292531]",
+            "Name": "Ground",
+            "Components": {
+                "Component_[12260880513256986252]": {
+                    "$type": "EditorEntityIconComponent",
+                    "Id": 12260880513256986252
+                },
+                "Component_[13711420870643673468]": {
+                    "$type": "EditorDisabledCompositionComponent",
+                    "Id": 13711420870643673468
+                },
+                "Component_[138002849734991713]": {
+                    "$type": "EditorOnlyEntityComponent",
+                    "Id": 138002849734991713
+                },
+                "Component_[16578565737331764849]": {
+                    "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+                    "Id": 16578565737331764849,
+                    "Parent Entity": "Entity_[1176639161715]"
+                },
+                "Component_[16919232076966545697]": {
+                    "$type": "EditorInspectorComponent",
+                    "Id": 16919232076966545697
+                },
+                "Component_[4228479570410194639]": {
+                    "$type": "EditorStaticRigidBodyComponent",
+                    "Id": 4228479570410194639
+                },
+                "Component_[5182430712893438093]": {
+                    "$type": "EditorMaterialComponent",
+                    "Id": 5182430712893438093
+                },
+                "Component_[5245524694917323904]": {
+                    "$type": "EditorColliderComponent",
+                    "Id": 5245524694917323904,
+                    "ColliderConfiguration": {
+                        "Position": [
+                            0.0,
+                            0.0,
+                            -0.5
+                        ],
+                        "MaterialSlots": {
+                            "Slots": [
+                                {
+                                    "Name": "Entire object"
+                                }
+                            ]
+                        }
+                    },
+                    "ShapeConfiguration": {
+                        "ShapeType": 1,
+                        "Box": {
+                            "Configuration": [
+                                512.0,
+                                512.0,
+                                1.0
+                            ]
+                        }
+                    },
+                    "DebugDrawSettings": {
+                        "LocallyEnabled": false
+                    }
+                },
+                "Component_[5675108321710651991]": {
+                    "$type": "AZ::Render::EditorMeshComponent",
+                    "Id": 5675108321710651991,
+                    "Controller": {
+                        "Configuration": {
+                            "ModelAsset": {
+                                "assetId": {
+                                    "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
+                                    "subId": 277889906
+                                },
+                                "assetHint": "objects/groudplane/groundplane_512x512m.azmodel"
+                            }
+                        }
+                    }
+                },
+                "Component_[5681893399601237518]": {
+                    "$type": "EditorEntitySortComponent",
+                    "Id": 5681893399601237518
+                },
+                "Component_[592692962543397545]": {
+                    "$type": "EditorPendingCompositionComponent",
+                    "Id": 592692962543397545
+                },
+                "Component_[7090012899106946164]": {
+                    "$type": "EditorLockComponent",
+                    "Id": 7090012899106946164
+                },
+                "Component_[9410832619875640998]": {
+                    "$type": "EditorVisibilityComponent",
+                    "Id": 9410832619875640998
+                }
+            }
+        },
+        "Entity_[1163754259827]": {
+            "Id": "Entity_[1163754259827]",
+            "Name": "Camera",
+            "Components": {
+                "Component_[11895140916889160460]": {
+                    "$type": "EditorEntityIconComponent",
+                    "Id": 11895140916889160460
+                },
+                "Component_[16880285896855930892]": {
+                    "$type": "{CA11DA46-29FF-4083-B5F6-E02C3A8C3A3D} EditorCameraComponent",
+                    "Id": 16880285896855930892,
+                    "Controller": {
+                        "Configuration": {
+                            "Field of View": 55.0
+                        }
+                    }
+                },
+                "Component_[17187464423780271193]": {
+                    "$type": "EditorLockComponent",
+                    "Id": 17187464423780271193
+                },
+                "Component_[17495696818315413311]": {
+                    "$type": "EditorEntitySortComponent",
+                    "Id": 17495696818315413311
+                },
+                "Component_[18086214374043522055]": {
+                    "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+                    "Id": 18086214374043522055,
+                    "Parent Entity": "Entity_[1176639161715]",
+                    "Transform Data": {
+                        "Translate": [
+                            -2.3000001907348633,
+                            -3.9368600845336914,
+                            1.0
+                        ],
+                        "Rotate": [
+                            -2.050307512283325,
+                            1.9552897214889526,
+                            -43.623355865478516
+                        ]
+                    }
+                },
+                "Component_[2654521436129313160]": {
+                    "$type": "EditorVisibilityComponent",
+                    "Id": 2654521436129313160
+                },
+                "Component_[5265045084611556958]": {
+                    "$type": "EditorDisabledCompositionComponent",
+                    "Id": 5265045084611556958
+                },
+                "Component_[7169798125182238623]": {
+                    "$type": "EditorPendingCompositionComponent",
+                    "Id": 7169798125182238623
+                },
+                "Component_[7255796294953281766]": {
+                    "$type": "GenericComponentWrapper",
+                    "Id": 7255796294953281766,
+                    "m_template": {
+                        "$type": "FlyCameraInputComponent"
+                    }
+                },
+                "Component_[8866210352157164042]": {
+                    "$type": "EditorInspectorComponent",
+                    "Id": 8866210352157164042
+                },
+                "Component_[9129253381063760879]": {
+                    "$type": "EditorOnlyEntityComponent",
+                    "Id": 9129253381063760879
+                }
+            }
+        },
+        "Entity_[1168049227123]": {
+            "Id": "Entity_[1168049227123]",
+            "Name": "Grid",
+            "Components": {
+                "Component_[11443347433215807130]": {
+                    "$type": "EditorEntityIconComponent",
+                    "Id": 11443347433215807130
+                },
+                "Component_[14249419413039427459]": {
+                    "$type": "EditorInspectorComponent",
+                    "Id": 14249419413039427459
+                },
+                "Component_[15448581635946161318]": {
+                    "$type": "AZ::Render::EditorGridComponent",
+                    "Id": 15448581635946161318,
+                    "Controller": {
+                        "Configuration": {
+                            "primarySpacing": 4.0,
+                            "primaryColor": [
+                                0.501960813999176,
+                                0.501960813999176,
+                                0.501960813999176
+                            ],
+                            "secondarySpacing": 0.5,
+                            "secondaryColor": [
+                                0.250980406999588,
+                                0.250980406999588,
+                                0.250980406999588
+                            ]
+                        }
+                    }
+                },
+                "Component_[1843303322527297409]": {
+                    "$type": "EditorDisabledCompositionComponent",
+                    "Id": 1843303322527297409
+                },
+                "Component_[380249072065273654]": {
+                    "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+                    "Id": 380249072065273654,
+                    "Parent Entity": "Entity_[1176639161715]"
+                },
+                "Component_[7476660583684339787]": {
+                    "$type": "EditorPendingCompositionComponent",
+                    "Id": 7476660583684339787
+                },
+                "Component_[7557626501215118375]": {
+                    "$type": "EditorEntitySortComponent",
+                    "Id": 7557626501215118375
+                },
+                "Component_[7984048488947365511]": {
+                    "$type": "EditorVisibilityComponent",
+                    "Id": 7984048488947365511
+                },
+                "Component_[8118181039276487398]": {
+                    "$type": "EditorOnlyEntityComponent",
+                    "Id": 8118181039276487398
+                },
+                "Component_[9189909764215270515]": {
+                    "$type": "EditorLockComponent",
+                    "Id": 9189909764215270515
+                }
+            }
+        },
+        "Entity_[1172344194419]": {
+            "Id": "Entity_[1172344194419]",
+            "Name": "Shader Ball",
+            "Components": {
+                "Component_[10789351944715265527]": {
+                    "$type": "EditorOnlyEntityComponent",
+                    "Id": 10789351944715265527
+                },
+                "Component_[12037033284781049225]": {
+                    "$type": "EditorEntitySortComponent",
+                    "Id": 12037033284781049225
+                },
+                "Component_[13759153306105970079]": {
+                    "$type": "EditorPendingCompositionComponent",
+                    "Id": 13759153306105970079
+                },
+                "Component_[14135560884830586279]": {
+                    "$type": "EditorInspectorComponent",
+                    "Id": 14135560884830586279
+                },
+                "Component_[16247165675903986673]": {
+                    "$type": "EditorVisibilityComponent",
+                    "Id": 16247165675903986673
+                },
+                "Component_[18082433625958885247]": {
+                    "$type": "EditorDisabledCompositionComponent",
+                    "Id": 18082433625958885247
+                },
+                "Component_[6472623349872972660]": {
+                    "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+                    "Id": 6472623349872972660,
+                    "Parent Entity": "Entity_[1176639161715]",
+                    "Transform Data": {
+                        "Rotate": [
+                            0.0,
+                            0.10000000149011612,
+                            180.0
+                        ]
+                    }
+                },
+                "Component_[6495255223970673916]": {
+                    "$type": "AZ::Render::EditorMeshComponent",
+                    "Id": 6495255223970673916,
+                    "Controller": {
+                        "Configuration": {
+                            "ModelAsset": {
+                                "assetId": {
+                                    "guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
+                                    "subId": 281415304
+                                },
+                                "assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
+                            }
+                        }
+                    }
+                },
+                "Component_[8550141614185782969]": {
+                    "$type": "EditorEntityIconComponent",
+                    "Id": 8550141614185782969
+                },
+                "Component_[9439770997198325425]": {
+                    "$type": "EditorLockComponent",
+                    "Id": 9439770997198325425
+                }
+            }
+        },
+        "Entity_[1176639161715]": {
+            "Id": "Entity_[1176639161715]",
+            "Name": "Atom Default Environment",
+            "Components": {
+                "Component_[10757302973393310045]": {
+                    "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+                    "Id": 10757302973393310045,
+                    "Parent Entity": "Entity_[1146574390643]"
+                },
+                "Component_[14505817420424255464]": {
+                    "$type": "EditorInspectorComponent",
+                    "Id": 14505817420424255464,
+                    "ComponentOrderEntryArray": [
+                        {
+                            "ComponentId": 10757302973393310045
+                        }
+                    ]
+                },
+                "Component_[14988041764659020032]": {
+                    "$type": "EditorLockComponent",
+                    "Id": 14988041764659020032
+                },
+                "Component_[15900837685796817138]": {
+                    "$type": "EditorVisibilityComponent",
+                    "Id": 15900837685796817138
+                },
+                "Component_[3298767348226484884]": {
+                    "$type": "EditorOnlyEntityComponent",
+                    "Id": 3298767348226484884
+                },
+                "Component_[4076975109609220594]": {
+                    "$type": "EditorPendingCompositionComponent",
+                    "Id": 4076975109609220594
+                },
+                "Component_[5679760548946028854]": {
+                    "$type": "EditorDisabledCompositionComponent",
+                    "Id": 5679760548946028854
+                },
+                "Component_[5855590796136709437]": {
+                    "$type": "EditorEntitySortComponent",
+                    "Id": 5855590796136709437,
+                    "Child Entity Order": [
+                        "Entity_[1155164325235]",
+                        "Entity_[1180934129011]",
+                        "Entity_[1172344194419]",
+                        "Entity_[1168049227123]",
+                        "Entity_[1163754259827]",
+                        "Entity_[1159459292531]"
+                    ]
+                },
+                "Component_[9277695270015777859]": {
+                    "$type": "EditorEntityIconComponent",
+                    "Id": 9277695270015777859
+                }
+            }
+        },
+        "Entity_[1180934129011]": {
+            "Id": "Entity_[1180934129011]",
+            "Name": "Global Sky",
+            "Components": {
+                "Component_[11231930600558681245]": {
+                    "$type": "AZ::Render::EditorHDRiSkyboxComponent",
+                    "Id": 11231930600558681245,
+                    "Controller": {
+                        "Configuration": {
+                            "CubemapAsset": {
+                                "assetId": {
+                                    "guid": "{215E47FD-D181-5832-B1AB-91673ABF6399}",
+                                    "subId": 1000
+                                },
+                                "assetHint": "lightingpresets/highcontrast/goegap_4k_skyboxcm.exr.streamingimage"
+                            }
+                        }
+                    }
+                },
+                "Component_[1428633914413949476]": {
+                    "$type": "EditorLockComponent",
+                    "Id": 1428633914413949476
+                },
+                "Component_[14936200426671614999]": {
+                    "$type": "AZ::Render::EditorImageBasedLightComponent",
+                    "Id": 14936200426671614999,
+                    "Controller": {
+                        "Configuration": {
+                            "diffuseImageAsset": {
+                                "assetId": {
+                                    "guid": "{3FD09945-D0F2-55C8-B9AF-B2FD421FE3BE}",
+                                    "subId": 3000
+                                },
+                                "assetHint": "lightingpresets/highcontrast/goegap_4k_iblglobalcm_ibldiffuse.exr.streamingimage"
+                            },
+                            "specularImageAsset": {
+                                "assetId": {
+                                    "guid": "{3FD09945-D0F2-55C8-B9AF-B2FD421FE3BE}",
+                                    "subId": 2000
+                                },
+                                "assetHint": "lightingpresets/highcontrast/goegap_4k_iblglobalcm_iblspecular.exr.streamingimage"
+                            }
+                        }
+                    }
+                },
+                "Component_[14994774102579326069]": {
+                    "$type": "EditorDisabledCompositionComponent",
+                    "Id": 14994774102579326069
+                },
+                "Component_[15417479889044493340]": {
+                    "$type": "EditorPendingCompositionComponent",
+                    "Id": 15417479889044493340
+                },
+                "Component_[15826613364991382688]": {
+                    "$type": "EditorEntitySortComponent",
+                    "Id": 15826613364991382688
+                },
+                "Component_[1665003113283562343]": {
+                    "$type": "EditorOnlyEntityComponent",
+                    "Id": 1665003113283562343
+                },
+                "Component_[3704934735944502280]": {
+                    "$type": "EditorEntityIconComponent",
+                    "Id": 3704934735944502280
+                },
+                "Component_[5698542331457326479]": {
+                    "$type": "EditorVisibilityComponent",
+                    "Id": 5698542331457326479
+                },
+                "Component_[6644513399057217122]": {
+                    "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+                    "Id": 6644513399057217122,
+                    "Parent Entity": "Entity_[1176639161715]"
+                },
+                "Component_[931091830724002070]": {
+                    "$type": "EditorInspectorComponent",
+                    "Id": 931091830724002070
+                }
+            }
+        }
+    }
+}

+ 14 - 0
Templates/ScriptOnlyProject/Template/autoexec.cfg

@@ -0,0 +1,14 @@
+; edit this file to make it load whatever level you want on startup automatically
+; You can also add additional commands in here that you want it to exec on startup.
+loadlevel start
+
+; uncomment the following line in any game packages that have all the
+; assets precompiled, so that it doesn't try to launch the Asset Processor in
+; actual shipping builds.
+
+; bg_ConnectToAssetProcessor 0
+
+; uncomment the following line to hide any debug display info from the top
+; right corner of the screen.
+
+; r_DisplayInfo 0

+ 27 - 0
Templates/ScriptOnlyProject/Template/package.bat

@@ -0,0 +1,27 @@
+REM --------------------------------------------------------------------------------------------------
+REM 
+REM Copyright (c) Contributors to the Open 3D Engine Project.
+REM For complete copyright and license terms please see the LICENSE at the root of this distribution.
+REM 
+REM SPDX-License-Identifier: Apache-2.0 OR MIT
+REM 
+REM --------------------------------------------------------------------------------------------------
+
+
+REM This script is meant to export the project into a standalone shippable project that others can run.
+REM However, the project developer is expected to modify it to add steps or change it to their needs.
+REM
+REM To get more information about the possible tweakable parameters, run 
+REM (engine folder)\scripts\o3de.bat export-project -es ExportScripts/export_source_built_project.py --script-help
+
+set O3DE_PATH=${EnginePath}
+set O3DE_PROJECT_PATH=${ProjectPath}
+set O3DE_PROJECT_SEEDLIST=%O3DE_PROJECT_PATH%\AssetBundling\SeedLists\Example.seed
+set OUTPUT_PATH=%O3DE_PROJECT_PATH%\ProjectPackages
+
+REM change this to release or debug if you want it to make a release or debug package
+REM (Only works if the installer you have actually includes release and debug binaries)
+set OUTPUT_CONFIGURATION=profile
+
+%O3DE_PATH%\scripts\o3de.bat export-project -es ExportScripts\export_source_built_project.py --project-path %O3DE_PROJECT_PATH% --no-monolithic-build --log-level INFO -assets --config %OUTPUT_CONFIGURATION% --archive-output zip --seedlist %O3DE_PROJECT_SEEDLIST% -out %OUTPUT_PATH%
+

+ 24 - 0
Templates/ScriptOnlyProject/Template/package.sh

@@ -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
+#
+#
+
+# This script is meant to export the project into a standalone shippable project that others can run.
+# However, the project developer is expected to modify it to add steps or change it to their needs.
+
+# To get more information about the possible tweakable parameters, run 
+# (engine folder)/scripts/o3de.sh export-project -es ExportScripts/export_source_built_project.py --script-help
+
+O3DE_PATH=${EnginePath}
+O3DE_PROJECT_PATH=${ProjectPath}
+O3DE_PROJECT_SEEDLIST=${O3DE_PROJECT_PATH}/AssetBundling/SeedLists/Example.seed
+OUTPUT_PATH=${O3DE_PROJECT_PATH}/ProjectPackages
+
+# change this to release or debug if you want it to make a release or debug package
+# (Only works if the installer you have actually includes release and debug binaries)
+OUTPUT_CONFIGURATION=profile
+
+${O3DE_PATH}/scripts/o3de.sh export-project -es ExportScripts/export_source_built_project.py --project-path ${O3DE_PROJECT_PATH} --no-monolithic-build  --log-level INFO -assets --config ${OUTPUT_CONFIGURATION} --archive-output gztar --seedlist ${O3DE_PROJECT_SEEDLIST} -out ${OUTPUT_PATH}

+ 28 - 0
Templates/ScriptOnlyProject/template.json

@@ -42,6 +42,10 @@
             "file": "Config/shader_global_build_options.json",
             "isTemplated": false
         },
+        {
+            "file": "Levels/start/start.prefab",
+            "isTemplated": false
+        },
         {
             "file": "Platform/Android/android_project.cmake",
             "isTemplated": false
@@ -258,6 +262,18 @@
             "file": "autoexec.cfg",
             "isTemplated": false
         },
+        {
+            "file": "package.bat",
+            "isTemplated": true
+        },
+        {
+            "file": "package.sh",
+            "isTemplated": true
+        },
+        {
+            "file": "AssetBundling/SeedLists/Example.seed",
+            "isTemplated": false
+        },
         {
             "file": "game.cfg",
             "isTemplated": false
@@ -275,12 +291,24 @@
         {
             "dir": "Assets"
         },
+        {
+            "dir": "AssetBundling"
+        },
+        {
+            "dir": "AssetBundling/SeedLists"
+        },
         {
             "dir": "cmake"
         },
         {
             "dir": "Config"
         },
+        {
+            "dir": "Levels"
+        },
+        {
+            "dir": "Levels/start"
+        },
         {
             "dir": "Platform"
         },

+ 112 - 0
cmake/3rdParty/script-only-mode/PostProcessScriptOnlyMappings.cmake

@@ -0,0 +1,112 @@
+#
+# 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 file is used during generation of the installer layout.
+# note that ARGV0 is the cmake command itself, and ARGV1 is the -P command line option, so we skip them
+# ARGV2 is the name of this script.
+# ARGV3 is the output folder name
+# ARGV4 and onwards are the names of input files, generated during the engine configure/generate
+# containing information about the 3p libraries available.
+
+#[[ there is 1 input file for each 3p library, and each input file contains a set of "set" commands in this format:
+    set(target_name ${TARGET_NAME})
+    set(copy_dependencies_source_file_path ${copy_dependencies_source_file_path})
+    set(copy_dependencies_target_rel_path ${copy_dependencies_target_rel_path})
+
+    The goal of this file is to generate one output_filename/target_name.cmake for each input file such 
+    that it contains the ability to register the given 3p library target
+    libraries as fake ones (which have the appropriate dependencies so that files get copied).
+]]#
+
+if (${CMAKE_ARGC} LESS 5)
+    message(FATAL_ERROR "This command was invoked incorrectly.\nUsage:\n"
+                             "cmake -P (SCRIPT_NAME) (OUTPUT_DIR) (INPUT FILE) (INPUT FILE) ...")
+    return()
+endif()
+
+set(output_directory ${CMAKE_ARGV3})
+
+if (NOT output_directory)
+    message(FATAL_ERROR "Expected the first argument to be an output directory")
+endif()
+
+foreach(index RANGE 4 ${CMAKE_ARGC})
+    if (CMAKE_ARGV${index})
+        list(APPEND file_list ${CMAKE_ARGV${index}})
+    endif()
+endforeach()
+
+
+set(copyright_and_preamble [[#
+# 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
+#
+#
+
+# Generated as part of the install command, this file contains calls to register 3p libraries
+# for script-only mode, to ensure that their dependent files are copied to the final location
+# during game deploy.  It should ONLY be used in script-only mode.
+]])
+
+foreach(data_file IN LISTS file_list)
+    unset(target_name)
+    unset(copy_dependencies_source_file_path)
+    unset(copy_dependencies_target_rel_path)
+    unset(trimmed_source_paths)
+    set(final_data ${copyright_and_preamble})
+
+    include(${data_file})
+
+    if (NOT target_name)
+        message(FATAL_ERROR "Error parsing data file ${data_file} - consider cleaning it out and rebuilding.")
+    endif()
+
+    foreach(abs_filepath IN LISTS copy_dependencies_source_file_path)
+        cmake_path(GET abs_filepath FILENAME filename_only)
+        list(APPEND trimmed_source_paths ${filename_only})
+    endforeach()
+
+    # sanity check
+    if (trimmed_source_paths OR copy_dependencies_target_rel_path)
+        list(LENGTH trimmed_source_paths source_list_length)
+        list(LENGTH copy_dependencies_target_rel_path relpath_list_lenth)
+        if (NOT source_list_length EQUAL relpath_list_lenth)
+            message(FATAL_ERROR "Programmer error - for target ${target_name}, lists are supposed to be same length, but\n\
+                                ${source_list_length} source and ${relpath_list_lenth} relpath\n\
+                                source:'${trimmed_source_paths}'\n\
+                                relpath: '${copy_dependencies_target_rel_path}'")
+        endif()
+    endif()
+
+    string(APPEND final_data "add_library(${target_name} INTERFACE IMPORTED GLOBAL)\n")
+
+    # binary_folder can be a genex but will always be the Default folder since monolithic
+    # cannot be combined with script-only
+    set(installer_binaries [[${LY_ROOT_FOLDER}/bin/${PAL_PLATFORM_NAME}/$<CONFIG>/Default]])
+    if (trimmed_source_paths)
+        foreach(file_name relative_path IN ZIP_LISTS trimmed_source_paths copy_dependencies_target_rel_path)
+            if (relative_path)
+                set(file_name "${installer_binaries}/${relative_path}/${file_name}")
+            else()
+                set(relative_path "")
+                set(file_name "${installer_binaries}/${file_name}")
+            endif()
+            string(APPEND final_data 
+                    "ly_add_target_files(TARGETS ${target_name}\n\
+                        FILES\n\
+                            \"${file_name}\"\n\
+                        OUTPUT_SUBDIRECTORY \"${relative_path}\")\n\n")
+        endforeach()        
+    endif()
+
+    string(REPLACE "::" "__" CLEAN_TARGET_NAME "${target_name}")  
+    file(WRITE "${output_directory}/${CLEAN_TARGET_NAME}.cmake" "${final_data}")
+
+endforeach()

+ 20 - 1
cmake/LYWrappers.cmake

@@ -573,14 +573,23 @@ function(ly_parse_third_party_dependencies ly_THIRD_PARTY_LIBRARIES)
 
     # Interface dependencies may require to find_packages. So far, we are just using packages for 3rdParty, so we will
     # search for those and automatically bring those packages. The naming convention used is 3rdParty::PackageName::OptionalInterface
+    unset(all_thirdparty_dependencies_found)
+
     foreach(dependency ${ly_THIRD_PARTY_LIBRARIES})
         string(REPLACE "::" ";" dependency_list ${dependency})
         list(GET dependency_list 0 dependency_namespace)
         if(${dependency_namespace} STREQUAL "3rdParty")
+            list(APPEND all_thirdparty_dependencies_found ${dependency})
             if (NOT TARGET ${dependency})
                 if (O3DE_SCRIPT_ONLY)
                     # we don't actually need 3p deps to try to download the package or call find_package.
-                    add_library(${dependency} IMPORTED INTERFACE GLOBAL)
+                    # instead we use pre-created part-of-the-installer 3p targets baked in from the above list
+                    # which will have been made at install time.
+                    # instead, we execute a pregenerated file that was created as part of install to 
+                    # create this target:
+                    string(REPLACE "::" "__" CLEAN_TARGET_NAME "${dependency}")  
+                    # not all 3ps actually exist as real targets, so this is an OPTIONAL include.
+                    include(${LY_ROOT_FOLDER}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/Default/${CLEAN_TARGET_NAME}.cmake OPTIONAL)
                 else()
                     list(GET dependency_list 1 dependency_package)
                     list(LENGTH dependency_list dependency_list_length)
@@ -602,6 +611,16 @@ function(ly_parse_third_party_dependencies ly_THIRD_PARTY_LIBRARIES)
     foreach(dependency IN LISTS packages_with_components)
         find_package(${dependency} REQUIRED MODULE COMPONENTS ${${dependency}_components})
     endforeach()
+    
+    foreach(dependency ${all_thirdparty_dependencies_found})
+        if (TARGET ${dependency})
+            # keep track of all the 3p dependencies we actually depended on.
+            get_property(o3de_all_3rdparty_targets GLOBAL PROPERTY O3DE_ALL_3RDPARTY_TARGETS)
+            if(NOT ${dependency} IN_LIST o3de_all_3rdparty_targets)
+                set_property(GLOBAL APPEND PROPERTY O3DE_ALL_3RDPARTY_TARGETS "${dependency}")
+            endif()
+        endif()
+    endforeach()
 endfunction()
 
 #! ly_configure_target_platform_properties: Configures any platform specific properties on target

+ 136 - 1
cmake/Platform/Common/Install_common.cmake

@@ -349,6 +349,140 @@ function(ly_setup_subdirectories)
     endforeach()
 endfunction()
 
+#! ly_setup_3p_target: Export enough data such that the script-only mode knows about the runtime dependencies
+#! for the given target.  This function returns a string which is a setup function that can be called
+#! in script only mode to create a fake target for the 3p library that just includes its copy dependencies.
+function(ly_setup_3p_target OUTVAR_GENERATED_DATA_FILENAME OUTVAR_FILE_NAME_TO_GENERATE ALIAS_TARGET_NAME)
+    ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME)
+    o3de_get_dependencies_for_target(
+            TARGET "${TARGET_NAME}"
+            COPY_DEPENDENCIES_VAR target_copy_dependencies
+            TARGET_DEPENDENCIES_VAR target_target_dependencies
+        )
+
+    # note that we want to actually create and register the aliased target name
+    # but get the data from the de-aliased target.  So except for the call above
+    # we use the aliased target name.
+    string(REPLACE "::" "__" CLEAN_TARGET_NAME "${ALIAS_TARGET_NAME}")  
+
+    unset(copy_dependencies_target_rel_path)
+    unset(copy_dependencies_source_file_path)
+    foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
+        unset(copy_dependencies_${conf})
+    endforeach()
+
+    foreach(dependency_for_target IN LISTS target_target_dependencies)
+        if (NOT TARGET ${dependency_for_target})
+            # Sometimes, things set actual shared libraries as a target dependency instead of a copy dependency.
+            list(APPEND target_copy_dependencies "${dependency_for_target}\n")
+        endif()
+    endforeach()     
+    
+    # note that the copy dependencies are actually in pairs newline delimited, so
+    # file_to_copy_a\nwhere_to_copy_a;file_to_copy_b\nwhere_to_copy_b;...
+    foreach(copy_dependency IN LISTS target_copy_dependencies)
+        string(REPLACE "\n" ";" copy_dep_pair "${copy_dependency}")
+        list(POP_FRONT copy_dep_pair source_filepath destination_relpath)
+        list(APPEND copy_dependencies_source_file_path "${source_filepath}")
+        # a quirk of list append is that if you give it an empty element, it does nothing.
+        # use dummy element (0) to indicate its an empty path
+        if (NOT destination_relpath)
+            set(destination_relpath "0")
+        endif()
+
+        list(APPEND copy_dependencies_target_rel_path "${destination_relpath}")
+    endforeach()
+
+    # sanity check
+    if (copy_dependencies_source_file_path OR copy_dependencies_target_rel_path)
+        list(LENGTH copy_dependencies_source_file_path source_list_length)
+        list(LENGTH copy_dependencies_target_rel_path  relpath_list_lenth)
+        if (NOT source_list_length EQUAL relpath_list_lenth)
+            message(FATAL_ERROR "Programmer error - for target ${ALIAS_TARGET_NAME}, lists are supposed to be same length, but\n\
+                                ${source_list_length} source and ${relpath_list_lenth} relpath\n\
+                                source:'${copy_dependencies_source_file_path}'\n\
+                                relpath: '${copy_dependencies_target_rel_path}'")
+        endif()
+    endif()
+
+    unset(${OUTVAR_GENERATED_DATA_FILENAME} PARENT_SCOPE)
+
+    # the absolute source paths of files to copy can have generator expressions that are per-config.
+    # use file(GENERATE ...) to evaluate the genexes, by writing it as a build file
+    # since GENERATE only happens during generate step, this is as far as we can go during
+    # configure.  It will be up to a build step to read these generated files back and
+    # do a final transform that removes things like absolute paths.
+    # note that we generate a file for every 3p target, as they must exist.
+    set(generate_content "set(target_name ${ALIAS_TARGET_NAME})\n")
+    if (copy_dependencies_source_file_path)
+        string(APPEND generate_content "set(copy_dependencies_source_file_path \"${copy_dependencies_source_file_path}\")\n")
+        string(APPEND generate_content "set(copy_dependencies_target_rel_path \"${copy_dependencies_target_rel_path}\")\n")
+    endif()
+
+    file(GENERATE OUTPUT  "${CMAKE_BINARY_DIR}/install/$<CONFIG>/${PAL_PLATFORM_NAME}/${CLEAN_TARGET_NAME}.cmake" 
+                  CONTENT "${generate_content}")
+    set(${OUTVAR_GENERATED_DATA_FILENAME} "${CMAKE_BINARY_DIR}/install/$<CONFIG>/${PAL_PLATFORM_NAME}/${CLEAN_TARGET_NAME}.cmake" PARENT_SCOPE)
+    set(${OUTVAR_FILE_NAME_TO_GENERATE} ${CLEAN_TARGET_NAME} PARENT_SCOPE)
+
+endfunction()
+
+# In "Script only mode", the 3p libraries are not downloaded at all.
+# But some of them (not all) have extraneous .so or .dll files that need to be deployed
+# into the final runtime package if you intend to ship a script-only runtime.
+# This function exports a file that is used only in script-only mode to supply that list
+# of extra DLLs to copy along with the game.
+function(ly_setup_3p_dependencies)
+
+    # 3p dependency generation is only relevant to installer builds, which is expected to happen only if no project is being built
+    # prevent this code from running in non-instlaler-builds, otherwise it will try to hang these commands off a non-existant generic
+    # game launcher target (which itself is also only relevant to installer builds for script-only mode.)
+    if (LY_PROJECTS)
+        return()
+    endif()
+
+    unset(list_of_files_to_process)
+    unset(expected_output_files)
+    set(final_3p_output_dir "${CMAKE_BINARY_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}")
+    get_property(o3de_all_3rdparty_targets GLOBAL PROPERTY O3DE_ALL_3RDPARTY_TARGETS)
+
+    # call the ly_setup_3p_target for each 3p target.  It will create a GENERATE step
+    # that will output a file, and also return the file name of the generated file.
+    foreach(target_3p IN LISTS o3de_all_3rdparty_targets)
+        ly_setup_3p_target(file_to_process output_filename ${target_3p})
+        if (file_to_process)
+            list(APPEND list_of_files_to_process ${file_to_process})
+            list(APPEND expected_output_files ${final_3p_output_dir}/${output_filename}.cmake)
+        endif()
+    endforeach()
+    
+    # note that generate only occurs during the generate step.  The above file will not be available until the build step
+    # so a finalization build step needs to run a script to finalize it.
+    if (list_of_files_to_process)
+        add_custom_command(
+            COMMAND ${CMAKE_COMMAND} -P 
+                "${LY_ROOT_FOLDER}/cmake/3rdParty/script-only-mode/PostProcessScriptOnlyMappings.cmake" # Script to run
+                "${final_3p_output_dir}" # the output file to make
+                ${list_of_files_to_process}
+            OUTPUT ${expected_output_files}
+            COMMENT "Updating script-only mode 3rd Party library mappings..."
+            DEPENDS ${list_of_files_to_process} 
+                    "${LY_ROOT_FOLDER}/cmake/3rdParty/script-only-mode/PostProcessScriptOnlyMappings.cmake"
+            VERBATIM
+        )
+
+        # make a custom target that depends on the above output file.
+        add_custom_target(GenerateScriptOnlyMappings DEPENDS ${expected_output_files})
+
+        # make it so that at least one real target that actually gets built depends on the above target.
+        # or else cmake won't evaluate it since nothing hangs off it.
+        add_dependencies(O3DE.GameLauncher GenerateScriptOnlyMappings)
+
+        ly_install(FILES ${expected_output_files}
+            DESTINATION "cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}"
+            COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT})
+    endif()
+endfunction()
+
 
 #! ly_setup_subdirectory: setup all targets in the subdirectory
 function(ly_setup_subdirectory absolute_target_source_dir)
@@ -651,7 +785,7 @@ endfunction()
 #! ly_setup_runtime_dependencies: install runtime dependencies
 function(ly_setup_runtime_dependencies)
 
-    # Common functions used by the bellow code
+    # Common functions used by the below code
     if(COMMAND ly_setup_runtime_dependencies_copy_function_override)
         ly_setup_runtime_dependencies_copy_function_override()
     else()
@@ -975,6 +1109,7 @@ function(ly_setup_o3de_install)
     ly_setup_cmake_install()
     ly_setup_runtime_dependencies()
     ly_setup_assets()
+    ly_setup_3p_dependencies()
 
     # Misc
     ly_install(FILES

+ 17 - 12
cmake/Platform/Linux/LYWrappers_linux.cmake

@@ -9,19 +9,24 @@
 set(LY_STRIP_DEBUG_SYMBOLS FALSE CACHE BOOL "Flag to strip debug symbols from the (non-debug) output binaries")
 set(LY_DEBUG_SYMBOLS_FILE_EXTENSION "dbg" CACHE STRING "Extension for generated debug symbol files")
 
-# Check if 'strip' is available so that debug symbols can be stripped from output libraries and executables.
-find_program(GNU_STRIP_TOOL strip)
-if (NOT GNU_STRIP_TOOL)
-    message(WARNING "Unable to locate 'strip' tool needed to strip debug symbols from the output target(s). "
-                    "Debug symbols will not be removed from output libraries and executables.")
-endif()
+# in script only mode, we have no compiler or compiler tools and are always in a situation
+# where a project is being built versus a pre-built version of the engine.  This means that
+# stripping and copying should not be attempted.
+if (NOT O3DE_SCRIPT_ONLY)
+    # Check if 'strip' is available so that debug symbols can be stripped from output libraries and executables.
+    find_program(GNU_STRIP_TOOL strip)
+    if (NOT GNU_STRIP_TOOL)
+        message(WARNING "Unable to locate 'strip' tool needed to strip debug symbols from the output target(s). "
+                        "Debug symbols will not be removed from output libraries and executables.")
+    endif()
 
-# Check if 'objcopy' is available so that debug symbols can be extracted from output libraries and executables.
-find_program(GNU_OBJCOPY objcopy)
-if (NOT GNU_OBJCOPY)
-    message(WARNING "Unable to locate 'objcopy' tool needed to extract debug symbols from the output target(s). "
-                    "Debug symbols will not be removed from output libraries and executables. Make sure that "
-                    "'objcopy' is installed.")
+    # Check if 'objcopy' is available so that debug symbols can be extracted from output libraries and executables.
+    find_program(GNU_OBJCOPY objcopy)
+    if (NOT GNU_OBJCOPY)
+        message(WARNING "Unable to locate 'objcopy' tool needed to extract debug symbols from the output target(s). "
+                        "Debug symbols will not be removed from output libraries and executables. Make sure that "
+                        "'objcopy' is installed.")
+    endif()
 endif()
 
 

+ 8 - 3
scripts/o3de/ExportScripts/export_source_built_project.py

@@ -36,6 +36,7 @@ def export_standalone_project(ctx: exp.O3DEScriptExportContext,
                               should_build_server_launcher: bool = True,
                               should_build_unified_launcher: bool = True,
                               should_build_headless_server_launcher: bool = True,
+                              monolithic_build: bool = True,
                               allow_registry_overrides: bool = False,
                               tools_build_path: pathlib.Path | None =None,
                               launcher_build_path: pathlib.Path | None =None,
@@ -67,6 +68,7 @@ def export_standalone_project(ctx: exp.O3DEScriptExportContext,
     :param should_build_server_launcher:            Option to build the server launcher package
     :param should_build_unified_launcher:           Option to build the unified launcher package
     :param should_build_headless_server_launcher:   Option to build the headless server launcher package
+    :param monolithic_build:                        Option to build the game binaries monolithically
     :param allow_registry_overrides:                Option to allow registry overrides in the build process
     :param tools_build_path:                        Optional build path to build the tools. (Will default to build/tools if not supplied)
     :param launcher_build_path:                     Optional build path to build the game launcher(s). (Will default to build/launcher if not supplied)
@@ -131,6 +133,7 @@ def export_standalone_project(ctx: exp.O3DEScriptExportContext,
                                build_config=build_config,
                                game_build_path=launcher_build_path,
                                engine_centric=engine_centric,
+                               monolithic_build=monolithic_build,
                                launcher_types=launcher_type,
                                allow_registry_overrides=allow_registry_overrides,
                                tool_config=tool_config,
@@ -237,7 +240,7 @@ if "o3de_context" in globals():
         parser.add_argument('-a', '--archive-output',  type=str,
                             help="Option to create a compressed archive the output. "
                                  "Specify the format of archive to create from the output directory. If 'none' specified, no archiving will occur.",
-                            choices=["none", "zip", "gzip", "bz2", "xz"], default="none")
+                            choices=exp.ALL_AVAILABLE_ARCHIVE_FORMATS, default="none")
         parser.add_argument('-assets', '--should-build-assets', default=False, action='store_true',
                             help='Toggles building all assets for the bundle.')
         parser.add_argument('-foa', '--fail-on-asset-errors', default=False, action='store_true',
@@ -264,12 +267,13 @@ if "o3de_context" in globals():
                             help="When configuring cmake builds, this determines if the script allows for overriding registry settings from external sources.")
         parser.add_argument('-abp', '--asset-bundling-path', type=pathlib.Path, default=None,
                             help="Designates where the artifacts from the asset bundling process will be written to before creation of the package. If not specified, default is <o3de_project_path>/build/asset_bundling.")
-        parser.add_argument('-maxsize', '--max-bundle-size', type=int, default=2048, help='Specify the maximum size of a given asset bundle.')
+        parser.add_argument('-maxsize', '--max-bundle-size', type=int, default=2048, help='Specify the maximum size of a given asset bundle (in MiB).')
         parser.add_argument('-nogame', '--no-game-launcher', action='store_true', help='This flag skips building the Game Launcher on a platform if not needed.')
         parser.add_argument('-noserver', '--no-server-launcher', action='store_true', help='This flag skips building the Server Launcher on a platform if not needed.')
         parser.add_argument('-noheadless', '--no-headless-server-launcher', action='store_true', help='This flag skips building the Headless Server Launcher on a platform if not needed.')
         parser.add_argument('-nounified', '--no-unified-launcher', action='store_true', help='This flag skips building the Unified Launcher on a platform if not needed.')
-        parser.add_argument('-pl', '--platform', type=str, default=exp.get_default_asset_platform(), choices=['pc', 'linux', 'mac'])
+        parser.add_argument('-nomonolithic', '--no-monolithic-build', action='store_true', help='Build the project binaries as shared libraries (as opposed to default monolithic build).')
+        parser.add_argument('-pl', '--platform', type=str, default=exp.get_default_asset_platform(), choices=['pc', 'linux', 'mac'], help="The asset platform to package (from the Cache folder)")
         parser.add_argument('-ec', '--engine-centric', action='store_true', default=False, help='Option use the engine-centric work flow to export the project.')
         parser.add_argument('-q', '--quiet', action='store_true', help='Suppresses logging information unless an error occurs.')
         if o3de_context is None:
@@ -307,6 +311,7 @@ if "o3de_context" in globals():
                                   should_build_server_launcher=not args.no_server_launcher,
                                   should_build_unified_launcher=not args.no_unified_launcher,
                                   should_build_headless_server_launcher=not args.no_headless_server_launcher,
+                                  monolithic_build=not args.no_monolithic_build,
                                   engine_centric=args.engine_centric,
                                   allow_registry_overrides=args.allow_registry_overrides,
                                   tools_build_path=args.tools_build_path,

+ 6 - 0
scripts/o3de/o3de/engine_template.py

@@ -1726,6 +1726,12 @@ def create_project(project_path: pathlib.Path,
         logger.error(f'Project name cannot be a restricted name. {project_name}')
         return 1
 
+    # the generic launcher (and the engine, often) are referred to as o3de, so prevent the user from 
+    # accidentally creating a confusing error situation.
+    if project_name.lower() == 'o3de':
+        logger.error(f"Project name cannot be 'o3de' as this is reserved for the generic launcher.")
+        return 1
+
     # project restricted name
     if project_restricted_name and not project_restricted_path:
         gem_restricted_path = manifest.get_registered(restricted_name=project_restricted_name)

+ 12 - 4
scripts/o3de/o3de/export_project.py

@@ -25,7 +25,10 @@ from enum import IntEnum
 LOCAL_ENGINE_PATH  = pathlib.Path(__file__).parent.parent.parent.parent
 
 # Account for some windows-specific attributes
-CURRENT_PLATFORM = platform.system().lower()
+CURRENT_PLATFORM_NAME_WITH_CASE = platform.system()  # used to find the Installer binaries folder.
+CURRENT_PLATFORM = CURRENT_PLATFORM_NAME_WITH_CASE.lower()
+
+ALL_AVAILABLE_ARCHIVE_FORMATS = ["none"] + [name for name, description in shutil.get_archive_formats()]
 
 if CURRENT_PLATFORM == 'windows':
     EXECUTABLE_EXTENSION = '.exe'
@@ -541,6 +544,7 @@ def build_game_targets(ctx: O3DEScriptExportContext,
                        build_config: str,
                        game_build_path: pathlib.Path,
                        engine_centric: bool,
+                       monolithic_build: bool,
                        launcher_types: int,
                        allow_registry_overrides: bool,
                        tool_config: str = PREREQUISITE_TOOL_BUILD_CONFIG,
@@ -552,6 +556,7 @@ def build_game_targets(ctx: O3DEScriptExportContext,
     @param build_config:                The build config to build (profile or release)
     @param game_build_path:             The cmake build folder target
     @engine_centric:                    Option to generate/build an engine-centric workflow
+    @monolithic_build:                  Option to build as one executable (smaller) or to use individual dll/shared libraries instead (larger)
     @additional_cmake_configure_options:List of additional configure arguments to pass to cmake during the cmake project generation process
     @param launcher_types:              The launcher type options (bit mask from the LauncherType enum) to specify which launcher types to build
     @param allow_registry_overrides:    Custom Flag argument for 'DALLOW_SETTINGS_REGISTRY_DEVELOPMENT_OVERRIDES' to pass down to the project generation
@@ -589,10 +594,13 @@ def build_game_targets(ctx: O3DEScriptExportContext,
     if ctx.cmake_additional_configure_args:
         cmake_configure_command.extend(ctx.cmake_additional_configure_args)
 
-    cmake_configure_command.extend(["-DLY_MONOLITHIC_GAME=1",
-                                    f"-DALLOW_SETTINGS_REGISTRY_DEVELOPMENT_OVERRIDES={'0' if not allow_registry_overrides else '1'}"])
+    cmake_configure_command.extend([
+            f"-DLY_MONOLITHIC_GAME={'0' if not monolithic_build else '1'}",
+            f"-DALLOW_SETTINGS_REGISTRY_DEVELOPMENT_OVERRIDES={'0' if not allow_registry_overrides else '1'}"
+        ])
+
     if logger:
-        logger.info(f"Generating (monolithic) project the build folder for project {ctx.project_name}")
+        logger.info(f"Generating {'monolithic' if monolithic_build else 'non-monolithic'} build folder for project {ctx.project_name}")
     ret = process_command(cmake_configure_command)
     if ret != 0:
         raise ExportProjectError(f"Error generating projects for project {ctx.project_name}.")

+ 1 - 0
scripts/o3de/tests/test_export_project.py

@@ -316,6 +316,7 @@ def test_build_game_targets(tmp_path, build_config, build_game_launcher, build_s
                            build_config=build_config,
                            game_build_path=test_game_build_path,
                            engine_centric=engine_centric,
+                           monolithic_build=True,
                            launcher_types=launcher_types,
                            allow_registry_overrides=allow_registry_overrides)