Skip to content

Commit

Permalink
Merge pull request #391 from aws-lumberyard-dev/MPSGameLiftPackageExp…
Browse files Browse the repository at this point in the history
…orter

Multiplayer Sample GameLift Exporter Script
  • Loading branch information
AMZN-Gene authored May 3, 2023
2 parents 6bd7e81 + 27edb86 commit 12d1f62
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 44 deletions.
66 changes: 22 additions & 44 deletions MPSGameLift/Documentation/GameLift.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,58 +12,32 @@ This README covers optional setup, testing and running on [Amazon GameLift](http
C:\> aws --version
aws-cli/2.10.0 Python/3.11.2 Windows/10 exe/AMD64 prompt/off
```
1. Enable the "AWSGameLift" and "MPSGameLift" gems

Option 1: Commandline
```sh
<path-to-o3de-engine>\scripts\o3de.bat enable-gem -pp <path-to-multiplayer-sample> -gn MPSGameLift
```
Option 2: Project Manager
1. Open Project Manager
2. Select the "Configure Gems" options for Multiplayer Sample
3. Enable "AWSGameLift" and "MPSGameLift" gems

![Enable GameLift Gems](Media/enable_gamelift_gems.jpg)
4. Click "Save"


---
**NOTE**

Due to [bug-15829](https://github.com/o3de/o3de/issues/15829) please also add "AWSGameLift" to project.json's _gem_names_ list.
---
1. Build the server, game launchers, and asset bundler for MultiplayerSample
`cmake --build build\windows --target Editor MultiplayerSample.GameLauncher MultiplayerSample.ServerLauncher AssetBundler --config profile -- /m `
1. Build all the assets
`cmake --build build\windows --target MultiplayerSample.Assets --config profile -- /m`
1. Work in progress (WiP) step: Add your AWS region to Config/default_aws_resource_mappings.json (example: "Region": "us-west-2")

a. Currently needed otherwise when the client initializes GameLift there will be an error about not having a region.

b. This step will be removed once we properly parse the game-session data which contains the fleet-id, region-id, etc

## Build Server for Windows
1. Build Monolithic Server
1. Use Export Project to Compile Code and Build Assets

a. `cmake -B build\windows_mono -S . -G "Visual Studio 16" -DLY_MONOLITHIC_GAME=1 -DALLOW_SETTINGS_REGISTRY_DEVELOPMENT_OVERRIDES=0`
```sh
<path-to-o3de-engine>\scripts\o3de.bat export-project -es <path-to-multiplayer-sample>\MPSGameLift\Scripts\export_gamelift_server_package.py --code --assets -ll INFO
```
---
**Important**

b. `cmake --build build\windows_mono --target MultiplayerSample.GameLauncher MultiplayerSample.ServerLauncher --config profile -- /m /nologo`
1. Bundle Content
The export_gamelift_server_package script only works for projects built using engine source, and won't work with engine as an sdk.
a. Open .\build\windows\bin\profile\AssetBundler.exe
---
---
**Important**
b. Follow steps for "Create a bundle for game assets" and "Create a bundle for engine assets" and "Add bundles to the release game layout" here: https://www.o3de.org/docs/user-guide/packaging/asset-bundler/bundle-assets-for-release/
The export_gamelift_server_package script only works for projects built using engine source, and won't work with engine as an sdk.

The "default seed lists" choice should choose all but 4 seed lists to make the engine_pc.pak
The other 4 seed lists should all get selected to make the game_pc.pak
---
It's important to make sure that the bootstrap.game.profile.setreg file has been added to one of the seed files. (also add debug if you want to support debug builds)
1. Create the Launcher Zip file
Use the following .bat file or equivalent copy steps to create a directory with the launchers in it:
Run from MultiplayerSample project root directory...
Expand All @@ -90,14 +64,14 @@ It's important to make sure that the bootstrap.game.profile.setreg file has been
1. Test the profile pak server and game locally
Run the server in headless mode using `rhi=null` and `NullRenderer` parameters; the server appears as a white screen in headless mode.
`C:\GameLiftPackageWindows\MultiplayerSample.ServerLauncher.exe --rhi=null -NullRenderer -bg_ConnectToAssetProcessor=0 -sys_PakPriority=2 -sv_terminateOnPlayerExit=true --console-command-file=launch_server.cfg`
`C:\GameLiftPackageWindows\MultiplayerSample.ServerLauncher.exe --rhi=null -NullRenderer -bg_ConnectToAssetProcessor=0 -sys_PakPriority=2 --console-command-file=launch_server.cfg`
`C:\GameLiftPackageWindows\MultiplayerSample.GameLauncher.exe -bg_ConnectToAssetProcessor=0 -sys_PakPriority=2 --connect`
`<path-to-multiplayer-sample>\build\windows\bin\profile\MultiplayerSample.GameLauncher.exe -bg_ConnectToAssetProcessor=0 --connect`
---
**NOTE**
Note: launch_server.cfg is required because there's a bug with multiplayer when calling --loadlevel in the command-line. See https://github.com/o3de/o3de/issues/15773.
Launch_server.cfg is required because there's a bug with multiplayer when calling --loadlevel in the command-line. See https://github.com/o3de/o3de/issues/15773.

---

Expand Down Expand Up @@ -150,9 +124,13 @@ Launch the game client with:
```sh
aws gamelift create-player-session --region us-west-2 --game-session-id <GameSessionId> --player-id Player1
```
Note: PlayerId passed into create-player-session shouldn't be the player id passed into these JSON block; keep these unique.
---
**NOTE**
PlayerId passed into create-player-session shouldn't be the player id passed into these JSON block; keep these unique.
Record PlayerSessionId and use this in the game immediately because it expires after 60 seconds. Example: psess-50311090-9283-4fb0-ad1a-94468e60fa16
---
Paste in the game session and player session and click Connect.
```json
{ "GameSessionId": "<GameSessionId>", "PlayerId": "player_id", "PlayerSessionId": "<PlayerSessionId>" }
Expand Down
153 changes: 153 additions & 0 deletions MPSGameLift/Scripts/export_gamelift_server_package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#
# 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
#
#
"""
Enables the project for AWS Gamelift and creates a Windows server package which can be uploaded to a GameLift.
To use this script pass it into o3de.bat's export-project command:
<path-to-o3de-engine>\scripts\o3de.bat export-project -es <path-to-multiplayer-sample>\MPSGameLift\Scripts\export_gamelift_server_package.py -ll INFO
"""

import os
import argparse

import o3de.export_project as exp
import o3de.enable_gem as enable_gem

from o3de.export_project import process_command
from o3de import manifest

project_json_data = manifest.get_project_json_data(project_path=o3de_context.project_path)
project_name = project_json_data.get('project_name')

o3de_logger.info(f"Exporting AWS GameLift Server Package for {project_name}")

# Parse arguments to either build code, assets, or both
parser = argparse.ArgumentParser(
prog='GameLift Server Package',
description='Helps setup the project for AWS Gamelift and creates a Windows server package which can be uploaded to a GameLift.')

parser.add_argument('--code', action='store_true', help='Build code')
parser.add_argument('--assets', action='store_true', help='Build assets')
parser.add_argument('-g', '--generator', choices=['Visual Studio 16', 'Visual Studio 17'], help='Which compiler do you want to use?')

args = parser.parse_args(o3de_context.args)

# Help user choose to build code, assets, or both if they didn't specify via command-line
while not args.code and not args.assets:
user_input = input('No build command specified. Do you want to build code, assets, or both? (c/a/b). Quit(q): ')
if user_input.lower() == 'c':
args.code = True
elif user_input.lower() == 'a':
args.assets = True
elif user_input.lower() == 'b':
args.code = True
args.assets = True
elif user_input.lower() == 'q':
quit()

# Help user choose their compiler if they didn't specify via command-line
while not args.generator:
user_input = input('Select generator:\n 1. Visual Studio 16\n 2. Visual Studio 17.\n Quit(q)\n')
if user_input == '1':
args.generator = "Visual Studio 16"
if user_input == '2':
args.generator = "Visual Studio 17"
elif user_input.lower() == 'q':
quit()

build_folder = os.path.join(o3de_context.project_path, "build", "windows")

# Build code
if (args.code):
# Enable GameLift gems
o3de_logger.info(f"Enabling AWSGameLift and MPSGameLift gem")
if (enable_gem.enable_gem_in_project(gem_name="AWSGameLift", project_path=o3de_context.project_path) != 0):
quit()

if (enable_gem.enable_gem_in_project(gem_name="MPSGameLift", project_path=o3de_context.project_path) != 0):
quit()

# Build server launcher
os.makedirs(build_folder, exist_ok=True)
o3de_logger.info(f"Building {project_name}.ServerLauncher")

if (process_command(["cmake", "-B", build_folder, "-S", o3de_context.project_path, "-G", args.generator])):
quit()

if (process_command(["cmake", "--build", build_folder, "--target", f"{project_name}.ServerLauncher", "AssetProcessor", "AssetBundler", "AssetBundlerBatch", "--config", "profile", "--", "/m"]) != 0):
quit()

# Build monolithic server launcher build
monolithic_build_folder = os.path.join(o3de_context.project_path, "build", "windows_mono")
os.makedirs(monolithic_build_folder, exist_ok=True)
if (process_command(["cmake", "-B", monolithic_build_folder, "-S", o3de_context.project_path, "-G", args.generator, "-DLY_MONOLITHIC_GAME=1", "-DALLOW_SETTINGS_REGISTRY_DEVELOPMENT_OVERRIDES=0"])):
quit()

if (process_command(["cmake", "--build", monolithic_build_folder, "--target", f"{project_name}.ServerLauncher", "--config", "profile", "--", "/m"])):
quit()

# Build Assets
if (args.assets):
# Process assets
if (process_command(["cmake", "--build", build_folder, "--target", f"{project_name}.Assets", "--config", "profile", "--", "/m"]) != 0):
quit()

if (process_command(["cmake", "--build", build_folder, "--target", "AssetBundler", "AssetBundlerBatch", "--config", "profile", "--", "/m"]) != 0):
quit()

# Create a game asset list by using the game seed list
platform = "pc"
asset_bundler_batch = os.path.join(build_folder, "bin", "profile", "AssetBundlerBatch.exe")
asset_list_directory = os.path.join(o3de_context.project_path, "AssetBundling", "AssetLists" )
seed_list_directory = os.path.join(o3de_context.project_path, "AssetBundling", "SeedLists" )
game_asset_list_path = os.path.join(asset_list_directory, f"game_{platform}.assetlist")
engine_asset_list_path = os.path.join(asset_list_directory, f"engine_{platform}.assetlist")

generate_asset_list_command = f"{asset_bundler_batch} assetLists --assetListFile {game_asset_list_path} --platform {platform} --allowOverwrites"

# Add all the .seed files found inside <project>/AssetBundling/SeedLists
seed_file_extension = ".seed"

seed_files = [os.path.join(seed_list_directory, f) for f in os.listdir(seed_list_directory) if f.endswith(seed_file_extension)]

if not seed_files:
o3de_logger.error(f"Building assets failed! Could not find any game seed files inside {seed_list_directory}")
quit()

for file in seed_files:
generate_asset_list_command += str(f" --seedListFile ")
generate_asset_list_command += str(os.path.join(seed_list_directory, file))

if (process_command(generate_asset_list_command.split()) != 0):
quit()


if (process_command([asset_bundler_batch, "assetLists", "--assetListFile", game_asset_list_path, "--platform", platform, "--allowOverwrites",
"--seedListFile", os.path.join(seed_list_directory, "BasePopcornFxSeedList.seed"),
"--seedListFile", os.path.join(seed_list_directory, "GameSeedList.seed"),
"--seedListFile", os.path.join(seed_list_directory, "ProfileOnlySeedList.seed"),
"--seedListFile", os.path.join(seed_list_directory, "VFXSeedList.seed")]) != 0):
quit()

# Create a engine asset list by using the engine seed list
if (process_command([asset_bundler_batch, "assetLists", "--assetListFile", engine_asset_list_path, "--platform", platform, "--allowOverwrites",
"--addDefaultSeedListFiles"]) != 0):
quit()

# Bundle game asset using game asset list
bundles_directory = os.path.join(o3de_context.project_path, "AssetBundling", "Bundles" )
if (process_command([asset_bundler_batch, "bundles", "--maxSize", "2048", "--platform", platform, "--allowOverwrites",
"--outputBundlePath", os.path.join(bundles_directory, "game.pak"),
"--assetListFile", game_asset_list_path]) != 0):
quit()

# Bundle engine asset using engine asset list
if (process_command([asset_bundler_batch, "bundles", "--maxSize", "2048", "--platform", platform, "--allowOverwrites",
"--outputBundlePath", os.path.join(bundles_directory, "engine.pak"),
"--assetListFile", engine_asset_list_path]) != 0):
quit()

0 comments on commit 12d1f62

Please sign in to comment.