├── doc ├── ARM-templates.md ├── images │ ├── new-functions.png │ ├── base-architecture.png │ ├── template-outputs.png │ ├── advanced-tools-kudu.png │ ├── kudu-scenario-folders.png │ └── debug-console-powershell.png ├── deploy-scenario.md └── deploy-base-architecture.md ├── src ├── cloud │ └── functions │ │ ├── generic │ │ └── quote-of-the-day │ │ │ ├── quote │ │ │ ├── sample.dat │ │ │ ├── project.json │ │ │ ├── function.json │ │ │ └── run.csx │ │ │ ├── host.json │ │ │ ├── functiondeploy.txt │ │ │ ├── .gitignore │ │ │ └── README.md │ │ ├── leaderboards │ │ ├── top-n │ │ │ ├── leaderboard │ │ │ │ ├── sample.dat │ │ │ │ ├── project.json │ │ │ │ ├── function.json │ │ │ │ └── run.csx │ │ │ ├── host.json │ │ │ ├── score │ │ │ │ ├── sample.dat │ │ │ │ ├── project.json │ │ │ │ ├── function.json │ │ │ │ └── run.csx │ │ │ ├── functiondeploy.txt │ │ │ ├── .gitignore │ │ │ └── README.md │ │ └── around-me │ │ │ ├── host.json │ │ │ ├── leaderboard │ │ │ ├── sample.dat │ │ │ ├── project.json │ │ │ ├── function.json │ │ │ └── run.csx │ │ │ ├── score │ │ │ ├── sample.dat │ │ │ ├── project.json │ │ │ └── function.json │ │ │ ├── functiondeploy.txt │ │ │ ├── .gitignore │ │ │ └── README.md │ │ ├── package.ps1 │ │ ├── deploy.ps1 │ │ └── azuredeploy.json └── Client │ └── Unity │ ├── ProjectSettings │ ├── ProjectVersion.txt │ ├── ClusterInputManager.asset │ ├── NetworkManager.asset │ ├── TimeManager.asset │ ├── EditorBuildSettings.asset │ ├── AudioManager.asset │ ├── EditorSettings.asset │ ├── TagManager.asset │ ├── DynamicsManager.asset │ ├── UnityConnectSettings.asset │ ├── Physics2DSettings.asset │ ├── NavMeshAreas.asset │ ├── GraphicsSettings.asset │ ├── QualitySettings.asset │ └── InputManager.asset │ ├── Assets │ ├── Sprites │ │ ├── Facebook.png │ │ ├── Twitter.png │ │ ├── GooglePlus.png │ │ ├── MicrosoftAccount.png │ │ ├── Facebook.png.meta │ │ ├── GooglePlus.png.meta │ │ ├── Twitter.png.meta │ │ └── MicrosoftAccount.png.meta │ ├── Nether.meta │ ├── Scenes.meta │ ├── Scenes │ │ ├── Message Demo │ │ │ ├── MessageDemo.unity.meta │ │ │ ├── MessageDemoScript.cs.meta │ │ │ └── MessageDemoScript.cs │ │ ├── Leaderboard Demo │ │ │ ├── LeaderboardDemo.unity.meta │ │ │ ├── LeaderboardDemoScript.cs.meta │ │ │ └── LeaderboardDemoScript.cs │ │ ├── Message Demo.meta │ │ └── Leaderboard Demo.meta │ ├── Sprites.meta │ └── Nether │ │ ├── Dependencies │ │ ├── TSTableView │ │ │ ├── LICENSE.meta │ │ │ ├── README.md.meta │ │ │ ├── TableView.cs.meta │ │ │ ├── TableViewCell.cs.meta │ │ │ ├── ITableViewDataSource.cs.meta │ │ │ ├── TableViewCell.cs │ │ │ ├── ITableViewDataSource.cs │ │ │ ├── LICENSE │ │ │ └── README.md │ │ ├── RESTClient.meta │ │ ├── TSTableView.meta │ │ ├── AzureAppServices.meta │ │ ├── AzureFunctions.meta │ │ ├── RESTClient │ │ │ ├── http.meta │ │ │ ├── helpers.meta │ │ │ ├── RestClient.cs.meta │ │ │ ├── http │ │ │ │ ├── Method.cs.meta │ │ │ │ ├── QueryParams.cs.meta │ │ │ │ ├── RestRequest.cs.meta │ │ │ │ ├── RestResponse.cs.meta │ │ │ │ └── IRestResponse.cs.meta │ │ │ ├── helpers │ │ │ │ ├── Model.cs.meta │ │ │ │ └── JsonHelper.cs.meta │ │ │ └── RestClient.cs │ │ ├── AzureAppServices │ │ │ ├── http.meta │ │ │ ├── model.meta │ │ │ ├── authentication.meta │ │ │ ├── model │ │ │ │ ├── User.cs │ │ │ │ ├── ResponseError.cs │ │ │ │ ├── User.cs.meta │ │ │ │ ├── AccessToken.cs.meta │ │ │ │ ├── AccessTokenId.cs.meta │ │ │ │ ├── ResponseError.cs.meta │ │ │ │ ├── AccessTokenSecret.cs.meta │ │ │ │ ├── AuthenticatedUser.cs.meta │ │ │ │ ├── AuthenticatedUser.cs │ │ │ │ ├── AccessToken.cs │ │ │ │ ├── AccessTokenId.cs │ │ │ │ └── AccessTokenSecret.cs │ │ │ ├── IZumoClient.cs.meta │ │ │ ├── ZumoClient.cs.meta │ │ │ ├── http │ │ │ │ ├── ZumoRequest.cs.meta │ │ │ │ └── ZumoRequest.cs │ │ │ ├── AppServicesClient.cs.meta │ │ │ ├── authentication │ │ │ │ ├── AuthenticationProvider.cs.meta │ │ │ │ └── AuthenticationProvider.cs │ │ │ ├── AppServicesClient.cs │ │ │ ├── IZumoClient.cs │ │ │ └── ZumoClient.cs │ │ ├── AzureFunctions │ │ │ ├── AzureFunction.cs.meta │ │ │ ├── AzureFunctionClient.cs.meta │ │ │ ├── AzureFunctionClient.cs │ │ │ └── AzureFunction.cs │ │ └── RestClient │ │ │ ├── http │ │ │ ├── Method.cs │ │ │ ├── IRestResponse.cs │ │ │ ├── QueryParams.cs │ │ │ ├── RestResponse.cs │ │ │ └── RestRequest.cs │ │ │ └── helpers │ │ │ ├── Model.cs │ │ │ └── JsonHelper.cs │ │ ├── Message.meta │ │ ├── Dependencies.meta │ │ ├── Leaderboard.meta │ │ ├── Message │ │ ├── Prefabs.meta │ │ ├── View.meta │ │ ├── View │ │ │ ├── Transitions.meta │ │ │ ├── MessageView.cs.meta │ │ │ ├── Transitions │ │ │ │ ├── RectScale.cs.meta │ │ │ │ └── RectScale.cs │ │ │ └── MessageView.cs │ │ ├── Prefabs │ │ │ └── MessageView.prefab.meta │ │ ├── MessageManager.cs.meta │ │ └── MessageManager.cs │ │ └── Leaderboard │ │ ├── Prefabs.meta │ │ ├── View.meta │ │ ├── DataModel.meta │ │ ├── Prefabs │ │ ├── Leaderboard.prefab.meta │ │ └── ScoreCell.prefab.meta │ │ ├── DataModel │ │ ├── ScoreItem.cs │ │ ├── LeaderboardItem.cs │ │ ├── ScoreItem.cs.meta │ │ └── LeaderboardItem.cs.meta │ │ ├── View │ │ ├── ScoreCell.cs.meta │ │ └── ScoreCell.cs │ │ ├── LeaderboardManager.cs.meta │ │ └── LeaderboardManager.cs │ ├── .editorconfig │ ├── .gitignore │ ├── .vscode │ ├── settings.json │ └── launch.json │ └── omnisharp.json ├── media ├── logo-only │ ├── nether-logo-32x32.png │ ├── nether-logo-64x64.png │ ├── nether-logo-128x128.png │ ├── nether-logo-256x256.png │ ├── nether-logo-512x512.png │ ├── nether-logo-1024x1024.png │ └── nether-logo-2048x2048.png ├── title-only │ ├── nether-title-106x32.png │ ├── nether-title-1706x512.png │ ├── nether-title-213x64.png │ ├── nether-title-426x128.png │ ├── nether-title-853x256.png │ ├── nether-title-3413x1024.png │ └── nether-title-6826x2048.png └── both-logo-and-title │ ├── logo-title-138x32.png │ ├── logo-title-277x64.png │ ├── logo-title-1109x256.png │ ├── logo-title-2218x512.png │ ├── logo-title-554x128.png │ ├── logo-title-4437x1024.png │ └── logo-title-8874x2048.png ├── .gitattributes ├── .github └── PULL_REQUEST_TEMPLATE.md ├── appveyor.yml ├── LICENSE ├── .vscode ├── launch.json └── tasks.json ├── CONTRIBUTING.md ├── README.md └── .gitignore /doc/ARM-templates.md: -------------------------------------------------------------------------------- 1 | # ARM Templates 2 | 3 | -------------------------------------------------------------------------------- /src/cloud/functions/generic/quote-of-the-day/quote/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/leaderboard/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2017.1.1f1 2 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "7ca29bd4685c4e32b20c8e6905a37c85" 3 | } -------------------------------------------------------------------------------- /src/cloud/functions/generic/quote-of-the-day/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "7ca29bd4685c4e32b20c8e6905a37c85" 3 | } -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/around-me/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "7ca29bd4685c4e32b20c8e6905a37c85" 3 | } -------------------------------------------------------------------------------- /doc/images/new-functions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/doc/images/new-functions.png -------------------------------------------------------------------------------- /doc/images/base-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/doc/images/base-architecture.png -------------------------------------------------------------------------------- /doc/images/template-outputs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/doc/images/template-outputs.png -------------------------------------------------------------------------------- /doc/images/advanced-tools-kudu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/doc/images/advanced-tools-kudu.png -------------------------------------------------------------------------------- /doc/images/kudu-scenario-folders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/doc/images/kudu-scenario-folders.png -------------------------------------------------------------------------------- /media/logo-only/nether-logo-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/logo-only/nether-logo-32x32.png -------------------------------------------------------------------------------- /media/logo-only/nether-logo-64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/logo-only/nether-logo-64x64.png -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/around-me/leaderboard/sample.dat: -------------------------------------------------------------------------------- 1 | https://{your_function_app_name}.azurewebsites.net/api/Global/8 -------------------------------------------------------------------------------- /doc/images/debug-console-powershell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/doc/images/debug-console-powershell.png -------------------------------------------------------------------------------- /media/logo-only/nether-logo-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/logo-only/nether-logo-128x128.png -------------------------------------------------------------------------------- /media/logo-only/nether-logo-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/logo-only/nether-logo-256x256.png -------------------------------------------------------------------------------- /media/logo-only/nether-logo-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/logo-only/nether-logo-512x512.png -------------------------------------------------------------------------------- /media/logo-only/nether-logo-1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/logo-only/nether-logo-1024x1024.png -------------------------------------------------------------------------------- /media/logo-only/nether-logo-2048x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/logo-only/nether-logo-2048x2048.png -------------------------------------------------------------------------------- /media/title-only/nether-title-106x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/title-only/nether-title-106x32.png -------------------------------------------------------------------------------- /media/title-only/nether-title-1706x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/title-only/nether-title-1706x512.png -------------------------------------------------------------------------------- /media/title-only/nether-title-213x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/title-only/nether-title-213x64.png -------------------------------------------------------------------------------- /media/title-only/nether-title-426x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/title-only/nether-title-426x128.png -------------------------------------------------------------------------------- /media/title-only/nether-title-853x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/title-only/nether-title-853x256.png -------------------------------------------------------------------------------- /media/title-only/nether-title-3413x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/title-only/nether-title-3413x1024.png -------------------------------------------------------------------------------- /media/title-only/nether-title-6826x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/title-only/nether-title-6826x2048.png -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Sprites/Facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/src/Client/Unity/Assets/Sprites/Facebook.png -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Sprites/Twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/src/Client/Unity/Assets/Sprites/Twitter.png -------------------------------------------------------------------------------- /media/both-logo-and-title/logo-title-138x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/both-logo-and-title/logo-title-138x32.png -------------------------------------------------------------------------------- /media/both-logo-and-title/logo-title-277x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/both-logo-and-title/logo-title-277x64.png -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Sprites/GooglePlus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/src/Client/Unity/Assets/Sprites/GooglePlus.png -------------------------------------------------------------------------------- /media/both-logo-and-title/logo-title-1109x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/both-logo-and-title/logo-title-1109x256.png -------------------------------------------------------------------------------- /media/both-logo-and-title/logo-title-2218x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/both-logo-and-title/logo-title-2218x512.png -------------------------------------------------------------------------------- /media/both-logo-and-title/logo-title-554x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/both-logo-and-title/logo-title-554x128.png -------------------------------------------------------------------------------- /src/cloud/functions/generic/quote-of-the-day/functiondeploy.txt: -------------------------------------------------------------------------------- 1 | quote/function.json 2 | quote/project.json 3 | quote/run.csx 4 | quote/sample.dat 5 | -------------------------------------------------------------------------------- /media/both-logo-and-title/logo-title-4437x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/both-logo-and-title/logo-title-4437x1024.png -------------------------------------------------------------------------------- /media/both-logo-and-title/logo-title-8874x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/media/both-logo-and-title/logo-title-8874x2048.png -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Sprites/MicrosoftAccount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDX/nether/HEAD/src/Client/Unity/Assets/Sprites/MicrosoftAccount.png -------------------------------------------------------------------------------- /src/cloud/functions/generic/quote-of-the-day/quote/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "frameworks": { 3 | "net46":{ 4 | "dependencies": { 5 | } 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/score/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "leaderboard": "level1", 3 | "player": "mario", 4 | "playerId": "1337", 5 | "score": 420 6 | } -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/around-me/score/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "leaderboard": "level1", 3 | "player": "mario", 4 | "playerId": "1337", 5 | "score": 420 6 | } -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # force bash script files to have LF only, even on Windows so that the scripts run in the bash console! 2 | *.sh text eol=lf 3 | build/build-order.txt eol=lf 4 | build/test-order.txt eol=lf 5 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/around-me/score/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "frameworks": { 3 | "net46":{ 4 | "dependencies": { 5 | "Microsoft.Azure.DocumentDB": "1.17.0" 6 | } 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/score/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "frameworks": { 3 | "net46":{ 4 | "dependencies": { 5 | "Microsoft.Azure.DocumentDB": "1.17.0" 6 | } 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/leaderboard/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "frameworks": { 3 | "net46":{ 4 | "dependencies": { 5 | "Microsoft.Azure.DocumentDB": "1.17.0" 6 | } 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/around-me/leaderboard/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "frameworks": { 3 | "net46":{ 4 | "dependencies": { 5 | "Microsoft.Azure.DocumentDB": "1.17.0" 6 | } 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!149 &1 4 | NetworkManager: 5 | m_ObjectHideFlags: 0 6 | m_DebugLevel: 0 7 | m_Sendrate: 15 8 | m_AssetToPrefab: {} 9 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/functiondeploy.txt: -------------------------------------------------------------------------------- 1 | score/function.json 2 | score/project.json 3 | score/run.csx 4 | score/sample.dat 5 | leaderboard/function.json 6 | leaderboard/project.json 7 | leaderboard/run.csx 8 | leaderboard/sample.dat 9 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/around-me/functiondeploy.txt: -------------------------------------------------------------------------------- 1 | score/function.json 2 | score/project.json 3 | score/run.csx 4 | score/sample.dat 5 | leaderboard/function.json 6 | leaderboard/project.json 7 | leaderboard/run.csx 8 | leaderboard/sample.dat 9 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9742dd8b324184f22a7b8f38de09570b 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 02dd7f008f9d24099a71f1bd85007f09 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Scenes/Message Demo/MessageDemo.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b5c166dc6e704bebb599f08e8cb9fa5 3 | timeCreated: 1507902950 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Sprites.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c5ee3193cda1d4cb7a459aad1aa54fe3 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/TSTableView/LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1d2668084825e4936a2146960aca7bb0 3 | timeCreated: 1507888810 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/TSTableView/README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dbb690565e86441408f91b7adb847498 3 | timeCreated: 1507888810 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Message.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 602deef2665b044f8840876d21b0efba 3 | folderAsset: yes 4 | timeCreated: 1507901702 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Scenes/Leaderboard Demo/LeaderboardDemo.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 164ca1395da3b43bb98f1bf9303d9fdf 3 | timeCreated: 1507888810 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1798d239bd09242d782eddc6aabc6f81 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 23b3d987c97f84ac99592fcfd7542ddd 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Message/Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 20d85e84ec0724c21bbeec7f9f4f52e6 3 | folderAsset: yes 4 | timeCreated: 1507902913 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Message/View.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a914fdf8679b44b71a3d513bd45740fb 3 | folderAsset: yes 4 | timeCreated: 1507937799 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Scenes/Message Demo.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9dd7c07459cb843e28a66c7a40a36bd2 3 | folderAsset: yes 4 | timeCreated: 1507902924 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fa3639e271b1f45b0b1a42ecd2e39115 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/View.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e3ad9e75ab2f4a648cee4492ce25696 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Scenes/Leaderboard Demo.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: efc830cd4e2384a37af193079e229c79 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9ff632656fe0e4f2caf20dd1f2254f5a 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/TSTableView.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8cb9d041c9c824e43be7c065762220d2 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/DataModel.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d7415c69df8014d7a9e6848fc6085ae3 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Message/View/Transitions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cd2e8ff0c1b5c4d688390bbafb9b1ce0 3 | folderAsset: yes 4 | timeCreated: 1507937501 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4da721292a3d64646a7b16c8ecbfe3d0 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureFunctions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2b51ddbcca2c432fa12120cd822beaf 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient/http.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a3232f06f4cec4321a9d50bedc165f92 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/http.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 80039ac7f5a86407991efc7c42d03239 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 02960319f982c43adb826176d63f586b 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient/helpers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cf0b3b0bbcf0e4a93bad9ce7d7d4e4df 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/authentication.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 552f3419f3ffa413db2cd947d0dfecbe 3 | folderAsset: yes 4 | timeCreated: 1507888810 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/Prefabs/Leaderboard.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed365de9027fd4202a1e5d3c20c3f7c3 3 | timeCreated: 1507888815 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 0 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/Prefabs/ScoreCell.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 654c98f7d646440f3a45c6caa02a2982 3 | timeCreated: 1507888815 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 0 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Message/Prefabs/MessageView.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 748739ed42b13433a9428be522f7f7ef 3 | timeCreated: 1507915631 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 100100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/around-me/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | bin 3 | obj 4 | csx 5 | .vs 6 | edge 7 | Publish 8 | .vscode 9 | 10 | *.user 11 | *.suo 12 | *.cscfg 13 | *.Cache 14 | project.lock.json 15 | 16 | /packages 17 | /TestResults 18 | 19 | /tools/NuGet.exe 20 | /App_Data 21 | /secrets 22 | /data 23 | .secrets 24 | appsettings.json 25 | local.settings.json 26 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | bin 3 | obj 4 | csx 5 | .vs 6 | edge 7 | Publish 8 | .vscode 9 | 10 | *.user 11 | *.suo 12 | *.cscfg 13 | *.Cache 14 | project.lock.json 15 | 16 | /packages 17 | /TestResults 18 | 19 | /tools/NuGet.exe 20 | /App_Data 21 | /secrets 22 | /data 23 | .secrets 24 | appsettings.json 25 | local.settings.json 26 | -------------------------------------------------------------------------------- /src/cloud/functions/generic/quote-of-the-day/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | bin 3 | obj 4 | csx 5 | .vs 6 | edge 7 | Publish 8 | .vscode 9 | 10 | *.user 11 | *.suo 12 | *.cscfg 13 | *.Cache 14 | project.lock.json 15 | 16 | /packages 17 | /TestResults 18 | 19 | /tools/NuGet.exe 20 | /App_Data 21 | /secrets 22 | /data 23 | .secrets 24 | appsettings.json 25 | local.settings.json 26 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/User.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Azure.AppServices 5 | { 6 | [System.Serializable] 7 | public class User 8 | { 9 | public string userId; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/DataModel/ScoreItem.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | [System.Serializable] 5 | public class ScoreItem { 6 | public string player; 7 | public string playerId; 8 | public double score; 9 | } 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/View/ScoreCell.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c13559e52bb184a55986b52f4ecb3f2f 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Message/MessageManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 64253638b75a747a88454ec45d5eac7a 3 | timeCreated: 1507901719 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Message/View/MessageView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a0350d38478a54653badd7647bc9010e 3 | timeCreated: 1507915260 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/DataModel/LeaderboardItem.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | [System.Serializable] 5 | public class LeaderboardItem { 6 | public string player; 7 | public double score; 8 | public int rank; 9 | } 10 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/DataModel/ScoreItem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: afc054195022c49709953265dc9aeeb5 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/LeaderboardManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a18947f761e74ab2a373c76a4e69a92 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Scenes/Message Demo/MessageDemoScript.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3cb7c53cce0d847449336ccc992ffd67 3 | timeCreated: 1507902973 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient/RestClient.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ff88bb7dc12104c868c9d0499a6fc1ae 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient/http/Method.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 212fcf85821c24281929a25da039d56b 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/TSTableView/TableView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 254b98e02e9064aebb24408a5a65f593 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Message/View/Transitions/RectScale.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 89f30a189776d4d079134d5b8ad7312a 3 | timeCreated: 1507909489 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/IZumoClient.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 623274067812f450298994b60596a8da 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/ZumoClient.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6c0d789bdcec6457386e3d156b9a9924 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/ResponseError.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Azure.AppServices 5 | { 6 | [System.Serializable] 7 | public class ResponseError 8 | { 9 | public string error; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/User.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b1c71cc16c3e54b399241df07d718e23 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureFunctions/AzureFunction.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 94301d57842344e5ba66e26b258e3399 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient/helpers/Model.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6eb47c1f099284409886e6160ee08757 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient/http/QueryParams.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b24fdbfe22144a6e97539fd17dde6e4 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient/http/RestRequest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e4fd5520accc546ff87f1b375e2eeb19 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient/http/RestResponse.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bc29bc8829fa94440bd32eb42713b112 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/TSTableView/TableViewCell.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: af0b96ce4780e4aed9337612fe4ae1e2 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/DataModel/LeaderboardItem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6deba109eae474dfda7fc4b7149c334d 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Scenes/Leaderboard Demo/LeaderboardDemoScript.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 071db8780d92d4ce1b36d0268e1e9a6e 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/http/ZumoRequest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5e26a4065f94644118fd581e974405bc 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient/helpers/JsonHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a6255560d780046c8bd9f2ba79641c2d 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient/http/IRestResponse.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d3dd8e8a4f9464a9dbbee1598313ba73 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/TSTableView/ITableViewDataSource.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 896a20d5c0977457382994e92de48008 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/AppServicesClient.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3b882e1de98fa41c5be6c91f984956bb 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/AccessToken.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 98072303b833345ba8a76ecc4ad561fe 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/AccessTokenId.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 812498fe09e854b459ad4017f7a31276 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/ResponseError.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4a5282d1ab2af425c840b09e01633d59 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureFunctions/AzureFunctionClient.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 500aa9dc61f424708a6c31792927e82f 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/AccessTokenSecret.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cdde7bad42e1a4820814605d176be15b 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/AuthenticatedUser.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e4fc692dee8df4c3e89aec7862355e0c 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/authentication/AuthenticationProvider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cf69ed954a5ca49868f7616c2bc5b1e7 3 | timeCreated: 1507888812 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RestClient/http/Method.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using UnityEngine; 5 | using System.Collections; 6 | 7 | namespace RESTClient { 8 | public enum Method { 9 | GET, 10 | POST, 11 | PATCH, 12 | DELETE 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/AuthenticatedUser.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Azure.AppServices 5 | { 6 | [System.Serializable] 7 | public class AuthenticatedUser 8 | { 9 | public string authenticationToken; 10 | public User user; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/score/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "function", 5 | "name": "req", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "methods": [ 9 | "post" 10 | ], 11 | "route": "score" 12 | }, 13 | { 14 | "name": "$return", 15 | "type": "http", 16 | "direction": "out" 17 | } 18 | ], 19 | "disabled": false 20 | } -------------------------------------------------------------------------------- /src/cloud/functions/generic/quote-of-the-day/quote/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "function", 5 | "name": "req", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "methods": [ 9 | "get" 10 | ], 11 | "route": "quote" 12 | }, 13 | { 14 | "name": "$return", 15 | "type": "http", 16 | "direction": "out" 17 | } 18 | ], 19 | "disabled": false 20 | } -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/around-me/score/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "function", 5 | "name": "req", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "methods": [ 9 | "post" 10 | ], 11 | "route": "score" 12 | }, 13 | { 14 | "name": "$return", 15 | "type": "http", 16 | "direction": "out" 17 | } 18 | ], 19 | "disabled": false 20 | } -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/leaderboard/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "function", 5 | "name": "req", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "methods": [ 9 | "get" 10 | ], 11 | "route": "leaderboard" 12 | }, 13 | { 14 | "name": "$return", 15 | "type": "http", 16 | "direction": "out" 17 | } 18 | ], 19 | "disabled": false 20 | } -------------------------------------------------------------------------------- /src/Client/Unity/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = false 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | # Matches multiple files with brace expansion notation 13 | # Set default charset 14 | [*.{cs}] 15 | charset = utf-8 16 | indent_style = space 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: 8 | - enabled: 1 9 | path: Assets/Scenes/Leaderboard Demo/LeaderboardDemo.unity 10 | guid: 164ca1395da3b43bb98f1bf9303d9fdf 11 | - enabled: 1 12 | path: Assets/Scenes/Message Demo/MessageDemo.unity 13 | guid: 2b5c166dc6e704bebb599f08e8cb9fa5 14 | -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | m_Volume: 1 7 | Rolloff Scale: 1 8 | Doppler Factor: 1 9 | Default Speaker Mode: 2 10 | m_SampleRate: 0 11 | m_DSPBufferSize: 0 12 | m_VirtualVoiceCount: 512 13 | m_RealVoiceCount: 32 14 | m_SpatializerPlugin: 15 | m_AmbisonicDecoderPlugin: 16 | m_DisableAudio: 0 17 | m_VirtualizeEffects: 1 18 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/around-me/leaderboard/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "function", 5 | "name": "req", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "route": "{leaderboard}/{playerId}", 9 | "methods": [ 10 | "get" 11 | ] 12 | }, 13 | { 14 | "name": "$return", 15 | "type": "http", 16 | "direction": "out" 17 | } 18 | ], 19 | "disabled": false 20 | } -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/View/ScoreCell.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using UnityEngine; 5 | using System.Collections; 6 | using UnityEngine.UI; 7 | using Tacticsoft; 8 | using System; 9 | 10 | namespace Nether { 11 | public class ScoreCell : TableViewCell { 12 | public Text Rank; 13 | public Text Score; 14 | public Text Name; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 4 7 | m_ExternalVersionControlSupport: Visible Meta Files 8 | m_SerializationMode: 2 9 | m_DefaultBehaviorMode: 0 10 | m_SpritePackerMode: 0 11 | m_SpritePackerPaddingPower: 1 12 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd 13 | m_ProjectGenerationRootNamespace: 14 | m_UserGeneratedProjectSuffix: 15 | m_CollabEditorSettings: 16 | inProgressEnabled: 1 17 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Issue: #PutYourIssueNumberHere 2 | 3 | - [ ] Tick here to confirm that you have run RunCodeFormatter.ps1 4 | 5 | ### Description: 6 | Briefly describe the work that has been done and how that differ from what was there before. Only a few sentences since reviewer should be able to find more information in the issue linked at the top. 7 | 8 | ### Test: 9 | Describe how a reviewer should go ahead and test the introduced change(s) and/or what to look for. 10 | 11 | (Make sure that all above information is provided before submitting your pull request) 12 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/authentication/AuthenticationProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Azure.AppServices 5 | { 6 | // App Service authentication identity providers: Microsoft Account, Google Plus, Twitter, Facebook, Azure Active Directory 7 | public enum AuthenticationProvider 8 | { 9 | MicrosoftAccount = 0, 10 | Google = 1, 11 | Twitter = 2, 12 | Facebook = 3, 13 | AAD = 4 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Client/Unity/.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /Assets/AssetStoreTools* 7 | 8 | # Visual Studio 2015 cache directory 9 | /.vs/ 10 | 11 | # Autogenerated VS/MD/Consulo solution and project files 12 | ExportedObj/ 13 | .consulo/ 14 | *.csproj 15 | *.unityproj 16 | *.sln 17 | *.suo 18 | *.tmp 19 | *.user 20 | *.userprefs 21 | *.pidb 22 | *.booproj 23 | *.svd 24 | *.pdb 25 | 26 | # Unity3D generated meta files 27 | *.pidb.meta 28 | 29 | # Unity3D Generated File On Crash Reports 30 | sysinfo.txt 31 | 32 | # Builds 33 | *.apk 34 | *.unitypackage -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RestClient/http/IRestResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Net; 6 | 7 | namespace RESTClient { 8 | public interface IRestResponse { 9 | bool IsError { get; } 10 | 11 | string ErrorMessage { get; } 12 | 13 | string Url { get; } 14 | 15 | HttpStatusCode StatusCode { get; } 16 | 17 | string Content { get; } 18 | 19 | T Data { get; } 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/AppServicesClient.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using RESTClient; 5 | 6 | namespace Azure.AppServices { 7 | public sealed class AppServicesClient : ZumoClient { 8 | 9 | public AppServicesClient(string url) : base(url) { 10 | } 11 | 12 | public static AppServicesClient Create(string account) { 13 | string url = AppUrl(account); 14 | return new AppServicesClient(url); 15 | } 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/AccessToken.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Azure.AppServices 5 | { 6 | [System.Serializable] 7 | public class AccessToken 8 | { 9 | public string access_token; 10 | 11 | /// 12 | /// Facebook, Microsoft Account, Azure Active Directory "access_token" request body 13 | /// 14 | public AccessToken (string accessTokenValue) 15 | { 16 | access_token = accessTokenValue; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureFunctions/AzureFunctionClient.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Azure.AppServices; 5 | using RESTClient; 6 | 7 | namespace Azure.Functions { 8 | public sealed class AzureFunctionClient : ZumoClient { 9 | 10 | public AzureFunctionClient(string url) : base(url) { 11 | } 12 | 13 | public static AzureFunctionClient Create(string account) { 14 | string url = AppUrl(account); 15 | return new AzureFunctionClient(url); 16 | } 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2017 2 | version: 1.0.{build} 3 | build_script: 4 | - ps: ./src/cloud/functions/package.ps1 5 | - ps: Push-AppveyorArtifact packaged-content/nether-master.zip -FileName nether-master.zip -Type WebDeployPackage 6 | - git rev-parse HEAD > commit.txt 7 | deploy: 8 | - provider: AzureBlob 9 | storage_account_name: netherartifacts 10 | storage_access_key: 11 | secure: /KfEywXdV6Ys21sIob+Sjo3c3D+XPfQ/mftzcEeJs1Mom8HJmFSCu5919qqa/FzS++agyWJPwjBl0P7y8uc8m1CyszF5q/OUvWmgM0dIgGCWdR3FM2crLAGBipPqUF8G 12 | container: deployment-artifacts 13 | folder: master 14 | artifact: nether-master.zip,commit.txt 15 | on: 16 | branch: master 17 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/AccessTokenId.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Azure.AppServices 5 | { 6 | [System.Serializable] 7 | public class AccessTokenId 8 | { 9 | public string access_token; 10 | public string id_token; 11 | 12 | /// 13 | /// Google+ "access_token" and "id_token" request body 14 | /// 15 | public AccessTokenId (string accessTokenValue, string idTokenValue) 16 | { 17 | access_token = accessTokenValue; 18 | id_token = idTokenValue; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/model/AccessTokenSecret.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Azure.AppServices 5 | { 6 | [System.Serializable] 7 | public class AccessTokenSecret 8 | { 9 | public string access_token; 10 | public string access_token_secret; 11 | 12 | /// 13 | /// Twitter with "access_token" and "access_token_secret" request body 14 | /// 15 | public AccessTokenSecret (string accessTokenValue, string accessTokenSecret) 16 | { 17 | access_token = accessTokenValue; 18 | access_token_secret = accessTokenSecret; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/TSTableView/TableViewCell.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System; 4 | 5 | namespace Tacticsoft 6 | { 7 | /// 8 | /// The base class for cells in a TableView. ITableViewDataSource returns pointers 9 | /// to these objects 10 | /// 11 | public class TableViewCell : MonoBehaviour 12 | { 13 | /// 14 | /// TableView will cache unused cells and reuse them according to their 15 | /// reuse identifier. Override this to add custom cache grouping logic. 16 | /// 17 | public virtual string reuseIdentifier { 18 | get { 19 | return this.GetType().Name; 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Message/View/MessageView.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Nether; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using UnityEngine; 8 | using UnityEngine.UI; 9 | 10 | public class MessageView : MonoBehaviour { 11 | public Text message; 12 | 13 | [SerializeField] 14 | private RectScale transition; 15 | 16 | public void Open() { 17 | if (transition != null) { 18 | transition.Open(); 19 | return; 20 | } 21 | } 22 | 23 | public void Close() { 24 | if (transition != null && transition.enabled) { 25 | transition.Close(); 26 | return; 27 | } 28 | Destroy(this.gameObject); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 3 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_EnablePCM: 1 18 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 19 | m_AutoSimulation: 1 20 | -------------------------------------------------------------------------------- /src/Client/Unity/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // Configure glob patterns for excluding files and folders. 3 | "files.exclude": { 4 | "**/.git": true, 5 | "**/.DS_Store": true, 6 | "**/*.meta": true, 7 | "**/*.*.meta": true, 8 | "**/*.unity": true, 9 | "**/*.unityproj": true, 10 | "**/*.mat": true, 11 | "**/*.fbx": true, 12 | "**/*.FBX": true, 13 | "**/*.tga": true, 14 | "**/*.cubemap": true, 15 | "**/*.prefab": true, 16 | "**/Library": true, 17 | "**/ProjectSettings": true, 18 | "**/Temp": true 19 | }, 20 | "editor.tabSize": 2, 21 | "editor.insertSpaces": true, 22 | "editor.detectIndentation": false, 23 | "editor.rulers": [ 24 | 140 25 | ], 26 | "search.exclude": { 27 | "**/.git": true, 28 | "**/obj": true, 29 | "**/build": true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | m_Enabled: 0 7 | m_TestMode: 0 8 | m_TestEventUrl: 9 | m_TestConfigUrl: 10 | m_TestInitMode: 0 11 | CrashReportingSettings: 12 | m_EventUrl: https://perf-events.cloud.unity3d.com/api/events/crashes 13 | m_Enabled: 0 14 | m_CaptureEditorExceptions: 1 15 | UnityPurchasingSettings: 16 | m_Enabled: 0 17 | m_TestMode: 0 18 | UnityAnalyticsSettings: 19 | m_Enabled: 0 20 | m_InitializeOnStartup: 1 21 | m_TestMode: 0 22 | m_TestEventUrl: 23 | m_TestConfigUrl: 24 | UnityAdsSettings: 25 | m_Enabled: 0 26 | m_InitializeOnStartup: 1 27 | m_TestMode: 0 28 | m_EnabledPlatforms: 4294967295 29 | m_IosGameId: 30 | m_AndroidGameId: 31 | m_GameIds: {} 32 | m_GameId: 33 | PerformanceReportingSettings: 34 | m_Enabled: 0 35 | -------------------------------------------------------------------------------- /src/Client/Unity/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Unity Editor", 9 | "type": "unity", 10 | "request": "launch" 11 | }, 12 | { 13 | "name": "Windows Player", 14 | "type": "unity", 15 | "request": "launch" 16 | }, 17 | { 18 | "name": "OSX Player", 19 | "type": "unity", 20 | "request": "launch" 21 | }, 22 | { 23 | "name": "Linux Player", 24 | "type": "unity", 25 | "request": "launch" 26 | }, 27 | { 28 | "name": "iOS Player", 29 | "type": "unity", 30 | "request": "launch" 31 | }, 32 | { 33 | "name": "Android Player", 34 | "type": "unity", 35 | "request": "launch" 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/TSTableView/ITableViewDataSource.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System; 4 | 5 | namespace Tacticsoft 6 | { 7 | /// 8 | /// An interface for a data source to a TableView 9 | /// 10 | public interface ITableViewDataSource 11 | { 12 | /// 13 | /// Get the number of rows that a certain table should display 14 | /// 15 | int GetNumberOfRowsForTableView(TableView tableView); 16 | 17 | /// 18 | /// Get the height of a row of a certain cell in the table view 19 | /// 20 | float GetHeightForRowInTableView(TableView tableView, int row); 21 | 22 | /// 23 | /// Create a cell for a certain row in a table view. 24 | /// Callers should use tableView.GetReusableCell to cache objects 25 | /// 26 | TableViewCell GetCellForRowInTableView(TableView tableView, int row); 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/IZumoClient.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using RESTClient; 5 | using System; 6 | using System.Collections; 7 | 8 | namespace Azure.AppServices { 9 | public interface IZumoClient { 10 | 11 | AuthenticatedUser User { get; } 12 | IEnumerator LoginWithFacebook(string accessToken, Action> callback = null); 13 | IEnumerator LoginWithTwitter(string accessToken, string accessTokenSecret, Action> callback = null); 14 | 15 | IEnumerator LoginWithGoogle(string accessToken, string idToken, Action> callback = null); 16 | 17 | IEnumerator LoginWithMicrosoftAccount(string accessToken, Action> callback = null); 18 | 19 | IEnumerator LoginWithAAD(string accessToken, Action> callback = null); 20 | 21 | IEnumerator Logout(Action> callback = null); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/TSTableView/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Tacticsoft Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/cloud/functions/package.ps1: -------------------------------------------------------------------------------- 1 | $here = $PSScriptRoot 2 | $functionRootPath = "$here" 3 | $functionContentParentPath = "$here\..\..\..\packaged-content" 4 | $functionContentRootPath = "$functionContentParentPath\root" 5 | 6 | function ResetOutputDirectory() { 7 | if (Test-Path $functionContentParentPath) { 8 | Remove-Item $functionContentParentPath -Recurse -Force 9 | } 10 | New-Item $functionContentRootPath -ItemType Directory | out-null 11 | Set-Content "$functionContentParentPath\.gitignore" "**/**" # avoid accidentally committing this build output to source control :-) 12 | } 13 | function CopyDeployScript() { 14 | Copy-Item "$functionRootPath\deploy.ps1" "$functionContentRootPath\deploy.ps1" 15 | } 16 | function CreateZip() { 17 | $zipPath = "$functionContentParentPath/nether-master.zip" 18 | if (Test-Path $zipPath) { 19 | Remove-Item $zipPath -Force 20 | } 21 | [Reflection.Assembly]::LoadWithPartialName( "System.IO.Compression.FileSystem" ) | out-null 22 | [System.IO.Compression.ZipFile]::CreateFromDirectory("$functionContentParentPath\root", "$zipPath", "Fastest", $false) 23 | } 24 | 25 | 26 | ResetOutputDirectory 27 | CopyDeployScript 28 | 29 | CreateZip -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RestClient/http/QueryParams.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using UnityEngine; 10 | 11 | namespace RESTClient { 12 | public class QueryParams { 13 | private Dictionary parameters; 14 | 15 | public QueryParams() { 16 | parameters = new Dictionary(); 17 | } 18 | 19 | public void AddParam(string key, string value) { 20 | parameters.Add(key, value); 21 | } 22 | 23 | public override string ToString() { 24 | if (parameters.Count == 0) { 25 | return ""; 26 | } 27 | StringBuilder sb = new StringBuilder("?"); 28 | foreach (KeyValuePair param in parameters) { 29 | string key = WWW.EscapeURL(param.Key); 30 | string value = WWW.EscapeURL(param.Value); 31 | sb.Append(key + "=" + value + "&"); 32 | } 33 | sb.Remove(sb.Length - 1, 1); 34 | return sb.ToString(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RestClient/helpers/Model.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | 6 | namespace RESTClient { 7 | /// 8 | /// Helper methods to check and get object properties 9 | /// 10 | public class Model { 11 | public static bool HasProperty(object obj, string propertyName) { 12 | return GetProperty(obj, propertyName) != null; 13 | } 14 | 15 | public static PropertyInfo GetProperty(object obj, string propertyName) { 16 | #if NETFX_CORE 17 | return obj.GetType().GetTypeInfo().GetDeclaredProperty(propertyName); // GetProperty for UWP 18 | #else 19 | return obj.GetType().GetProperty(propertyName); 20 | #endif 21 | } 22 | 23 | public static bool HasField(object obj, string fieldName) { 24 | return GetField(obj, fieldName) != null; 25 | } 26 | 27 | public static FieldInfo GetField(object obj, string fieldName) { 28 | #if NETFX_CORE 29 | return obj.GetType().GetTypeInfo().GetDeclaredField(fieldName); // GetField for UWP 30 | #else 31 | return obj.GetType().GetField(fieldName); 32 | #endif 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Scenes/Message Demo/MessageDemoScript.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Nether; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using UnityEngine; 8 | 9 | public class MessageDemoScript : MonoBehaviour { 10 | 11 | [Header("Nether")] 12 | [SerializeField] 13 | private MessageManager messageManager; 14 | 15 | // Use this for initialization 16 | void Start() { 17 | if (messageManager == null) { 18 | Debug.LogError("Unity is missing connections to game objects in hierarchy."); 19 | return; 20 | } 21 | 22 | messageManager.LoadMessage(); 23 | } 24 | 25 | // Update is called once per frame 26 | void Update() { 27 | 28 | } 29 | 30 | #region Event handlers (optional) 31 | 32 | void OnEnable() { 33 | MessageManager.OnMessageSuccess += OnMessageSuccess; 34 | MessageManager.OnMessageFail += OnMessageFail; 35 | } 36 | 37 | 38 | void OnDisable() { 39 | MessageManager.OnMessageSuccess -= OnMessageSuccess; 40 | MessageManager.OnMessageFail -= OnMessageFail; 41 | } 42 | 43 | private void OnMessageSuccess(string message) { 44 | Debug.Log(":) " + message); 45 | } 46 | 47 | private void OnMessageFail() { 48 | Debug.LogWarning(":("); 49 | } 50 | 51 | #endregion 52 | } 53 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Launch (web)", 6 | "type": "coreclr", 7 | "request": "launch", 8 | "preLaunchTask": "build", 9 | "program": "${workspaceRoot}\\src\\Nether.Web\\bin\\Debug\\netcoreapp1.0\\Nether.Web.dll", 10 | "args": [], 11 | "cwd": "${workspaceRoot}\\src\\Nether.Web", 12 | "stopAtEntry": false, 13 | "internalConsoleOptions": "openOnSessionStart", 14 | "launchBrowser": { 15 | "enabled": true, 16 | "args": "${auto-detect-url}/api/swagger/ui", 17 | "windows": { 18 | "command": "cmd.exe", 19 | "args": "/C start ${auto-detect-url}" 20 | }, 21 | "osx": { 22 | "command": "open" 23 | }, 24 | "linux": { 25 | "command": "xdg-open" 26 | } 27 | }, 28 | "env": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | }, 31 | "sourceFileMap": { 32 | "/Views": "${workspaceRoot}/Views" 33 | } 34 | }, 35 | { 36 | "name": ".NET Core Attach", 37 | "type": "coreclr", 38 | "request": "attach", 39 | "processId": "${command.pickProcess}" 40 | } 41 | ] 42 | } -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 3 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_AutoSimulation: 1 23 | m_QueriesHitTriggers: 1 24 | m_QueriesStartInColliders: 1 25 | m_ChangeStopsCallbacks: 0 26 | m_CallbacksOnDisable: 1 27 | m_AlwaysShowColliders: 0 28 | m_ShowColliderSleep: 1 29 | m_ShowColliderContacts: 0 30 | m_ShowColliderAABB: 0 31 | m_ContactArrowScale: 0.2 32 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 33 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 34 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 35 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 36 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 37 | -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | m_SettingNames: 89 | - Humanoid 90 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## How to contribute? 4 | 5 | We appreciate and welcome community contributions. 6 | 7 | 1. You must sign a Contributor License Agreement (CLA) before submitting your pull request. To complete the CLA, submit a request via the form and electronically sign the CLA when you receive the email containing the link to the document. You need to complete the CLA only once to cover all Microsoft Open Technologies OSS projects. To sign a CLA please follow the instructions on [Microsoft CLA](https://cla.microsoft.com/) 8 | 9 | 1. Before starting work on a new feature, enhancement or fix, please create an issue and optionally assign it to yourself or a developer. 10 | 2. Fork the repository and make your changes against the fork just created (and not against master). 11 | 3. After making your changes in your fork, run tests and ensure that the code runs well on all suported platforms. Ensure that your branch has no merge conflicts with master. 12 | 5. Issue a Pull Request and make sure to fill out the information needed according to the Pull Request Template. 13 | 6. The admins will review your code and may optionally request conformance, functional or other changes. Work with them to resolve any issues. 14 | 7. Upon acceptance, your code will be merged into the master branch and will become available for all. 15 | 16 | ## Coding style 17 | This project uses the [coding style](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md) from the [dotnet/corefx](https://github.com/dotnet/corefx) repo. 18 | 19 | The coding style (and C# license header) is enforced by the [CodeFormatter](https://github.com/dotnet/codeformatter) tool when building a Pull Request. If you are [running on Windows](https://github.com/dotnet/codeformatter/issues/106) then you can run the tool locally to short-circuit the feedback loop. If you're on another platform then vote up the [xplat issue](https://github.com/dotnet/codeformatter/issues/106) :-) 20 | 21 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Message/View/Transitions/RectScale.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using UnityEngine; 7 | 8 | public class RectScale : MonoBehaviour { 9 | public float duration = 0.5f; 10 | private float a = 0.0f; 11 | private float b = 1.0f; 12 | private float timer = 0.0f; 13 | private RectTransform panel; 14 | private bool open = false; 15 | private bool isPlaying = false; 16 | 17 | // Use this for initialization 18 | void Start() { 19 | panel = gameObject.GetComponent(); 20 | 21 | if (panel == null) { 22 | Debug.LogWarning("Game object doesn't have Rect Transform component to scale."); 23 | return; 24 | } 25 | 26 | ApplyInitialTransform(); 27 | } 28 | 29 | // Update is called once per frame 30 | void Update() { 31 | if (!isPlaying) { 32 | return; 33 | } 34 | timer += Time.deltaTime; 35 | if (timer < duration) { 36 | float t = timer / duration; 37 | float value = Mathf.Lerp(a, b, t); 38 | panel.localScale = new Vector3(value, value, value); 39 | } else { 40 | ApplyFinalTransform(); 41 | timer = 0.0f; 42 | isPlaying = false; 43 | } 44 | } 45 | 46 | public void Open() { 47 | open = true; 48 | a = 0.0f; 49 | b = 1.0f; 50 | timer = 0.0f; 51 | isPlaying = true; 52 | } 53 | 54 | public void Close() { 55 | open = false; 56 | a = 1.0f; 57 | b = 0.0f; 58 | timer = 0.0f; 59 | isPlaying = true; 60 | } 61 | 62 | public void Toggle() { 63 | open = !open; 64 | if (open) { 65 | Open(); 66 | } else { 67 | Close(); 68 | } 69 | } 70 | 71 | private void ApplyInitialTransform() { 72 | panel.localScale = Vector3.zero; 73 | } 74 | 75 | private void ApplyFinalTransform() { 76 | if (!open) { 77 | Destroy(this.gameObject); // automatically destroy after closing 78 | return; 79 | } 80 | panel.localScale = open ? Vector3.one : Vector3.zero; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/cloud/functions/deploy.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory = $true)] 3 | [string] $Group, 4 | [Parameter(Mandatory = $true)] 5 | [string]$Scenario, 6 | [Parameter()] 7 | [string]$BaseUrl = "https://raw.githubusercontent.com/MicrosoftDX/nether/master/src/cloud/functions/" 8 | ) 9 | $here = $PSScriptRoot 10 | 11 | function EnsureTrailingSlash($url) { 12 | if (-not $url.EndsWith("/")) { 13 | $url + "/" 14 | } 15 | else { 16 | $url 17 | } 18 | } 19 | function DownloadScenario($url, $groupName, $scenarioName) { 20 | $webClient = New-Object System.Net.WebClient 21 | try { 22 | Write-Output "Determining file list for Group '$groupName', Scenario '$scenarioName'..." 23 | $scenarioUrl = "$url$groupName/$scenarioName" 24 | $files = $webClient.DownloadString("$scenarioUrl/functiondeploy.txt").Split() ` 25 | | Where-Object { -not [string]::IsNullOrEmpty($_) } 26 | } 27 | catch { 28 | $e = $error[0] 29 | if ($e.Exception.InnerException.Response.StatusCode -eq "NotFound") { 30 | Write-Output "Scenario not found" 31 | } 32 | else { 33 | Write-Output "Error occurred: $($e.Exception.ToString())" 34 | } 35 | return 36 | $webClient.Dispose() 37 | } 38 | 39 | try { 40 | $files | ForEach-Object { 41 | $filename = $_ 42 | $folder = Split-Path -Path "$here\$filename"; 43 | if ( -not (Test-Path $folder)) { 44 | "Creating folder $folder"; mkdir $folder | Out-Null 45 | } 46 | Write-Output "Downloading $filename..." 47 | $webClient.DownloadFile("$scenarioUrl/$filename", "$here/$filename") 48 | } 49 | } 50 | catch { 51 | $e = $error[0] 52 | Write-Output "Error occurred: $($e.Exception.ToString())" 53 | } 54 | finally { 55 | $webClient.Dispose() 56 | } 57 | } 58 | 59 | $BaseUrl = EnsureTrailingSlash $BaseUrl 60 | 61 | # TODO - error handling (url not found etc) 62 | # TODO warn if target exists 63 | # TODO allow cherry-picking functions? 64 | 65 | DownloadScenario $BaseUrl $Group $Scenario 66 | 67 | "Deployment done!" 68 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RESTClient/RestClient.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using UnityEngine; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using System; 8 | using System.Text.RegularExpressions; 9 | 10 | 11 | #if !NETFX_CORE || UNITY_ANDROID 12 | using System.Net; 13 | using System.Security.Cryptography.X509Certificates; 14 | using System.Net.Security; 15 | #endif 16 | 17 | namespace RESTClient { 18 | public class RestClient { 19 | public string Url { get; private set; } 20 | 21 | /// 22 | /// Creates a new REST Client 23 | /// 24 | public RestClient(string url, bool forceHttps = true) { 25 | if (forceHttps) { 26 | Url = HttpsUri(url); 27 | } 28 | // required for running in Windows and Android 29 | #if !NETFX_CORE || UNITY_ANDROID 30 | ServicePointManager.ServerCertificateValidationCallback = RemoteCertificateValidationCallback; 31 | #endif 32 | } 33 | 34 | public override string ToString() { 35 | return this.Url; 36 | } 37 | 38 | /// 39 | /// Changes 'http' to be 'https' instead 40 | /// 41 | private static string HttpsUri(string appUrl) { 42 | return Regex.Replace(appUrl, "(?si)^http://", "https://").TrimEnd('/'); 43 | } 44 | 45 | private static string DomainName(string url) { 46 | var match = Regex.Match(url, @"^(https:\/\/|http:\/\/)(www\.)?([a-z0-9-_]+\.[a-z]+)", RegexOptions.IgnoreCase); 47 | if (match.Groups.Count == 4 && match.Groups[3].Value.Length > 0) { 48 | return match.Groups[3].Value; 49 | } 50 | return url; 51 | } 52 | 53 | #if !NETFX_CORE || UNITY_ANDROID 54 | private bool RemoteCertificateValidationCallback(System.Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { 55 | // Check the certificate to see if it was issued from Azure 56 | if (certificate.Subject.Contains(DomainName(Url))) { 57 | return true; 58 | } else { 59 | return false; 60 | } 61 | } 62 | #endif 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Client/Unity/omnisharp.json: -------------------------------------------------------------------------------- 1 | { 2 | "formattingOptions": { 3 | "NewLine": "\n", 4 | "UseTabs": false, 5 | "TabSize": 2, 6 | "IndentationSize": 2, 7 | "SpacingAfterMethodDeclarationName": false, 8 | "SpaceWithinMethodDeclarationParenthesis": false, 9 | "SpaceBetweenEmptyMethodDeclarationParentheses": false, 10 | "SpaceAfterMethodCallName": false, 11 | "SpaceWithinMethodCallParentheses": false, 12 | "SpaceBetweenEmptyMethodCallParentheses": false, 13 | "SpaceAfterControlFlowStatementKeyword": true, 14 | "SpaceWithinExpressionParentheses": false, 15 | "SpaceWithinCastParentheses": false, 16 | "SpaceWithinOtherParentheses": false, 17 | "SpaceAfterCast": false, 18 | "SpacesIgnoreAroundVariableDeclaration": false, 19 | "SpaceBeforeOpenSquareBracket": false, 20 | "SpaceBetweenEmptySquareBrackets": false, 21 | "SpaceWithinSquareBrackets": false, 22 | "SpaceAfterColonInBaseTypeDeclaration": true, 23 | "SpaceAfterComma": true, 24 | "SpaceAfterDot": false, 25 | "SpaceAfterSemicolonsInForStatement": true, 26 | "SpaceBeforeColonInBaseTypeDeclaration": true, 27 | "SpaceBeforeComma": false, 28 | "SpaceBeforeDot": false, 29 | "SpaceBeforeSemicolonsInForStatement": false, 30 | "SpacingAroundBinaryOperator": "single", 31 | "IndentBraces": false, 32 | "IndentBlock": true, 33 | "IndentSwitchSection": true, 34 | "IndentSwitchCaseSection": true, 35 | "LabelPositioning": "oneLess", 36 | "WrappingPreserveSingleLine": true, 37 | "WrappingKeepStatementsOnSingleLine": true, 38 | "NewLinesForBracesInTypes": false, 39 | "NewLinesForBracesInMethods": false, 40 | "NewLinesForBracesInProperties": false, 41 | "NewLinesForBracesInAccessors": false, 42 | "NewLinesForBracesInAnonymousMethods": false, 43 | "NewLinesForBracesInControlBlocks": false, 44 | "NewLinesForBracesInAnonymousTypes": false, 45 | "NewLinesForBracesInObjectCollectionArrayInitializers": false, 46 | "NewLinesForBracesInLambdaExpressionBody": false, 47 | "NewLineForElse": false, 48 | "NewLineForCatch": false, 49 | "NewLineForFinally": false, 50 | "NewLineForMembersInObjectInit": false, 51 | "NewLineForMembersInAnonymousTypes": false, 52 | "NewLineForClausesInQuery": false 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/http/ZumoRequest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using UnityEngine; 5 | using System.Text; 6 | using RESTClient; 7 | 8 | namespace Azure.AppServices { 9 | public sealed class ZumoRequest : RestRequest { 10 | 11 | // NB: Exclude system properties is a workaround to ignore read-only system properties during JSON utility deserialization. 12 | // If set to true then App Services System Properties will be stripped from the request body during deserialization. 13 | private bool excludeSystemProperties; 14 | 15 | public ZumoRequest(string url, Method httpMethod = Method.GET, bool excludeSystemProperties = true, AuthenticatedUser user = null) : base(url, httpMethod) { 16 | this.excludeSystemProperties = excludeSystemProperties; 17 | this.AddHeader("ZUMO-API-VERSION", "2.0.0"); 18 | this.AddHeader("Accept", "application/json"); 19 | this.AddHeader("Content-Type", "application/json; charset=utf-8"); 20 | // User Authentictated request 21 | if (user != null && !string.IsNullOrEmpty(user.authenticationToken)) { 22 | this.AddHeader("X-ZUMO-AUTH", user.authenticationToken); 23 | } 24 | } 25 | 26 | // Facebook, Microsoft Account, Azure Active Directory 27 | public void AddBodyAccessToken(string token) { 28 | AccessToken accessToken = new AccessToken(token); 29 | this.AddBody(accessToken); 30 | } 31 | 32 | // Twitter 33 | public void AddBodyAccessTokenSecret (string token, string tokenSecret) 34 | { 35 | AccessTokenSecret accessTokenSecret = new AccessTokenSecret (token, tokenSecret); 36 | this.AddBody (accessTokenSecret); 37 | } 38 | 39 | // Google+ 40 | public void AddBodyAccessTokenId (string token, string idToken) 41 | { 42 | AccessTokenId accessTokenId = new AccessTokenId (token, idToken); 43 | this.AddBody (accessTokenId); 44 | } 45 | 46 | public override void AddBody(T data, string contentType = "application/json; charset=utf-8") { 47 | string jsonString = excludeSystemProperties ? JsonHelper.ToJsonExcludingSystemProperties(data) : JsonUtility.ToJson(data); 48 | byte[] bytes = Encoding.UTF8.GetBytes(jsonString); 49 | this.AddBody(bytes, contentType); 50 | } 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/cloud/functions/generic/quote-of-the-day/README.md: -------------------------------------------------------------------------------- 1 | # Quote of the Day 2 | 3 | Implements a service that will respond with a different quote depending of the day of the week. This scenario can easily be used as a starting point to develop more advance services. 4 | 5 | ## Scenario Requirements 6 | 7 | The following requirements where considered while creating this scenario: 8 | 9 | * Game client should be able to retrieve a daily quote using a REST API 10 | * Demonstrate usage of Azure Functions without any interactin with a database 11 | 12 | ## Prerequisite 13 | 14 | In order to follow along in this scenario the following prerequisite need to be fulfilled: 15 | 16 | * You need to have access to a Microsoft Azure Subscription. If you don't have access you can sign up for an Azure Subscription at [https://azure.com](https://azure.com) 17 | * Deployment of Nether Base Architecture should be done. If you haven't deployed the Base Architecture, follow the instructions at [Deploy the Base Architecture](../../../../../doc/deploy-base-architecture.md) 18 | * You need to remember or re-visit the instructions described in [Deploy Scenario](../../../../../doc/deploy-scenario.md) 19 | * Installed the required SDK/Tools for the game client development, for example: Unity 20 | 21 | ## Scenario API Description 22 | 23 | When this scenario is deployed you'll have added one Azure function according to the following. 24 | 25 | Resource | Verb | Parameters | Description 26 | ------------------|------|--------------------------|----------------------------- 27 | /api/quote | GET | [None](quote/sample.dat) | Retrieves the quote of the day 28 | 29 | ## Deploying the Scenario 30 | 31 | > Please refer to the instructions in [Deploy a Nether Scenario](../../../../../doc/deploy-scenario.md) for more detailed instructions on how to find your Kudu PowerShell interface and how deployment works. 32 | 33 | From the Kudu PowerShell interface in your Azure Function App, execute the following command: 34 | 35 | ``` 36 | ./deploy.ps1 -Group generic -Scenario quote-of-the-day 37 | ``` 38 | 39 | Wait for the deployment to finish before continuing. 40 | 41 | ## Calling the API from a Client Application/Game 42 | 43 | _To be provided_ 44 | 45 | > Even if the documentation is not yet fully provided, we do have a sample implementation and Client Side SDK developed for Unity that you could use as a starting poing. Please have a look at [the implementation here](../../../../Client/Unity). 46 | -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 12 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 38 | - {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0} 39 | m_PreloadedShaders: [] 40 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 41 | type: 0} 42 | m_CustomRenderPipeline: {fileID: 0} 43 | m_TransparencySortMode: 0 44 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 45 | m_DefaultRenderingPath: 1 46 | m_DefaultMobileRenderingPath: 1 47 | m_TierSettings: [] 48 | m_LightmapStripping: 0 49 | m_FogStripping: 0 50 | m_InstancingStripping: 0 51 | m_LightmapKeepPlain: 1 52 | m_LightmapKeepDirCombined: 1 53 | m_LightmapKeepDynamicPlain: 1 54 | m_LightmapKeepDynamicDirCombined: 1 55 | m_LightmapKeepShadowMask: 1 56 | m_LightmapKeepSubtractive: 1 57 | m_FogKeepLinear: 1 58 | m_FogKeepExp: 1 59 | m_FogKeepExp2: 1 60 | m_AlbedoSwatchInfos: [] 61 | m_LightsUseLinearIntensity: 0 62 | m_LightsUseColorTemperature: 0 63 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/README.md: -------------------------------------------------------------------------------- 1 | # Top N Leaderboard 2 | 3 | Implements a simple top 10 leaderboard service, that will allow you to submit scores and retrieve a leaderboard. 4 | 5 | ## Scenario Requirements 6 | 7 | The following requirements where considered while creating this scenario: 8 | 9 | * Game client should be able to submit game scores using a REST API 10 | * Game client should be able to retrieve a leaderboard using a REST API 11 | * Demonstrate usage of Azure Functions that communicates with Cosmos DB 12 | 13 | ## Prerequisite 14 | 15 | In order to follow along in this scenario the following prerequisite need to be fulfilled: 16 | 17 | * You need to have access to a Microsoft Azure Subscription. If you don't have access you can sign up for an Azure Subscription at [https://azure.com](https://azure.com) 18 | * Deployment of Nether Base Architecture should be done. If you haven't deployed the Base Architecture, follow the instructions at [Deploy the Base Architecture](../../../../../doc/deploy-base-architecture.md) 19 | * You need to remember or re-visit the instructions described in [Deploy Scenario](../../../../../doc/deploy-scenario.md) 20 | * Installed the required SDK/Tools for the game client development, for example: Unity 21 | 22 | ## Scenario API Description 23 | 24 | When this scenario is deployed you'll have added one Azure function according to the following. 25 | 26 | Resource | Verb | Parameters | Description 27 | ------------------|------|--------------------------|----------------------------- 28 | /api/score | POST | [Body Application/Json](score/sample.dat) | Posts a score to the leaderboard 29 | /api/leaderboard | GET | [None](leaderboard/sample.dat) | Retrieves the leaderboard 30 | 31 | ## Deploying the Scenario 32 | 33 | > Please refer to the instructions in [Deploy a Nether Scenario](../../../../../doc/deploy-scenario.md) for more detailed instructions on how to find your Kudu PowerShell interface and how deployment works. 34 | 35 | From the Kudu PowerShell interface in your Azure Function App, execute the following command: 36 | 37 | ``` 38 | ./deploy.ps1 -Group leaderboards -Scenario top-n 39 | ``` 40 | 41 | Wait for the deployment to finish before continuing. 42 | 43 | ## Calling the API from a Client Application/Game 44 | 45 | _To be provided_ 46 | 47 | > Even if the documentation is not yet fully provided, we do have a sample implementation and Client Side SDK developed for Unity that you could use as a starting poing. Please have a look at [the implementation here](../../../../Client/Unity). 48 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/around-me/README.md: -------------------------------------------------------------------------------- 1 | # Around Me Leaderboard 2 | 3 | Implements a simple leaderboard service, that will allow you to submit scores and retrieve a leaderboard +/-5 positions around specific player with global ranking. 4 | 5 | ## Scenario Requirements 6 | 7 | The following requirements where considered while creating this scenario: 8 | 9 | * Game client should be able to submit game scores using a REST API 10 | * Game client should be able to retrieve a leaderboard using a REST API 11 | * Demonstrate usage of Azure Functions that communicates with Cosmos DB 12 | 13 | ## Prerequisite 14 | 15 | In order to follow along in this scenario the following prerequisite need to be fulfilled: 16 | 17 | * You need to have access to a Microsoft Azure Subscription. If you don't have access you can sign up for an Azure Subscription at [https://azure.com](https://azure.com) 18 | * Deployment of Nether Base Architecture should be done. If you haven't deployed the Base Architecture, follow the instructions at [Deploy the Base Architecture](../../../../../doc/deploy-base-architecture.md) 19 | * You need to remember or re-visit the instructions described in [Deploy Scenario](../../../../../doc/deploy-scenario.md) 20 | * Installed the required SDK/Tools for the game client development, for example: Unity 21 | 22 | ## Scenario API Description 23 | 24 | When this scenario is deployed you'll have added one Azure function according to the following. 25 | 26 | Resource | Verb | Parameters | Description 27 | ------------------|------|--------------------------|----------------------------- 28 | /api/score | POST | [Body Application/Json](score/sample.dat) | Posts a score to the leaderboard 29 | /api/leaderboard | GET | [{leaderboard}/{playerId}](leaderboard/sample.dat) | Retrieves the leaderboard 30 | 31 | ## Deploying the Scenario 32 | 33 | > Please refer to the instructions in [Deploy a Nether Scenario](../../../../../doc/deploy-scenario.md) for more detailed instructions on how to find your Kudu PowerShell interface and how deployment works. 34 | 35 | From the Kudu PowerShell interface in your Azure Function App, execute the following command: 36 | 37 | ``` 38 | ./deploy.ps1 -Group leaderboards -Scenario around-me 39 | ``` 40 | 41 | Wait for the deployment to finish before continuing. 42 | 43 | ## Calling the API from a Client Application/Game 44 | 45 | _To be provided_ 46 | 47 | > Even if the documentation is not yet fully provided, we do have a sample implementation and Client Side SDK developed for Unity that you could use as a starting poing. Please have a look at [the implementation here](../../../../Client/Unity). 48 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RestClient/http/RestResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Net; 5 | 6 | namespace RESTClient { 7 | public abstract class Response { 8 | public bool IsError { get; set; } 9 | 10 | public string ErrorMessage { get; set; } 11 | 12 | public string Url { get; set; } 13 | 14 | public HttpStatusCode StatusCode { get; set; } 15 | 16 | public string Content { get; set; } 17 | 18 | protected Response(HttpStatusCode statusCode) { 19 | this.StatusCode = statusCode; 20 | this.IsError = !((int)statusCode >= 200 && (int)statusCode < 300); 21 | } 22 | 23 | // success 24 | protected Response(HttpStatusCode statusCode, string url, string text) { 25 | this.IsError = false; 26 | this.Url = url; 27 | this.ErrorMessage = null; 28 | this.StatusCode = statusCode; 29 | this.Content = text; 30 | } 31 | 32 | // failure 33 | protected Response(string error, HttpStatusCode statusCode, string url, string text) { 34 | this.IsError = true; 35 | this.Url = url; 36 | this.ErrorMessage = error; 37 | this.StatusCode = statusCode; 38 | this.Content = text; 39 | } 40 | } 41 | 42 | public sealed class RestResponse : Response { 43 | // success 44 | public RestResponse(HttpStatusCode statusCode, string url, string text) : base(statusCode, url, text) { 45 | } 46 | 47 | // failure 48 | public RestResponse(string error, HttpStatusCode statusCode, string url, string text) : base(error, statusCode, url, text) { 49 | } 50 | } 51 | 52 | public sealed class RestResponse : Response, IRestResponse { 53 | public T Data { get; set; } 54 | 55 | // success 56 | public RestResponse(HttpStatusCode statusCode, string url, string text, T data) : base(statusCode, url, text) { 57 | this.Data = data; 58 | } 59 | public RestResponse(HttpStatusCode statusCode, string url, string text) : base(statusCode, url, text) { 60 | } 61 | 62 | // failure 63 | public RestResponse(string error, HttpStatusCode statusCode, string url, string text) : base(error, statusCode, url, text) { 64 | } 65 | } 66 | 67 | /// 68 | /// Parsed JSON result could either be an object or an array of objects 69 | /// 70 | internal sealed class RestResult : Response { 71 | public T AnObject { get; set; } 72 | 73 | public T[] AnArrayOfObjects { get; set; } 74 | 75 | public RestResult(HttpStatusCode statusCode) : base(statusCode) { 76 | } 77 | } 78 | 79 | } 80 | 81 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureFunctions/AzureFunction.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using UnityEngine; 5 | using System.Collections; 6 | using System; 7 | using RESTClient; 8 | using Azure.AppServices; 9 | 10 | namespace Azure.Functions { 11 | public class AzureFunction { 12 | private AzureFunctionClient client; 13 | 14 | private string name; // Azure Function name 15 | private string key; // Azure Function key 16 | private string apiPath; // Azure Functions API path 17 | 18 | private const string API = "api"; 19 | private const string PARAM_CODE = "code"; 20 | 21 | public AzureFunction(string name, AzureFunctionClient client, string key = null, string apiPath = API) { 22 | this.client = client; 23 | this.name = name; 24 | this.key = key; 25 | this.apiPath = apiPath; 26 | } 27 | 28 | public override string ToString() { 29 | return name; 30 | } 31 | 32 | public IEnumerator Post(B body, Action> callback = null) { 33 | var request = new ZumoRequest(ApiUrl(), Method.POST, false, client.User); 34 | if (!string.IsNullOrEmpty(key)) { 35 | request.AddQueryParam(PARAM_CODE, key, true); 36 | } 37 | request.AddBody(body); 38 | yield return request.Request.Send(); 39 | if (typeof(T) == typeof(string)) { 40 | request.GetText(callback); 41 | } else { 42 | request.ParseJson(callback); 43 | } 44 | } 45 | 46 | public IEnumerator GetArray(Action> callback = null, string path = null) { 47 | var request = new ZumoRequest(ApiUrl(path), Method.GET, false, client.User); 48 | if (!string.IsNullOrEmpty(key)) { 49 | request.AddQueryParam(PARAM_CODE, key, true); 50 | } 51 | yield return request.Request.Send(); 52 | request.ParseJsonArray(callback); 53 | } 54 | 55 | public IEnumerator Get(Action> callback = null, string path = null) { 56 | var request = new ZumoRequest(ApiUrl(path), Method.GET, false, client.User); 57 | if (!string.IsNullOrEmpty(key)) { 58 | request.AddQueryParam(PARAM_CODE, key, true); 59 | } 60 | yield return request.Request.Send(); 61 | if (typeof(T) == typeof(string)) { 62 | request.GetText(callback); 63 | } else { 64 | request.ParseJson(callback); 65 | } 66 | } 67 | 68 | private string ApiUrl(string path = null) { 69 | string endpoint = string.IsNullOrEmpty(path) ? "" : "/" + path; 70 | return string.Format("{0}/{1}/{2}{3}", client.Url, apiPath, name, endpoint); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Nether Logo](https://raw.githubusercontent.com/MicrosoftDX/nether/master/media/both-logo-and-title/logo-title-1109x256.png) 2 | # Building blocks for gaming on Azure 3 | 4 | Master Branch Status 5 | 6 | AppVeyor: [![Build status](https://ci.appveyor.com/api/projects/status/v5btbm617bcmu6nq?svg=true)](https://ci.appveyor.com/project/stuartleeks/nether) 7 | 8 | 11 | 12 | ## About 13 | 14 | Nether is a project composed of reusable set of building blocks, projects, services and best practices designed for Gaming workloads powered by Microsoft Azure, aimed to be beneficial for many type of game developers seeking inspiration or a fully implemented solution. 15 | 16 | ## Getting Started 17 | 18 | Getting started is an easy three step project: 19 | 20 | 1. Sign up for an Azure Subscription if you don't already have one at [https://azure.com](https://azure.com) 21 | 2. [Deploy the Base Architecture](doc/deploy-base-architecture.md) 22 | 3. Pick one of the scenarios below, read through the scenario description and deploy using [these instructions](doc/deploy-scenario.md) 23 | 24 | > That's it. Even though Azure definitively have a lot of SDKs and client tools that can help you out, the Server Less Architecture used in these scenarios require no local tools at all. In fact you could use your phone to deploy a leaderboard if you wanted to. 25 | 26 | ## Scenarios 27 | 28 | These are the scenarios that we currently have implemented in Nether. Each scenario contains some documentation as well as the required code to implement them. Unless otherwise stated, the scenarios all use the "base architecture". 29 | 30 | ### Generic 31 | 32 | * [Quote of the Day](src/cloud/functions/generic/quote-of-the-day/) 33 | 34 | ### Leaderboards 35 | 36 | * [Top N Leaderboard](src/cloud/functions/leaderboards/top-n/) 37 | * [Around Me Leaderboard](src/cloud/functions/leaderboards/around-me) 38 | * Facebook Friends Leaderboard (_work in progress_) 39 | 40 | ### Match Making 41 | 42 | * Simple Match Making (_work in progress_) 43 | 44 | ## Contribute Code 45 | 46 | We welcome contributions. To contribute please follow the instructions on 47 | [How to contribute?](CONTRIBUTING.md) 48 | 49 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 50 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 51 | or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 52 | 53 | ## Reporting issues and feedback 54 | 55 | If you encounter any bugs please file an issue in the Issues section of our GitHub repo. 56 | 57 | ## License 58 | 59 | Nether is licensed under the MIT License. 60 | -------------------------------------------------------------------------------- /src/cloud/functions/generic/quote-of-the-day/quote/run.csx: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Configuration; 5 | using System.Net; 6 | 7 | private static string baseArchitectureVersion = ConfigurationManager.AppSettings["BASE_ARCHITECTURE_VERSION"]; 8 | private const string requiredBaseArchitectureVersion = "1"; 9 | 10 | private static bool runOnce = true; 11 | 12 | public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log) 13 | { 14 | // Run initialization only once. 15 | // Remarks: This initialization will run once on every instance and on every recompile of this function 16 | if (runOnce) 17 | { 18 | log.Info("Running initialization"); 19 | 20 | if (string.IsNullOrWhiteSpace(baseArchitectureVersion) || 21 | !baseArchitectureVersion.StartsWith(requiredBaseArchitectureVersion)) log.Error($"The base architecture version doesn't match the expected version {requiredBaseArchitectureVersion}"); 22 | 23 | log.Info("Initialization done!"); 24 | } 25 | var now = DateTime.UtcNow; 26 | 27 | string msg; 28 | 29 | switch (now.DayOfWeek) 30 | { 31 | case DayOfWeek.Monday: 32 | msg = "It's Monday, don't forget to be aweseome. -Anonymous"; 33 | break; 34 | case DayOfWeek.Tuesday: 35 | msg = "Tuesday isn't so bad...It's a sign that I've somehow survived Monday. -Anonymous"; 36 | break; 37 | case DayOfWeek.Wednesday: 38 | msg = "Wednesday is like middle finger of the week. -Anonymous"; 39 | break; 40 | case DayOfWeek.Thursday: 41 | msg = "Thursday is perhaps the worst day of the week. It's nothing in itself; it just reminds you that the week has been going on too long. -Nicci French"; 42 | break; 43 | case DayOfWeek.Friday: 44 | msg = "My boss yelled at me yesterday 'It's the fifth time you've been late to work this week! Do you know what that means!?' I said, 'Probably that it's Friday?'. -Anonymous"; 45 | break; 46 | case DayOfWeek.Saturday: 47 | msg = "I didn't always have 14,000 people wanting to hang out with me on a Saturday night. -Taylor Swift"; 48 | break; 49 | case DayOfWeek.Sunday: 50 | msg = "I love to go to the zoo. But not on Sunday. I don't like to see the people making fun of the animals, when it should be the other way around. -Ernest Hemingway"; 51 | break; 52 | default: 53 | msg = "Somehow, today is a day, that doesn't exists"; 54 | break; 55 | } 56 | 57 | log.Info($"The following message will be returned: {0}"); 58 | 59 | return req.CreateResponse(HttpStatusCode.OK, msg); 60 | } 61 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/TSTableView/README.md: -------------------------------------------------------------------------------- 1 | # TSTableView by [Tacticsoft](http://www.tacticsoft.net)# 2 | 3 | TSTableView is a plugin for Unity 4.6's new UI system that implements a Table with an API inspired by Apple's [UITableView](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/index.html) while obeying the standards set by Unity 4.6's GUI system. 4 | 5 | ### Introduction ### 6 | 7 | * Unity 4.6 introducted a new UI system, but it lacks a ready for use table component. 8 | * This implementation is built to support tables with a large number of rows, and makes use of lazy loading and object pooling to perform well. 9 | 10 | ### Features ### 11 | 12 | * Reusable (vertical) Table component, following MVC paradigm 13 | * No external dependencies, very small footprint 14 | * Can handle tables with large amounts of rows 15 | * Native iOS / Mac developers will feel at home 16 | 17 | ### Setting up ### 18 | 19 | * If you would like to get a standalone Unity project of this component, consider cloning [TSTableViewPackage](https://bitbucket.org/tacticsoft/tstableviewpackage) instead. Don't forget to update submodules for the code itself to be included. 20 | * This repository contains just the code assets, so you can submodule / clone it directly into a directory of choice in your unity Assets directory. 21 | * You can also [download the repository](https://bitbucket.org/tacticsoft/tstableview/downloads) and place the files in your project. 22 | * Open the Examples directory to see example uses of the component. 23 | 24 | ### Code Tutorial ### 25 | 26 | * The main component introduced is the *TableView* component. The rows inside the table view are created programmatically by the data source which creates generates *TableViewCells* when asked. 27 | * The intended usage of this component is to implement *ITableViewDataSource* with one behavior (the controller), and subclass *TableViewCell* (the view). It makes sense to create a prefab of the game object hierarchy containing the *TableViewCell* and instantiate that from the *GetCellForRowInTableView* call. Make sure to check for reusable cells before instantiating again. 28 | * The TableView component assumes a certain hierarchy structure, see the *TableView Template* prefab for details. 29 | * *TableView* should be placed later than "Default" in Script Execution Order 30 | 31 | ### Missing features ### 32 | 33 | * Currently only vertical tables are supported, with one item per row 34 | * Performance can be better, but is already good enough for thousands of rows. 35 | * The VerticalLayoutGroup's spacing property can't change during runtime and must be smaller than the row height 36 | 37 | ### Contribution guidelines ### 38 | 39 | * Create pull requests! 40 | 41 | ### Who do I talk to? ### 42 | 43 | * Email [tech@tacticsoft.net](mailto:tech@tacticsoft.net) with comments, requests and suggestions 44 | * [@noamgat](http://www.twitter.com/noamgat) -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Sprites/Facebook.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c678e1dff2bdf44a085015ae095fab43 3 | timeCreated: 1507888815 4 | licenseType: Pro 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 0 11 | sRGBTexture: 1 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapsPreserveCoverage: 0 16 | alphaTestReferenceValue: 0.5 17 | mipMapFadeDistanceStart: 1 18 | mipMapFadeDistanceEnd: 3 19 | bumpmap: 20 | convertToNormalMap: 0 21 | externalNormalMap: 0 22 | heightScale: 0.25 23 | normalMapFilter: 0 24 | isReadable: 0 25 | grayScaleToAlpha: 0 26 | generateCubemap: 6 27 | cubemapConvolution: 0 28 | seamlessCubemap: 0 29 | textureFormat: 1 30 | maxTextureSize: 2048 31 | textureSettings: 32 | serializedVersion: 2 33 | filterMode: -1 34 | aniso: -1 35 | mipBias: -1 36 | wrapU: 1 37 | wrapV: -1 38 | wrapW: -1 39 | nPOTScale: 0 40 | lightmap: 0 41 | compressionQuality: 50 42 | spriteMode: 1 43 | spriteExtrude: 1 44 | spriteMeshType: 1 45 | alignment: 0 46 | spritePivot: {x: 0.5, y: 0.5} 47 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 48 | spritePixelsToUnits: 100 49 | alphaUsage: 1 50 | alphaIsTransparency: 1 51 | spriteTessellationDetail: -1 52 | textureType: 8 53 | textureShape: 1 54 | maxTextureSizeSet: 0 55 | compressionQualitySet: 0 56 | textureFormatSet: 0 57 | platformSettings: 58 | - buildTarget: DefaultTexturePlatform 59 | maxTextureSize: 2048 60 | textureFormat: -1 61 | textureCompression: 1 62 | compressionQuality: 50 63 | crunchedCompression: 0 64 | allowsAlphaSplitting: 0 65 | overridden: 0 66 | - buildTarget: Standalone 67 | maxTextureSize: 2048 68 | textureFormat: -1 69 | textureCompression: 1 70 | compressionQuality: 50 71 | crunchedCompression: 0 72 | allowsAlphaSplitting: 0 73 | overridden: 0 74 | - buildTarget: iPhone 75 | maxTextureSize: 2048 76 | textureFormat: -1 77 | textureCompression: 1 78 | compressionQuality: 50 79 | crunchedCompression: 0 80 | allowsAlphaSplitting: 0 81 | overridden: 0 82 | - buildTarget: tvOS 83 | maxTextureSize: 2048 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | - buildTarget: Android 91 | maxTextureSize: 2048 92 | textureFormat: -1 93 | textureCompression: 1 94 | compressionQuality: 50 95 | crunchedCompression: 0 96 | allowsAlphaSplitting: 0 97 | overridden: 0 98 | spriteSheet: 99 | serializedVersion: 2 100 | sprites: [] 101 | outline: [] 102 | physicsShape: [] 103 | spritePackingTag: 104 | userData: 105 | assetBundleName: 106 | assetBundleVariant: 107 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Sprites/GooglePlus.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f6b508383a0514df9a2b0c6a040c76af 3 | timeCreated: 1507888815 4 | licenseType: Pro 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 0 11 | sRGBTexture: 1 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapsPreserveCoverage: 0 16 | alphaTestReferenceValue: 0.5 17 | mipMapFadeDistanceStart: 1 18 | mipMapFadeDistanceEnd: 3 19 | bumpmap: 20 | convertToNormalMap: 0 21 | externalNormalMap: 0 22 | heightScale: 0.25 23 | normalMapFilter: 0 24 | isReadable: 0 25 | grayScaleToAlpha: 0 26 | generateCubemap: 6 27 | cubemapConvolution: 0 28 | seamlessCubemap: 0 29 | textureFormat: 1 30 | maxTextureSize: 2048 31 | textureSettings: 32 | serializedVersion: 2 33 | filterMode: -1 34 | aniso: -1 35 | mipBias: -1 36 | wrapU: 1 37 | wrapV: -1 38 | wrapW: -1 39 | nPOTScale: 0 40 | lightmap: 0 41 | compressionQuality: 50 42 | spriteMode: 1 43 | spriteExtrude: 1 44 | spriteMeshType: 1 45 | alignment: 0 46 | spritePivot: {x: 0.5, y: 0.5} 47 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 48 | spritePixelsToUnits: 100 49 | alphaUsage: 1 50 | alphaIsTransparency: 1 51 | spriteTessellationDetail: -1 52 | textureType: 8 53 | textureShape: 1 54 | maxTextureSizeSet: 0 55 | compressionQualitySet: 0 56 | textureFormatSet: 0 57 | platformSettings: 58 | - buildTarget: DefaultTexturePlatform 59 | maxTextureSize: 2048 60 | textureFormat: -1 61 | textureCompression: 1 62 | compressionQuality: 50 63 | crunchedCompression: 0 64 | allowsAlphaSplitting: 0 65 | overridden: 0 66 | - buildTarget: Standalone 67 | maxTextureSize: 2048 68 | textureFormat: -1 69 | textureCompression: 1 70 | compressionQuality: 50 71 | crunchedCompression: 0 72 | allowsAlphaSplitting: 0 73 | overridden: 0 74 | - buildTarget: iPhone 75 | maxTextureSize: 2048 76 | textureFormat: -1 77 | textureCompression: 1 78 | compressionQuality: 50 79 | crunchedCompression: 0 80 | allowsAlphaSplitting: 0 81 | overridden: 0 82 | - buildTarget: tvOS 83 | maxTextureSize: 2048 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | - buildTarget: Android 91 | maxTextureSize: 2048 92 | textureFormat: -1 93 | textureCompression: 1 94 | compressionQuality: 50 95 | crunchedCompression: 0 96 | allowsAlphaSplitting: 0 97 | overridden: 0 98 | spriteSheet: 99 | serializedVersion: 2 100 | sprites: [] 101 | outline: [] 102 | physicsShape: [] 103 | spritePackingTag: 104 | userData: 105 | assetBundleName: 106 | assetBundleVariant: 107 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Sprites/Twitter.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 52ac4a475acfd461d9e2818a03f75d84 3 | timeCreated: 1507888815 4 | licenseType: Pro 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 0 11 | sRGBTexture: 1 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapsPreserveCoverage: 0 16 | alphaTestReferenceValue: 0.5 17 | mipMapFadeDistanceStart: 1 18 | mipMapFadeDistanceEnd: 3 19 | bumpmap: 20 | convertToNormalMap: 0 21 | externalNormalMap: 0 22 | heightScale: 0.25 23 | normalMapFilter: 0 24 | isReadable: 0 25 | grayScaleToAlpha: 0 26 | generateCubemap: 6 27 | cubemapConvolution: 0 28 | seamlessCubemap: 0 29 | textureFormat: 1 30 | maxTextureSize: 2048 31 | textureSettings: 32 | serializedVersion: 2 33 | filterMode: -1 34 | aniso: -1 35 | mipBias: -1 36 | wrapU: 1 37 | wrapV: -1 38 | wrapW: -1 39 | nPOTScale: 0 40 | lightmap: 0 41 | compressionQuality: 50 42 | spriteMode: 1 43 | spriteExtrude: 1 44 | spriteMeshType: 1 45 | alignment: 0 46 | spritePivot: {x: 0.5, y: 0.5} 47 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 48 | spritePixelsToUnits: 100 49 | alphaUsage: 1 50 | alphaIsTransparency: 1 51 | spriteTessellationDetail: -1 52 | textureType: 8 53 | textureShape: 1 54 | maxTextureSizeSet: 0 55 | compressionQualitySet: 0 56 | textureFormatSet: 0 57 | platformSettings: 58 | - buildTarget: DefaultTexturePlatform 59 | maxTextureSize: 2048 60 | textureFormat: -1 61 | textureCompression: 1 62 | compressionQuality: 50 63 | crunchedCompression: 0 64 | allowsAlphaSplitting: 0 65 | overridden: 0 66 | - buildTarget: Standalone 67 | maxTextureSize: 2048 68 | textureFormat: -1 69 | textureCompression: 1 70 | compressionQuality: 50 71 | crunchedCompression: 0 72 | allowsAlphaSplitting: 0 73 | overridden: 0 74 | - buildTarget: iPhone 75 | maxTextureSize: 2048 76 | textureFormat: -1 77 | textureCompression: 1 78 | compressionQuality: 50 79 | crunchedCompression: 0 80 | allowsAlphaSplitting: 0 81 | overridden: 0 82 | - buildTarget: tvOS 83 | maxTextureSize: 2048 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | - buildTarget: Android 91 | maxTextureSize: 2048 92 | textureFormat: -1 93 | textureCompression: 1 94 | compressionQuality: 50 95 | crunchedCompression: 0 96 | allowsAlphaSplitting: 0 97 | overridden: 0 98 | spriteSheet: 99 | serializedVersion: 2 100 | sprites: [] 101 | outline: [] 102 | physicsShape: [] 103 | spritePackingTag: 104 | userData: 105 | assetBundleName: 106 | assetBundleVariant: 107 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Sprites/MicrosoftAccount.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 301bbdcc47b7c42c7ad266385c27aa93 3 | timeCreated: 1507888815 4 | licenseType: Pro 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 0 11 | sRGBTexture: 1 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapsPreserveCoverage: 0 16 | alphaTestReferenceValue: 0.5 17 | mipMapFadeDistanceStart: 1 18 | mipMapFadeDistanceEnd: 3 19 | bumpmap: 20 | convertToNormalMap: 0 21 | externalNormalMap: 0 22 | heightScale: 0.25 23 | normalMapFilter: 0 24 | isReadable: 0 25 | grayScaleToAlpha: 0 26 | generateCubemap: 6 27 | cubemapConvolution: 0 28 | seamlessCubemap: 0 29 | textureFormat: 1 30 | maxTextureSize: 2048 31 | textureSettings: 32 | serializedVersion: 2 33 | filterMode: -1 34 | aniso: -1 35 | mipBias: -1 36 | wrapU: 1 37 | wrapV: -1 38 | wrapW: -1 39 | nPOTScale: 0 40 | lightmap: 0 41 | compressionQuality: 50 42 | spriteMode: 1 43 | spriteExtrude: 1 44 | spriteMeshType: 1 45 | alignment: 0 46 | spritePivot: {x: 0.5, y: 0.5} 47 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 48 | spritePixelsToUnits: 100 49 | alphaUsage: 1 50 | alphaIsTransparency: 1 51 | spriteTessellationDetail: -1 52 | textureType: 8 53 | textureShape: 1 54 | maxTextureSizeSet: 0 55 | compressionQualitySet: 0 56 | textureFormatSet: 0 57 | platformSettings: 58 | - buildTarget: DefaultTexturePlatform 59 | maxTextureSize: 2048 60 | textureFormat: -1 61 | textureCompression: 1 62 | compressionQuality: 50 63 | crunchedCompression: 0 64 | allowsAlphaSplitting: 0 65 | overridden: 0 66 | - buildTarget: Standalone 67 | maxTextureSize: 2048 68 | textureFormat: -1 69 | textureCompression: 1 70 | compressionQuality: 50 71 | crunchedCompression: 0 72 | allowsAlphaSplitting: 0 73 | overridden: 0 74 | - buildTarget: iPhone 75 | maxTextureSize: 2048 76 | textureFormat: -1 77 | textureCompression: 1 78 | compressionQuality: 50 79 | crunchedCompression: 0 80 | allowsAlphaSplitting: 0 81 | overridden: 0 82 | - buildTarget: tvOS 83 | maxTextureSize: 2048 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | - buildTarget: Android 91 | maxTextureSize: 2048 92 | textureFormat: -1 93 | textureCompression: 1 94 | compressionQuality: 50 95 | crunchedCompression: 0 96 | allowsAlphaSplitting: 0 97 | overridden: 0 98 | spriteSheet: 99 | serializedVersion: 2 100 | sprites: [] 101 | outline: [] 102 | physicsShape: [] 103 | spritePackingTag: 104 | userData: 105 | assetBundleName: 106 | assetBundleVariant: 107 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Message/MessageManager.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using RESTClient; 5 | using Azure.Functions; 6 | using System.Collections; 7 | using System.Collections.Generic; 8 | using UnityEngine; 9 | 10 | namespace Nether { 11 | public class MessageManager : MonoBehaviour { 12 | 13 | // Delegates 14 | public delegate void MessageSuccess(string message); 15 | public delegate void MessageFail(); 16 | public static event MessageSuccess OnMessageSuccess; 17 | public static event MessageFail OnMessageFail; 18 | 19 | [Header("Azure Functions")] 20 | [SerializeField] 21 | private string account; 22 | [SerializeField] 23 | private string key; 24 | 25 | [Space(10)] 26 | [SerializeField] 27 | private string messageFunction = "Message"; 28 | 29 | [Header("Unity UI")] 30 | [SerializeField] 31 | private Canvas canvas; 32 | 33 | [Header("Message View Prefab")] 34 | [SerializeField] 35 | private MessageView messageViewPrefab; 36 | private MessageView messageView; 37 | 38 | private AzureFunctionClient client; 39 | private AzureFunction messageService; 40 | 41 | private IEnumerator coroutine; 42 | 43 | private static string kTAG = "Nether"; 44 | 45 | // Use this for initialization 46 | void Start() { 47 | if (canvas == null) { 48 | Debug.unityLogger.LogError(kTAG, "Attach 'canvas' property to root Canvas game object in hierarchy."); 49 | return; 50 | } 51 | 52 | if (messageViewPrefab == null) { 53 | Debug.unityLogger.LogError(kTAG, "To use the message view the associated prefabs must be attached."); 54 | return; 55 | } 56 | 57 | client = AzureFunctionClient.Create(account); 58 | messageService = new AzureFunction(messageFunction, client, key); 59 | } 60 | 61 | // Update is called once per frame 62 | void Update() { 63 | 64 | } 65 | 66 | public void LoadMessage() { 67 | coroutine = messageService.Get(LoadMessageComplete); 68 | StartCoroutine(coroutine); 69 | } 70 | 71 | private void LoadMessageComplete(IRestResponse response) { 72 | if (response.IsError) { 73 | Debug.unityLogger.LogError(kTAG, "Error load message failed. " + response.ErrorMessage); 74 | OnMessageFail(); 75 | return; 76 | } 77 | // automatically open message view when loaded 78 | CreateMessageView(response.Content); 79 | OnMessageSuccess(response.Content); 80 | } 81 | 82 | #region Show/hide message view 83 | 84 | private void CreateMessageView(string message = "") { 85 | if (messageView == null) { 86 | messageView = Instantiate(messageViewPrefab, canvas.transform); 87 | } 88 | messageView.message.text = message; 89 | messageView.Open(); 90 | } 91 | 92 | #endregion 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RestClient/helpers/JsonHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #pragma warning disable 0649 // ignores warning: array "is never assigned to, and will always have its default value 'null'" 5 | using UnityEngine; 6 | using System; 7 | using System.Text.RegularExpressions; 8 | #if NETFX_CORE 9 | using Windows.Data.Json; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | #endif 13 | 14 | namespace RESTClient { 15 | /// 16 | /// Wrapper work-around for json array described on https://forum.unity3d.com/threads/how-to-load-an-array-with-jsonutility.375735/ 17 | /// 18 | [Serializable] 19 | internal class Wrapper { 20 | public T[] array; 21 | } 22 | 23 | public class JsonHelper { 24 | /// 25 | /// Work-around to parse json array 26 | /// 27 | public static T[] FromJsonArray(string json) { 28 | // Work-around for JsonUtility array serialization issues in Windows Store Apps. 29 | #if NETFX_CORE 30 | JsonArray jsonArray = new JsonArray(); 31 | if (JsonArray.TryParse(json, out jsonArray)) 32 | { 33 | return GetArray(jsonArray); 34 | } 35 | Debug.LogWarning("Failed to parse json array of type:" + typeof(T).ToString() ); 36 | return default(T[]); 37 | #endif 38 | string newJson = "{\"array\":" + json + "}"; 39 | Wrapper wrapper = new Wrapper(); 40 | try { 41 | wrapper = JsonUtility.FromJson>(newJson); 42 | } catch (Exception e) { 43 | Debug.LogWarning("Failed to parse json array of type:" + typeof(T).ToString() + " Exception message: " + e.Message); 44 | return default(T[]); 45 | } 46 | return wrapper.array; 47 | } 48 | 49 | #if NETFX_CORE 50 | private static T[] GetArray(JsonArray array) 51 | { 52 | List list = new List(); 53 | foreach (var x in array) 54 | { 55 | try 56 | { 57 | T item = JsonUtility.FromJson(x.ToString()); 58 | list.Add(item); 59 | } 60 | catch (Exception e) 61 | { 62 | Debug.LogWarning("Failed to parse json of type:" + typeof(T).ToString() + " Exception message: " + e.Message + " json:'" + x.ToString() + "'"); 63 | } 64 | } 65 | return list.ToArray(); 66 | } 67 | #endif 68 | 69 | /// 70 | /// Workaround to only exclude Data Model's read only system properties being returned as json object. Unfortunately there is no JsonUtil attribute to do this as [NonSerialized] will just ignore the properties completely (both in and out). 71 | /// 72 | public static string ToJsonExcludingSystemProperties(object obj) { 73 | string jsonString = JsonUtility.ToJson(obj); 74 | return Regex.Replace(jsonString, "(?i)(\\\"id\\\":\\\"\\\",)?(\\\"createdAt\\\":\\\"[0-9TZ:.-]*\\\",)?(\\\"updatedAt\\\":\\\"[0-9TZ:.-]*\\\",)?(\\\"version\\\":\\\"[A-Z0-9=]*\\\",)?(\\\"deleted\\\":(true|false),)?(\\\"ROW_NUMBER\\\":\\\"[0-9]*\\\",)?", ""); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "windows": { 4 | "command": "powershell", 5 | "args": [ 6 | "-NoProfile", 7 | "-ExecutionPolicy", 8 | "ByPass" 9 | ], 10 | "tasks": [ 11 | { 12 | "taskName": "build", 13 | "args": [ 14 | "${workspaceRoot}\\build.ps1", 15 | "-NoDotNetRestore" 16 | ], 17 | "suppressTaskName": true, 18 | "isBuildCommand": true, 19 | "problemMatcher": "$msCompile" 20 | }, 21 | { 22 | "taskName": "test", 23 | "args": [ 24 | "${workspaceRoot}\\run-unit-tests.ps1" 25 | ], 26 | "suppressTaskName": true, 27 | "isTestCommand": true, 28 | "problemMatcher": "$msCompile" 29 | }, 30 | { 31 | "taskName": "restore", 32 | "args": [ 33 | "dotnet", 34 | "restore" 35 | ], 36 | "suppressTaskName": true 37 | } 38 | ] 39 | }, 40 | "linux": { 41 | "command": "bash", 42 | "tasks": [ 43 | { 44 | "taskName": "build", 45 | "args": [ 46 | "${workspaceRoot}/build.sh", 47 | "--no--dot-net-restore" 48 | ], 49 | "suppressTaskName": true, 50 | "isBuildCommand": true, 51 | "problemMatcher": "$msCompile" 52 | }, 53 | { 54 | "taskName": "test", 55 | "args": [ 56 | "${workspaceRoot}/run-unit-tests.sh" 57 | ], 58 | "suppressTaskName": true, 59 | "isTestCommand": true, 60 | "problemMatcher": "$msCompile" 61 | }, 62 | { 63 | "taskName": "restore", 64 | "args": [ 65 | "dotnet", 66 | "restore" 67 | ] 68 | } 69 | ] 70 | }, 71 | "osx": { 72 | "command": "sh", 73 | "tasks": [ 74 | { 75 | "taskName": "build", 76 | "args": [ 77 | "${workspaceRoot}/build.sh", 78 | "--no-restore" 79 | ], 80 | "suppressTaskName": true, 81 | "isBuildCommand": true, 82 | "problemMatcher": "$msCompile" 83 | }, 84 | { 85 | "taskName": "test", 86 | "args": [ 87 | "${workspaceRoot}/run-unit-tests.sh" 88 | ], 89 | "suppressTaskName": true, 90 | "isTestCommand": true, 91 | "problemMatcher": "$msCompile" 92 | }, 93 | { 94 | "taskName": "restore", 95 | "args": [ 96 | "dotnet", 97 | "restore" 98 | ] 99 | } 100 | ] 101 | }, 102 | "isShellCommand": true 103 | } -------------------------------------------------------------------------------- /doc/deploy-scenario.md: -------------------------------------------------------------------------------- 1 | # Deploy a Nether Scenario 2 | 3 | Nether is a project composed of reusable set of building blocks, projects, services and best practices designed for Gaming workloads powered by Microsoft Azure. Many of those building blocks are captured as scenarios that can be solved by deploying a set of Azure Functions on top of your [Base Architecture](deploy-base-architecture.md). 4 | 5 | ## Prerequisite 6 | 7 | In order to follow along this instruction, you need to have completed the [deployment of the Base Architecture for a Serverless Nether Architecture](deploy-base-architecture.md). 8 | 9 | ## Non Functional Requirements 10 | 11 | Unless otherwise stated, all scenarios are implemented with the following requirements in mind 12 | 13 | * Keep scenario simple 14 | * Minimize the need of maintainence 15 | * Scale from low, to extreme usage 16 | * Keep cost to a minimum 17 | * Service should be implemented using C# Script in order for ease of understanding and modification 18 | 19 | ## Azure Functions 20 | 21 | Nether uses Azure Functions for a serverless implemenation of your game services. Functions allow you to respond to different triggers and execute custom logic. A function can be triggered by: HTTP Requests, messages on queues, blobs created, etc. and can be implemented using several different languages. Even if you could have chosen any language to implement your server side code, in Nether we've taken a decission to use C# as a programming language whenever fit. 22 | 23 | Functions can be created and added to your Function App from within the Azure Portal, from your favorite terminal (PowerShell, Bash, Command Line, etc.) or development tool and by many other ways. In Nether we've implemented a custom script that automatically allow you to pull down functions available on the Nether GitHub Repository. This script is automatically installed inside your Function App Account if you deploy the base architecture using the provided template. 24 | 25 | > Even if we do recommend you to play with the tools and the Azure Portal, the rest of this documentation will tell you how to deploy the required functions included in the implemented scenarios in Nether, using the custom deployment script. 26 | 27 | ## Creating a function 28 | 29 | Once the [templated deployment](deploy-base-architecture) has completed then you can deploy one or more of the built-in scenarios. You do that by using the build in developer experience, aka. Kudu, in your Azure Function App. 30 | 31 | ### Finding Kudu 32 | In the outputs for the template deployment there is a `KuduUri` value that will be something like `yourapp.scm.azurewebsites.net`, and you can browse to that. 33 | 34 | ![template output](images/template-outputs.png) 35 | 36 | Alternatively, you can navigate to the Function App in the Azure Portal, click on "Platform Features" and then choose "Advanced Tools (Kudu)" as shown below: 37 | 38 | ![advanced tools - kudu](images/advanced-tools-kudu.png) 39 | 40 | #### Deploying a template 41 | 42 | In Kudu, select "PowerShell" from the "Debug console" menu: 43 | 44 | ![debug console - powershell](images/debug-console-powershell.png) 45 | 46 | 47 | In the PowerShell console, navigate to `site\wwwroot` (either by clicking the hyperlinked directories, or by typing `cd site\wwwroot`) 48 | 49 | At this point you should see `deploy.ps1` listed. This is the script that allows you to easily deploy scenarios. 50 | 51 | To deploy a scenario, run `./deploy.ps1 -Group -Scenario ` 52 | 53 | E.g `./deploy.ps1 -Group leaderboards -Scenario top-n` 54 | 55 | Current supported combinations for Group and Scenario are: 56 | 57 | |Group|Scenario|Description| 58 | |-|-|-| 59 | |leaderboards|top-n|functions to capture scores and show a top-n (e.g. top 10) leaderboard| 60 | 61 | 62 | After running the `deploy.ps1` script you should see new folders that have been created: 63 | 64 | ![kudu scenario folders](images/kudu-scenario-folders.png) 65 | 66 | And navigating back to the Azure Functions blade in the [Azure Portal](https://portal.azure.com) you will see the newly created functions: 67 | 68 | ![new functions](images/new-functions.png) 69 | 70 | Unless the scenario description tells you otherwise, you should now be able to test the deployed scenario. -------------------------------------------------------------------------------- /doc/deploy-base-architecture.md: -------------------------------------------------------------------------------- 1 | # Deploy the Base Architecture 2 | 3 | Nether is a project composed of reusable set of building blocks, projects, services and best practices designed for Gaming workloads powered by Microsoft Azure. Some of these scenarios uses an architecture style that is known as a Serverless Architecture. 4 | 5 | > "Serverless architectures refer to applications that significantly depend on third-party services" -Martin Fowler 6 | 7 | In other words, Serverless Architecture is a Software Architecture where you don't need to care about individual servers, but rather rely on platform services to provide you with the features you need. Microsoft Azure provides a plethora of such services in many different areas such as: custom code, databases, storage, AI, Connected Everything (IoT), analytics, etc. Nether is not the place to describe them all but different scenarios will use a few of those services. Please head over to [http://azure.com](http://azure.com) for more information of all services available. 8 | 9 | ## Prerequisite 10 | 11 | In order to deploy the base architecture you need to have a valid Azure Subscription. Head over to [http://azure.com](http://azure.com) to sign up for a free trial if you don't already have an account. 12 | 13 | ## The base architecture 14 | 15 | Unless otherwise stated, all scenarios that uses the serverless approach in Nether use the same base architecture. A very simple architecture, but still scalable. 16 | 17 | ![Architecture Diagram](images/base-architecture.png "Base Architecture") 18 | 19 | * [Azure Functions](https://azure.microsoft.com/en-us/services/functions/) 20 | * [Azure Cosmos DB](https://azure.microsoft.com/en-us/services/cosmos-db/) 21 | 22 | This architecture works well in many cases, both for small scale workloads and for big workloads since both Azure Functions and Azure Cosmos DB are cloud services designed with scale in mind. 23 | 24 | ## Deploying the base architecture to your Azure Subscription 25 | 26 | In order to get started and deploy the different scenarios, you first need to deploy the base architecture to your Azure Subscription. 27 | 28 | To get you up and running fast we have described the required services in a JSON-template format, quite often referred to as an Azure Resource Manager Template or ARM Template, that you can use to deploy the required services. 29 | 30 | > There is nothing that hinders you from deploying the base architecture manually using the Azure Portal, the Azure PowerShell CmdLets or the Cross Platform Azure CLI. This template will just automate the setup for you. 31 | 32 | During the deployment you'll need to provide an answer to the following parameters. 33 | 34 | Parameter | Description | Example Values 35 | --------------------|-------------------------------|-------------------- 36 | Subscription | The Azure Subscription you want to deploy to. Often you will not have more than one option here. | MySubscription 37 | Resource group | A resource group keeps related resources together. | Leaderboard 38 | Location | Defines where in the world you want your service to be deployed. | North Europe 39 | Function App Name | A globally unique name that will identify your Function App in Azure. Pick a name that identifies your solution. | nether 40 | Cosmos DB Account Name | A globally unique name that will identify your Cosmos DB Account in Azure. Pick a name that identifies your solution. | netherdb 41 | 42 | Click the below button to start the deployment. 43 | 44 | > WARNING! Due to a deployment feature that we are using to make sure individual scenarios are easy to download and install in your architecture, every deployment will start from scratch: DO NOT DEPLOY TWICE USING THE SAME PARAMETERS, SINCE THAT WILL OVERRIDE ANY IMPLEMENTED SCENARIOS/FUNCTIONS 45 | 46 | (Ctrl + Click will open the portal with the deployment in a separate tab in most browsers, hence allow you to keep this documentation available and ready to use) 47 | 48 | 49 | 50 | Wait for the deployment to finish before continuing. 51 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/leaderboard/run.csx: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Configuration; 5 | using System.Linq; 6 | using System.Net; 7 | using Microsoft.Azure.Documents; 8 | using Microsoft.Azure.Documents.Client; 9 | using Newtonsoft.Json; 10 | 11 | // Read application settings 12 | private static string db = ConfigurationManager.AppSettings["COSMOSDB_DBNAME"]; 13 | private static string endpoint = ConfigurationManager.AppSettings["COSMOSDB_ENDPOINT"]; 14 | private static string key = ConfigurationManager.AppSettings["COSMOSDB_PRIMARY_MASTER_KEY"]; 15 | private static string baseArchitectureVersion = ConfigurationManager.AppSettings["BASE_ARCHITECTURE_VERSION"]; 16 | private const string requiredBaseArchitectureVersion = "1.1"; 17 | 18 | private const string collection = "scores"; 19 | private const int lengthOfLeaderboard = 10; 20 | private static bool runOnce = true; 21 | private static DocumentClient client; 22 | 23 | public static async Task Run(HttpRequestMessage req, TraceWriter log) 24 | { 25 | // Run initialization only once. 26 | // Remarks: This initialization will run once on every instance and on every recompile of this function 27 | if (runOnce) 28 | { 29 | log.Info("Running initialization"); 30 | 31 | if (string.IsNullOrWhiteSpace(baseArchitectureVersion) || 32 | !baseArchitectureVersion.StartsWith(requiredBaseArchitectureVersion)) log.Error($"The base architecture version doesn't match the expected version {requiredBaseArchitectureVersion}"); 33 | 34 | // Check required application settings 35 | if (string.IsNullOrWhiteSpace(db)) log.Error("COSMOSDB_DBNAME settings wasn't provided"); 36 | if (string.IsNullOrWhiteSpace(endpoint)) log.Error("COSMOSDB_ENDPOINT settings wasn't provided"); 37 | if (string.IsNullOrWhiteSpace(key)) log.Error("COSMOSDB_PRIMARY_MASTER_KEY settings wasn't provided"); 38 | 39 | // Create Cosmos DB Client from settings 40 | client = new DocumentClient(new Uri(endpoint), key); 41 | 42 | // Create Database and Collection in Cosmos DB Account if they don't exist 43 | await client.CreateDatabaseIfNotExistsAsync(new Database { Id = db }); 44 | await client.CreateDocumentCollectionIfNotExistsAsync( 45 | UriFactory.CreateDatabaseUri(db), 46 | new DocumentCollection { Id = collection }); 47 | 48 | runOnce = false; 49 | 50 | log.Info("Initialization done!"); 51 | } 52 | 53 | try 54 | { 55 | var leaderboard = client.CreateDocumentQuery( 56 | UriFactory.CreateDocumentCollectionUri(db, collection), new FeedOptions { EnableCrossPartitionQuery = true }); 57 | 58 | var query = 59 | (from s in leaderboard 60 | orderby s.Score descending 61 | select new LeaderboardItem {Player = s.Player, Score = s.Score}).Take(lengthOfLeaderboard); 62 | 63 | var leaders = query.ToList(); 64 | 65 | int rank = 1; 66 | for (int i=0; i < leaders.Count; i++) 67 | { 68 | // Update rank to i + 1 if score is not the same as the last player's score 69 | // i.e. two or more players with the same score should have the same rank 70 | if (i > 0 && leaders[i-1].Score != leaders[i].Score) 71 | rank = i + 1; 72 | 73 | leaders[i].Rank = rank; 74 | } 75 | 76 | return req.CreateResponse(HttpStatusCode.OK, leaders); 77 | 78 | } 79 | catch (DocumentClientException ex) 80 | { 81 | log.Info(ex.ToString()); 82 | 83 | if (ex.StatusCode == HttpStatusCode.NotFound) 84 | return req.CreateResponse(HttpStatusCode.BadRequest, "This user does not exist in the database."); 85 | 86 | return req.CreateResponse(HttpStatusCode.BadRequest, $"An unknown error has occured. Message: {ex.Message}"); 87 | } 88 | } 89 | 90 | 91 | public class ScoreItem 92 | { 93 | [JsonProperty(PropertyName = "id")] 94 | public string Id { get; set;} 95 | [JsonProperty(PropertyName = "leaderboard")] 96 | public string Leaderboard { get; set;} 97 | [JsonProperty(PropertyName = "player")] 98 | public string Player { get; set;} 99 | [JsonProperty(PropertyName = "playerId")] 100 | public string PlayerId { get; set;} 101 | [JsonProperty(PropertyName = "score")] 102 | public double Score { get; set;} 103 | } 104 | 105 | public class LeaderboardItem 106 | { 107 | [JsonProperty(PropertyName = "rank")] 108 | public int Rank { get; set; } 109 | [JsonProperty(PropertyName = "player")] 110 | public string Player { get; set; } 111 | [JsonProperty(PropertyName = "score")] 112 | public double Score { get; set; } 113 | } 114 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/top-n/score/run.csx: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Net; 5 | using Microsoft.Azure.Documents; 6 | using Microsoft.Azure.Documents.Client; 7 | using Newtonsoft.Json; 8 | using System.Configuration; 9 | 10 | // Read application settings 11 | private static string db = ConfigurationManager.AppSettings["COSMOSDB_DBNAME"]; 12 | private static string endpoint = ConfigurationManager.AppSettings["COSMOSDB_ENDPOINT"]; 13 | private static string key = ConfigurationManager.AppSettings["COSMOSDB_PRIMARY_MASTER_KEY"]; 14 | private static string baseArchitectureVersion = ConfigurationManager.AppSettings["BASE_ARCHITECTURE_VERSION"]; 15 | private const string requiredBaseArchitectureVersion = "1.1"; 16 | 17 | private const string collection = "scores"; 18 | private static bool runOnce = true; 19 | private static DocumentClient client; 20 | 21 | public static async Task Run(HttpRequestMessage req, TraceWriter log) 22 | { 23 | // Run initialization only once. 24 | // Remarks: This initialization will run once on every instance and on every recompile of this function 25 | if (runOnce) 26 | { 27 | log.Info("Running initialization"); 28 | 29 | if (string.IsNullOrWhiteSpace(baseArchitectureVersion) || 30 | !baseArchitectureVersion.StartsWith(requiredBaseArchitectureVersion)) log.Error($"The base architecture version doesn't match the expected version {requiredBaseArchitectureVersion}"); 31 | 32 | // Check required application settings 33 | if (string.IsNullOrWhiteSpace(db)) log.Error("COSMOSDB_DBNAME settings wasn't provided"); 34 | if (string.IsNullOrWhiteSpace(endpoint)) log.Error("COSMOSDB_ENDPOINT settings wasn't provided"); 35 | if (string.IsNullOrWhiteSpace(key)) log.Error("COSMOSDB_PRIMARY_MASTER_KEY settings wasn't provided"); 36 | 37 | // Create Cosmos DB Client from settings 38 | client = new DocumentClient(new Uri(endpoint), key); 39 | 40 | // Create Database and Collection in Cosmos DB Account if they don't exist 41 | await client.CreateDatabaseIfNotExistsAsync(new Database { Id = db }); 42 | await client.CreateDocumentCollectionIfNotExistsAsync( 43 | UriFactory.CreateDatabaseUri(db), 44 | new DocumentCollection { Id = collection }); 45 | 46 | runOnce = false; 47 | 48 | log.Info("Initialization done!"); 49 | } 50 | 51 | dynamic data = await req.Content.ReadAsAsync(); 52 | string id = data?.playerId; 53 | string player = data?.player; 54 | 55 | if (string.IsNullOrEmpty(id) || data?.score == null || string.IsNullOrEmpty(player)) 56 | return req.CreateResponse(HttpStatusCode.BadRequest, "Please pass an playerId, player(name) and score in the request body"); 57 | 58 | var postedScore = new ScoreItem(); 59 | postedScore.PlayerId = data?.playerId; 60 | postedScore.Player = data?.player; 61 | postedScore.Score = data?.score; 62 | 63 | try 64 | { 65 | var scoreItems = client.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(db, collection), new FeedOptions { EnableCrossPartitionQuery = true }); 66 | var existingPlayer = new ScoreItem(); 67 | var query = 68 | from s in scoreItems 69 | where s.PlayerId == postedScore.PlayerId 70 | select s; 71 | 72 | var result = query.ToList(); 73 | if (result.Count()>1) 74 | existingPlayer = query.ToList().First(); 75 | 76 | if (string.IsNullOrEmpty(existingPlayer.PlayerId)) 77 | { 78 | await client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(db, collection), postedScore); 79 | return req.CreateResponse(HttpStatusCode.OK, $"The following user with score data was created successfully: id:{postedScore.PlayerId}, Name:{postedScore.Player}, Score:{postedScore.Score.ToString()}"); 80 | } 81 | else 82 | { 83 | postedScore.Id = existingPlayer.Id; 84 | if (postedScore.Score>existingPlayer.Score) 85 | { 86 | existingPlayer.Score = postedScore.Score; 87 | await client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(db, collection, existingPlayer.Id), postedScore); 88 | return req.CreateResponse(HttpStatusCode.OK, $"The score for user {existingPlayer.PlayerId} has been updated to {postedScore.Score}"); 89 | } 90 | else 91 | { 92 | return req.CreateResponse(HttpStatusCode.OK, $"The score for user {existingPlayer.PlayerId} is not higher than existing {postedScore.Score}"); 93 | } 94 | }; 95 | } 96 | catch (DocumentClientException) 97 | { 98 | return req.CreateResponse(HttpStatusCode.BadRequest, "Please pass an playerId, player(name) and score in the request body"); 99 | } 100 | } 101 | 102 | public class ScoreItem 103 | { 104 | [JsonProperty(PropertyName = "id")] 105 | public string Id { get; set;} 106 | [JsonProperty(PropertyName = "player")] 107 | public string Player { get; set;} 108 | [JsonProperty(PropertyName = "playerId")] 109 | public string PlayerId { get; set;} 110 | [JsonProperty(PropertyName = "score")] 111 | public double Score { get; set;} 112 | } 113 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | *.VC.db 83 | *.VC.VC.opendb 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | # TODO: Comment the next line if you want to checkin your web deploy settings 143 | # but database connection strings (with potential passwords) will be unencrypted 144 | *.pubxml 145 | *.publishproj 146 | 147 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 148 | # checkin your Azure Web App publish settings, but sensitive information contained 149 | # in these scripts will be unencrypted 150 | PublishScripts/ 151 | 152 | # NuGet Packages 153 | *.nupkg 154 | # The packages folder can be ignored because of Package Restore 155 | **/packages/* 156 | # except build/, which is used as an MSBuild target. 157 | !**/packages/build/ 158 | # Uncomment if necessary however generally it will be regenerated when needed 159 | #!**/packages/repositories.config 160 | # NuGet v3's project.json files produces more ignoreable files 161 | *.nuget.props 162 | *.nuget.targets 163 | 164 | # Microsoft Azure Build Output 165 | csx/ 166 | *.build.csdef 167 | 168 | # Microsoft Azure Emulator 169 | ecf/ 170 | rcf/ 171 | 172 | # Windows Store app package directories and files 173 | AppPackages/ 174 | BundleArtifacts/ 175 | Package.StoreAssociation.xml 176 | _pkginfo.txt 177 | 178 | # Visual Studio cache files 179 | # files ending in .cache can be ignored 180 | *.[Cc]ache 181 | # but keep track of directories ending in .cache 182 | !*.[Cc]ache/ 183 | 184 | # Others 185 | ClientBin/ 186 | ~$* 187 | *~ 188 | *.dbmdl 189 | *.dbproj.schemaview 190 | *.jfm 191 | .jfm 192 | *.pfx 193 | *.publishsettings 194 | node_modules/ 195 | bower_components/ 196 | orleans.codegen.cs 197 | 198 | 199 | # Since there are multiple workflows, uncomment next line to ignore bower_components 200 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 201 | #bower_components/ 202 | 203 | # RIA/Silverlight projects 204 | Generated_Code/ 205 | 206 | # Backup & report files from converting an old project file 207 | # to a newer Visual Studio version. Backup files are not needed, 208 | # because we have git ;-) 209 | _UpgradeReport_Files/ 210 | Backup*/ 211 | UpgradeLog*.XML 212 | UpgradeLog*.htm 213 | 214 | # SQL Server files 215 | *.mdf 216 | *.ldf 217 | 218 | # Business Intelligence projects 219 | *.rdl.data 220 | *.bim.layout 221 | *.bim_*.settings 222 | 223 | # Microsoft Fakes 224 | FakesAssemblies/ 225 | 226 | # GhostDoc plugin setting file 227 | *.GhostDoc.xml 228 | 229 | # Node.js Tools for Visual Studio 230 | .ntvs_analysis.dat 231 | 232 | # Visual Studio 6 build log 233 | *.plg 234 | 235 | # Visual Studio 6 workspace options file 236 | *.opt 237 | 238 | # Visual Studio LightSwitch build output 239 | **/*.HTMLClient/GeneratedArtifacts 240 | **/*.DesktopClient/GeneratedArtifacts 241 | **/*.DesktopClient/ModelManifest.xml 242 | **/*.Server/GeneratedArtifacts 243 | **/*.Server/ModelManifest.xml 244 | _Pvt_Extensions 245 | 246 | # Paket dependency manager 247 | .paket/paket.exe 248 | paket-files/ 249 | 250 | # FAKE - F# Make 251 | .fake/ 252 | 253 | # JetBrains Rider 254 | .idea/ 255 | *.sln.iml 256 | 257 | # Visual Studio Code 258 | .vscode/* 259 | !.vscode/settings.json 260 | !.vscode/tasks.json 261 | !.vscode/launch.json 262 | 263 | # Unity UWP build 264 | UWP 265 | *.pfx.meta 266 | 267 | # OS X 268 | .DS_Store 269 | 270 | # Azure Resource Manager 271 | *.privateparams.json 272 | 273 | appsettings.json 274 | -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!47 &1 4 | QualitySettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 5 7 | m_CurrentQuality: 5 8 | m_QualitySettings: 9 | - serializedVersion: 2 10 | name: Very Low 11 | pixelLightCount: 0 12 | shadows: 0 13 | shadowResolution: 0 14 | shadowProjection: 1 15 | shadowCascades: 1 16 | shadowDistance: 15 17 | shadowNearPlaneOffset: 3 18 | shadowCascade2Split: 0.33333334 19 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 20 | shadowmaskMode: 0 21 | blendWeights: 1 22 | textureQuality: 1 23 | anisotropicTextures: 0 24 | antiAliasing: 0 25 | softParticles: 0 26 | softVegetation: 0 27 | realtimeReflectionProbes: 0 28 | billboardsFaceCameraPosition: 0 29 | vSyncCount: 0 30 | lodBias: 0.3 31 | maximumLODLevel: 0 32 | particleRaycastBudget: 4 33 | asyncUploadTimeSlice: 2 34 | asyncUploadBufferSize: 4 35 | resolutionScalingFixedDPIFactor: 1 36 | excludedTargetPlatforms: [] 37 | - serializedVersion: 2 38 | name: Low 39 | pixelLightCount: 0 40 | shadows: 0 41 | shadowResolution: 0 42 | shadowProjection: 1 43 | shadowCascades: 1 44 | shadowDistance: 20 45 | shadowNearPlaneOffset: 3 46 | shadowCascade2Split: 0.33333334 47 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 48 | shadowmaskMode: 0 49 | blendWeights: 2 50 | textureQuality: 0 51 | anisotropicTextures: 0 52 | antiAliasing: 0 53 | softParticles: 0 54 | softVegetation: 0 55 | realtimeReflectionProbes: 0 56 | billboardsFaceCameraPosition: 0 57 | vSyncCount: 0 58 | lodBias: 0.4 59 | maximumLODLevel: 0 60 | particleRaycastBudget: 16 61 | asyncUploadTimeSlice: 2 62 | asyncUploadBufferSize: 4 63 | resolutionScalingFixedDPIFactor: 1 64 | excludedTargetPlatforms: [] 65 | - serializedVersion: 2 66 | name: Medium 67 | pixelLightCount: 1 68 | shadows: 1 69 | shadowResolution: 0 70 | shadowProjection: 1 71 | shadowCascades: 1 72 | shadowDistance: 20 73 | shadowNearPlaneOffset: 3 74 | shadowCascade2Split: 0.33333334 75 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 76 | shadowmaskMode: 0 77 | blendWeights: 2 78 | textureQuality: 0 79 | anisotropicTextures: 1 80 | antiAliasing: 0 81 | softParticles: 0 82 | softVegetation: 0 83 | realtimeReflectionProbes: 0 84 | billboardsFaceCameraPosition: 0 85 | vSyncCount: 1 86 | lodBias: 0.7 87 | maximumLODLevel: 0 88 | particleRaycastBudget: 64 89 | asyncUploadTimeSlice: 2 90 | asyncUploadBufferSize: 4 91 | resolutionScalingFixedDPIFactor: 1 92 | excludedTargetPlatforms: [] 93 | - serializedVersion: 2 94 | name: High 95 | pixelLightCount: 2 96 | shadows: 2 97 | shadowResolution: 1 98 | shadowProjection: 1 99 | shadowCascades: 2 100 | shadowDistance: 40 101 | shadowNearPlaneOffset: 3 102 | shadowCascade2Split: 0.33333334 103 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 104 | shadowmaskMode: 1 105 | blendWeights: 2 106 | textureQuality: 0 107 | anisotropicTextures: 1 108 | antiAliasing: 0 109 | softParticles: 0 110 | softVegetation: 1 111 | realtimeReflectionProbes: 1 112 | billboardsFaceCameraPosition: 1 113 | vSyncCount: 1 114 | lodBias: 1 115 | maximumLODLevel: 0 116 | particleRaycastBudget: 256 117 | asyncUploadTimeSlice: 2 118 | asyncUploadBufferSize: 4 119 | resolutionScalingFixedDPIFactor: 1 120 | excludedTargetPlatforms: [] 121 | - serializedVersion: 2 122 | name: Very High 123 | pixelLightCount: 3 124 | shadows: 2 125 | shadowResolution: 2 126 | shadowProjection: 1 127 | shadowCascades: 2 128 | shadowDistance: 70 129 | shadowNearPlaneOffset: 3 130 | shadowCascade2Split: 0.33333334 131 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 132 | shadowmaskMode: 1 133 | blendWeights: 4 134 | textureQuality: 0 135 | anisotropicTextures: 2 136 | antiAliasing: 2 137 | softParticles: 1 138 | softVegetation: 1 139 | realtimeReflectionProbes: 1 140 | billboardsFaceCameraPosition: 1 141 | vSyncCount: 1 142 | lodBias: 1.5 143 | maximumLODLevel: 0 144 | particleRaycastBudget: 1024 145 | asyncUploadTimeSlice: 2 146 | asyncUploadBufferSize: 4 147 | resolutionScalingFixedDPIFactor: 1 148 | excludedTargetPlatforms: [] 149 | - serializedVersion: 2 150 | name: Ultra 151 | pixelLightCount: 4 152 | shadows: 2 153 | shadowResolution: 2 154 | shadowProjection: 1 155 | shadowCascades: 4 156 | shadowDistance: 150 157 | shadowNearPlaneOffset: 3 158 | shadowCascade2Split: 0.33333334 159 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 160 | shadowmaskMode: 1 161 | blendWeights: 4 162 | textureQuality: 0 163 | anisotropicTextures: 2 164 | antiAliasing: 2 165 | softParticles: 1 166 | softVegetation: 1 167 | realtimeReflectionProbes: 1 168 | billboardsFaceCameraPosition: 1 169 | vSyncCount: 1 170 | lodBias: 2 171 | maximumLODLevel: 0 172 | particleRaycastBudget: 4096 173 | asyncUploadTimeSlice: 2 174 | asyncUploadBufferSize: 4 175 | resolutionScalingFixedDPIFactor: 1 176 | excludedTargetPlatforms: [] 177 | m_PerPlatformDefaultQuality: 178 | Android: 2 179 | Nintendo 3DS: 5 180 | Nintendo Switch: 5 181 | PS4: 5 182 | PSM: 5 183 | PSP2: 2 184 | Samsung TV: 2 185 | Standalone: 5 186 | Tizen: 2 187 | Web: 5 188 | WebGL: 3 189 | WiiU: 5 190 | Windows Store Apps: 5 191 | XboxOne: 5 192 | iPhone: 2 193 | tvOS: 2 194 | -------------------------------------------------------------------------------- /src/cloud/functions/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "functionAppName": { 6 | "type": "string", 7 | "minLength": 1 8 | }, 9 | "cosmosDBAccountName": { 10 | "type": "string", 11 | "minLength": 1 12 | }, 13 | "webZipUri": { 14 | "type": "string", 15 | "defaultValue": "https://netherartifacts.blob.core.windows.net/deployment-artifacts/master/nether-master.zip" 16 | } 17 | }, 18 | "variables": { 19 | "appServicePlanName": "[concat(parameters('functionAppName'), 'plan')]", 20 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]", 21 | "storageAccountid": "[concat(resourceGroup().id,'/providers/','Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]" 22 | }, 23 | "resources": [ 24 | { 25 | "type": "Microsoft.Storage/storageAccounts", 26 | "apiVersion": "2017-06-01", 27 | "name": "[variables('storageAccountName')]", 28 | "tags": { 29 | "displayName": "StorageAccount" 30 | }, 31 | "location": "[resourceGroup().location]", 32 | "kind": "Storage", 33 | "sku": { 34 | "name": "Standard_LRS" 35 | } 36 | }, 37 | { 38 | "type": "Microsoft.DocumentDB/databaseAccounts", 39 | "apiVersion": "2015-04-08", 40 | "name": "[parameters('cosmosDBAccountName')]", 41 | "tags": { 42 | "displayName": "CosmosDB" 43 | }, 44 | "location": "[resourceGroup().location]", 45 | "properties": { 46 | "name": "[parameters('cosmosDBAccountName')]", 47 | "databaseAccountOfferType": "Standard", 48 | "consistencyPolicy": { 49 | "defaultConsistencyLevel": "Session" 50 | } 51 | } 52 | }, 53 | { 54 | "type": "Microsoft.Web/serverfarms", 55 | "apiVersion": "2016-09-01", 56 | "name": "[variables('appServicePlanName')]", 57 | "tags": { 58 | "displayName": "AppServicePlan" 59 | }, 60 | "location": "[resourceGroup().location]", 61 | "sku": { 62 | "name": "Y1", 63 | "tier": "Dynamic", 64 | "size": "Y1", 65 | "family": "Y", 66 | "capacity": 0 67 | }, 68 | "kind": "functionapp", 69 | "dependsOn": [], 70 | "properties": { 71 | "name": "[variables('appServicePlanName')]" 72 | } 73 | }, 74 | { 75 | "type": "Microsoft.Web/sites", 76 | "apiVersion": "2016-08-01", 77 | "name": "[parameters('functionAppName')]", 78 | "tags": { 79 | "displayName": "FunctionApp" 80 | }, 81 | "location": "[resourceGroup().location]", 82 | "kind": "functionapp", 83 | "dependsOn": [ 84 | "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]", 85 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", 86 | "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosDBAccountName'))]" 87 | ], 88 | "properties": { 89 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]", 90 | "siteConfig": { 91 | "appSettings": [ 92 | { 93 | "name": "AzureWebJobsDashboard", 94 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]" 95 | }, 96 | { 97 | "name": "AzureWebJobsStorage", 98 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]" 99 | }, 100 | { 101 | "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", 102 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]" 103 | }, 104 | { 105 | "name": "WEBSITE_CONTENTSHARE", 106 | "value": "[toLower(parameters('functionAppName'))]" 107 | }, 108 | { 109 | "name": "FUNCTIONS_EXTENSION_VERSION", 110 | "value": "~1" 111 | }, 112 | { 113 | "name": "WEBSITE_NODE_DEFAULT_VERSION", 114 | "value": "6.5.0" 115 | }, 116 | { 117 | "Name": "COSMOSDB_DBNAME", 118 | "Value": "nether" 119 | }, 120 | { 121 | "Name": "COSMOSDB_ENDPOINT", 122 | "Value": "[reference(concat('Microsoft.DocumentDB/databaseAccounts/', parameters('cosmosDBAccountName'))).documentEndpoint]" 123 | }, 124 | { 125 | "Name": "COSMOSDB_PRIMARY_MASTER_KEY", 126 | "Value": "[listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosDBAccountName')), '2015-04-08').primaryMasterKey]" 127 | }, 128 | { 129 | "Name": "BASE_ARCHITECTURE_VERSION", 130 | "Value": "1.1.0" 131 | } 132 | ] 133 | } 134 | }, 135 | "resources": [ 136 | { 137 | "type": "extensions", 138 | "name": "MSDeploy", 139 | "apiVersion": "2016-08-01", 140 | "location": "[resourceGroup().location]", 141 | "dependsOn": [ 142 | "[resourceId('Microsoft.Web/sites/', parameters('functionAppName'))]" 143 | ], 144 | "tags": { 145 | "displayName": "DeployTheZip" 146 | }, 147 | "properties": { 148 | "packageUri": "[parameters('webZipUri')]" 149 | } 150 | } 151 | ] 152 | } 153 | ], 154 | "outputs": { 155 | "functionAppUri": { 156 | "type": "string", 157 | "value": "[concat('http://',reference(resourceId('Microsoft.Web/sites', parameters('functionAppName'))).hostNames[0])]" 158 | }, 159 | "kuduUri": { 160 | "type": "string", 161 | "value": "[replace(concat('http://',reference(resourceId('Microsoft.Web/sites', parameters('functionAppName'))).hostNames[0]), '.azurewebsites.net', '.scm.azurewebsites.net')]" 162 | } 163 | } 164 | } -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/AzureAppServices/ZumoClient.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using RESTClient; 5 | using System; 6 | using System.Collections; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Text.RegularExpressions; 11 | using UnityEngine; 12 | using System.Net; 13 | using UnityEngine.Assertions; 14 | 15 | namespace Azure.AppServices { 16 | public abstract class ZumoClient : RestClient, IZumoClient { 17 | 18 | public AuthenticatedUser User { get; private set; } 19 | 20 | public ZumoClient(string url) : base(url) { 21 | } 22 | 23 | public static string AppUrl(string account) { 24 | return string.Format("https://{0}.azurewebsites.net", account); 25 | } 26 | 27 | /// 28 | /// Client-directed single sign on for Facebook (using access token) 29 | /// 30 | public IEnumerator LoginWithFacebook(string accessToken, Action> callback = null) { 31 | return Login(AuthenticationProvider.Facebook, accessToken, callback); 32 | } 33 | 34 | /// 35 | /// Client-directed single sign on for Twitter (using access token and access token secret) 36 | /// 37 | public IEnumerator LoginWithTwitter(string accessToken, string accessTokenSecret, Action> callback = null) { 38 | string url = AppServiceAuthenticationProviderUrl(AuthenticationProvider.Twitter); 39 | var request = new ZumoRequest(url, Method.POST, false); 40 | request.AddBodyAccessTokenSecret(accessToken, accessTokenSecret); 41 | yield return request.Request.Send(); 42 | LoggedIn(request, callback); 43 | } 44 | 45 | /// 46 | /// Client-directed single sign on for Google+ (using access token and id token) 47 | /// 48 | public IEnumerator LoginWithGoogle(string accessToken, string idToken, Action> callback = null) { 49 | string url = AppServiceAuthenticationProviderUrl(AuthenticationProvider.Google); 50 | var request = new ZumoRequest(url, Method.POST, false); 51 | request.AddBodyAccessTokenId(accessToken, idToken); 52 | yield return request.Request.Send(); 53 | LoggedIn(request, callback); 54 | } 55 | 56 | /// 57 | /// Client-directed single sign on for Microsoft Account (using access token) 58 | /// 59 | public IEnumerator LoginWithMicrosoftAccount(string accessToken, Action> callback = null) { 60 | return Login(AuthenticationProvider.MicrosoftAccount, accessToken, callback); 61 | } 62 | 63 | /// 64 | /// Client-directed single sign on for Azure Active Directory (using access token) 65 | /// 66 | public IEnumerator LoginWithAAD(string accessToken, Action> callback = null) { 67 | return Login(AuthenticationProvider.AAD, accessToken, callback); 68 | } 69 | 70 | private IEnumerator Login(AuthenticationProvider authenticationProvider, 71 | string accessToken, 72 | Action> callback = null) { 73 | string url = AppServiceAuthenticationProviderUrl(authenticationProvider); 74 | var request = new ZumoRequest(url, Method.POST, false); 75 | request.AddBodyAccessToken(accessToken); 76 | yield return request.Request.Send(); 77 | LoggedIn(request, callback); 78 | } 79 | 80 | public IEnumerator Logout(Action> callback = null) { 81 | if (User == null) { 82 | Debug.LogWarning("Error, requires user login."); 83 | yield break; 84 | } 85 | string url = string.Format("{0}/.auth/logout", Url); 86 | var request = new ZumoRequest(url, Method.POST, false, User); 87 | yield return request.Request.Send(); 88 | if (callback == null) { 89 | yield break; 90 | } 91 | HttpStatusCode statusCode = (HttpStatusCode)Enum.Parse(typeof(HttpStatusCode), request.Request.responseCode.ToString()); 92 | RestResponse response = new RestResponse(statusCode, request.Request.url, request.Request.downloadHandler.text); 93 | if (!statusCode.Equals(HttpStatusCode.OK)) { 94 | Debug.LogWarning("Error, logout request failed."); 95 | yield break; 96 | } 97 | // Detect result of logout webpage (using title tag to verify sign out success) with callback response 98 | var match = Regex.Match(request.Request.downloadHandler.text, @"(.+)<\/title>", RegexOptions.IgnoreCase); 99 | if (match.Groups.Count == 2 && !string.IsNullOrEmpty(match.Groups[1].Value)) { 100 | string title = match.Groups[1].Value; 101 | Assert.IsTrue(string.Equals(title, "You have been signed out")); 102 | response = new RestResponse<string>(statusCode, request.Request.url, title); 103 | } 104 | callback(response); 105 | User = null; 106 | request.Dispose(); 107 | } 108 | 109 | private string AppServiceAuthenticationProviderUrl(AuthenticationProvider authenticationProvider) { 110 | return string.Format("{0}/.auth/login/{1}", Url, authenticationProvider.ToString().ToLower()); 111 | } 112 | 113 | private void LoggedIn(ZumoRequest request, Action<IRestResponse<AuthenticatedUser>> callback = null) { 114 | string message = request.Request.downloadHandler.text; 115 | IRestResponse<AuthenticatedUser> response = request.ParseJson<AuthenticatedUser>(); 116 | if (!response.IsError) { 117 | User = response.Data; 118 | if (callback != null) { 119 | callback(response); 120 | } 121 | } else { 122 | Debug.LogWarning("Login error message:" + message); 123 | } 124 | request.Dispose(); 125 | } 126 | 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Scenes/Leaderboard Demo/LeaderboardDemoScript.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using UnityEngine; 8 | using UnityEngine.UI; 9 | using Azure.AppServices; 10 | using Azure.Functions; 11 | using RESTClient; 12 | using Tacticsoft; 13 | using Nether; 14 | 15 | namespace NetherDemo { 16 | public class LeaderboardDemoScript : MonoBehaviour { 17 | [Header("Unity UI")] 18 | [SerializeField] 19 | private GameObject loginUI; 20 | [SerializeField] 21 | private Button logoutButton; 22 | [Space(10)] 23 | [SerializeField] 24 | private InputField inputUserAccessToken; 25 | [SerializeField] 26 | private InputField inputUserSecret; 27 | [Space(10)] 28 | [SerializeField] 29 | private InputField inputPlayer; 30 | [SerializeField] 31 | private InputField inputScore; 32 | [SerializeField] 33 | [Space(10)] 34 | private Text outputText; 35 | 36 | [Header("Nether")] 37 | [SerializeField] 38 | private LeaderboardManager leaderboardManager; 39 | private AuthenticationProvider identityProvider = AuthenticationProvider.Facebook; // default to Facebook 40 | 41 | // Use this for initialization 42 | void Start() { 43 | if (leaderboardManager == null || 44 | inputPlayer == null || 45 | inputScore == null || 46 | inputUserAccessToken == null || 47 | inputUserSecret == null || 48 | outputText == null) { 49 | Debug.LogError("Unity is missing connections to game objects in hierarchy."); 50 | return; 51 | } 52 | } 53 | 54 | // Update is called once per frame 55 | void Update() { 56 | 57 | } 58 | 59 | #region Demo UI 60 | 61 | public void ChangeIdentityProvider(Dropdown dropdown) { 62 | if (dropdown == null) { 63 | Debug.LogWarning("Unity missing connection to dropdown element"); 64 | return; 65 | } 66 | identityProvider = (AuthenticationProvider)dropdown.value; 67 | if (identityProvider.Equals(AuthenticationProvider.Twitter) || identityProvider.Equals(AuthenticationProvider.Google)) { 68 | inputUserSecret.placeholder.GetComponent<Text>().text = 69 | identityProvider.Equals(AuthenticationProvider.Twitter) ? "Enter access token secret..." : "Enter id token..."; 70 | inputUserSecret.gameObject.SetActive(true); 71 | } else { 72 | inputUserSecret.gameObject.SetActive(false); 73 | } 74 | } 75 | 76 | public void ClickLogin() { 77 | string token = inputUserAccessToken.text; 78 | if (string.IsNullOrEmpty(token)) { 79 | outputText.text = "Please enter access token!"; 80 | return; 81 | } 82 | string secret = inputUserSecret.text; 83 | leaderboardManager.Login(identityProvider, token, secret); 84 | } 85 | 86 | public void ClickLogout() { 87 | leaderboardManager.Logout(); 88 | } 89 | 90 | public void ClickLeaderboard() { 91 | if (!leaderboardManager.IsLeaderboardOpen()) { 92 | outputText.text = "Loading..."; 93 | } else { 94 | outputText.text = ""; 95 | } 96 | leaderboardManager.ToggleLeaderboard(); 97 | } 98 | 99 | public void ClickSubmit() { 100 | if (string.IsNullOrEmpty(inputPlayer.text)) { 101 | outputText.text = "Please enter a player name!"; 102 | return; 103 | } 104 | if (string.IsNullOrEmpty(inputScore.text)) { 105 | outputText.text = "Please enter a score!"; 106 | return; 107 | } 108 | 109 | double score = 0; 110 | Double.TryParse(inputScore.text, out score); 111 | 112 | outputText.text = "Submitting..."; 113 | leaderboardManager.SubmitScore(inputPlayer.text, score); 114 | } 115 | 116 | private void ChangeLoginUI(bool isLoggedIn = false) { 117 | loginUI.SetActive(!isLoggedIn); 118 | logoutButton.gameObject.SetActive(isLoggedIn); 119 | } 120 | 121 | #endregion 122 | 123 | #region Event handlers (optional) 124 | 125 | void OnEnable() { 126 | LeaderboardManager.OnLoginSuccess += OnLoginSuccess; 127 | LeaderboardManager.OnLoginFail += OnLoginFail; 128 | LeaderboardManager.OnLogoutSuccess += OnLogoutSuccess; 129 | LeaderboardManager.OnLogoutFail += OnLogoutFail; 130 | LeaderboardManager.OnLoadLeaderboardSuccess += OnLoadLeaderboardSuccess; 131 | LeaderboardManager.OnLoadLeaderboardFail += OnLoadLeaderboardFail; 132 | LeaderboardManager.OnSubmitScoreSuccess += OnSubmitScoreSuccess; 133 | LeaderboardManager.OnSubmitScoreFail += OnSubmitScoreFail; 134 | } 135 | 136 | 137 | void OnDisable() { 138 | LeaderboardManager.OnLoginSuccess -= OnLoginSuccess; 139 | LeaderboardManager.OnLoginFail -= OnLoginFail; 140 | LeaderboardManager.OnLogoutSuccess -= OnLogoutSuccess; 141 | LeaderboardManager.OnLogoutFail -= OnLogoutFail; 142 | LeaderboardManager.OnLoadLeaderboardSuccess -= OnLoadLeaderboardSuccess; 143 | LeaderboardManager.OnLoadLeaderboardFail -= OnLoadLeaderboardFail; 144 | LeaderboardManager.OnSubmitScoreSuccess -= OnSubmitScoreSuccess; 145 | LeaderboardManager.OnSubmitScoreFail -= OnSubmitScoreFail; 146 | } 147 | 148 | private void OnLoginSuccess() { 149 | outputText.text = "Logged in!"; 150 | ChangeLoginUI(true); 151 | } 152 | 153 | private void OnLoginFail() { 154 | outputText.text = "Failed to login"; 155 | } 156 | 157 | private void OnLogoutSuccess() { 158 | outputText.text = "Logged out!"; 159 | ChangeLoginUI(false); 160 | } 161 | 162 | private void OnLogoutFail() { 163 | outputText.text = "Failed to logout"; 164 | } 165 | 166 | private void OnLoadLeaderboardSuccess(LeaderboardItem[] scores) { 167 | outputText.text = "Loaded " + scores.Length + " scores."; 168 | } 169 | 170 | private void OnLoadLeaderboardFail() { 171 | outputText.text = "Failed to load scores."; 172 | } 173 | 174 | private void OnSubmitScoreSuccess() { 175 | outputText.text = "Successfully submitted score."; 176 | } 177 | 178 | private void OnSubmitScoreFail() { 179 | outputText.text = "Failed to submit score."; 180 | } 181 | 182 | #endregion 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Dependencies/RestClient/http/RestRequest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using UnityEngine; 5 | using UnityEngine.Networking; 6 | using System; 7 | using System.Net; 8 | using System.Collections.Generic; 9 | using System.Text.RegularExpressions; 10 | using System.Text; 11 | 12 | namespace RESTClient { 13 | public class RestRequest : IDisposable { 14 | public UnityWebRequest Request { get; private set; } 15 | 16 | private QueryParams queryParams; 17 | 18 | public RestRequest(string url, Method method) { 19 | Request = new UnityWebRequest(url, method.ToString()); 20 | Request.downloadHandler = new DownloadHandlerBuffer(); 21 | } 22 | 23 | public void AddHeader(string key, string value) { 24 | Request.SetRequestHeader(key, value); 25 | } 26 | 27 | public void AddBody(byte[] bytes, string contentType) { 28 | if (Request.uploadHandler != null) { 29 | Debug.LogWarning("Request body can only be set once"); 30 | return; 31 | } 32 | Request.uploadHandler = new UploadHandlerRaw(bytes); 33 | Request.uploadHandler.contentType = contentType; 34 | } 35 | 36 | public virtual void AddBody<T>(T data, string contentType = "application/json; charset=utf-8") { 37 | string jsonString = JsonUtility.ToJson(data); 38 | byte[] bytes = Encoding.UTF8.GetBytes(jsonString); 39 | this.AddBody(bytes, contentType); 40 | } 41 | 42 | public virtual void AddQueryParam(string key, string value, bool shouldUpdateRequestUrl = false) { 43 | if (queryParams == null) { 44 | queryParams = new QueryParams(); 45 | } 46 | queryParams.AddParam(key, value); 47 | if (shouldUpdateRequestUrl) { 48 | UpdateRequestUrl(); 49 | } 50 | } 51 | 52 | public virtual void UpdateRequestUrl() { 53 | if (queryParams == null) { 54 | return; 55 | } 56 | var match = Regex.Match(Request.url, @"^(.+)(\\?)(.+)", RegexOptions.IgnoreCase); 57 | if (match.Groups.Count == 4 && match.Groups[0].Value.Length > 0) { 58 | string url = match.Groups[0].Value + queryParams.ToString(); 59 | Request.url = url; 60 | } 61 | } 62 | 63 | #region Response and json object parsing 64 | 65 | private RestResult<T> GetRestResult<T>() { 66 | HttpStatusCode statusCode = (HttpStatusCode)Enum.Parse(typeof(HttpStatusCode), Request.responseCode.ToString()); 67 | RestResult<T> result = new RestResult<T>(statusCode); 68 | 69 | if (result.IsError) { 70 | result.ErrorMessage = "Response failed with status: " + statusCode.ToString(); 71 | return result; 72 | } 73 | 74 | if (string.IsNullOrEmpty(Request.downloadHandler.text)) { 75 | result.IsError = true; 76 | result.ErrorMessage = "Response has empty body"; 77 | return result; 78 | } 79 | 80 | return result; 81 | } 82 | 83 | /// <summary> 84 | /// Shared method to return response result whether an object or array of objects 85 | /// </summary> 86 | private RestResult<T> TryParseJsonArray<T>() { 87 | RestResult<T> result = GetRestResult<T>(); 88 | // try parse an array of objects 89 | try { 90 | result.AnArrayOfObjects = JsonHelper.FromJsonArray<T>(Request.downloadHandler.text); 91 | } catch (Exception e) { 92 | result.IsError = true; 93 | result.ErrorMessage = "Failed to parse an array of objects of type: " + typeof(T).ToString() + " Exception message: " + e.Message; 94 | } 95 | return result; 96 | } 97 | 98 | private RestResult<T> TryParseJson<T>() { 99 | RestResult<T> result = GetRestResult<T>(); 100 | // try parse an object 101 | try { 102 | result.AnObject = JsonUtility.FromJson<T>(Request.downloadHandler.text); 103 | } catch (Exception e) { 104 | result.IsError = true; 105 | result.ErrorMessage = "Failed to parse object of type: " + typeof(T).ToString() + " Exception message: " + e.Message; 106 | } 107 | return result; 108 | } 109 | 110 | /// <summary> 111 | /// Parses object with T data = JsonUtil.FromJson<T>, then callback RestResponse<T> 112 | /// </summary> 113 | public IRestResponse<T> ParseJson<T>(Action<IRestResponse<T>> callback = null) { 114 | RestResult<T> result = TryParseJson<T>(); 115 | RestResponse<T> response; 116 | if (result.IsError) { 117 | Debug.LogWarning("Response error status:" + result.StatusCode + " code:" + Request.responseCode + " error:" + result.ErrorMessage + " Request url:" + Request.url); 118 | response = new RestResponse<T>(result.ErrorMessage, result.StatusCode, Request.url, Request.downloadHandler.text); 119 | } else { 120 | response = new RestResponse<T>(result.StatusCode, Request.url, Request.downloadHandler.text, result.AnObject); 121 | } 122 | if (callback != null){ 123 | callback(response); 124 | } 125 | this.Dispose(); 126 | return response; 127 | } 128 | 129 | /// <summary> 130 | /// Parses array of objects with T[] data = JsonHelper.GetJsonArray<T>, then callback RestResponse<T[]> 131 | /// </summary> 132 | public IRestResponse<T[]> ParseJsonArray<T>(Action<IRestResponse<T[]>> callback = null) { 133 | RestResult<T> result = TryParseJsonArray<T>(); 134 | RestResponse<T[]> response; 135 | if (result.IsError) { 136 | Debug.LogWarning("Response error status:" + result.StatusCode + " code:" + Request.responseCode + " error:" + result.ErrorMessage + " Request url:" + Request.url); 137 | response = new RestResponse<T[]>(result.ErrorMessage, result.StatusCode, Request.url, Request.downloadHandler.text); 138 | } else { 139 | response = new RestResponse<T[]>(result.StatusCode, Request.url, Request.downloadHandler.text, result.AnArrayOfObjects); 140 | } 141 | if (callback != null){ 142 | callback(response); 143 | } 144 | this.Dispose(); 145 | return response; 146 | } 147 | 148 | /// Just return as plain text 149 | public IRestResponse<T> GetText<T>(Action<IRestResponse<T>> callback = null) { 150 | RestResult<string> result = GetRestResult<string>(); 151 | RestResponse<T> response; 152 | if (result.IsError) { 153 | response = new RestResponse<T>(result.ErrorMessage, result.StatusCode, Request.url, Request.downloadHandler.text); 154 | } else { 155 | response = new RestResponse<T>(result.StatusCode, Request.url, Request.downloadHandler.text); 156 | } 157 | if (callback != null){ 158 | callback(response); 159 | } 160 | this.Dispose(); 161 | return response; 162 | } 163 | 164 | public void Dispose() { 165 | Request.Dispose(); // Request completed, clean-up resources 166 | } 167 | 168 | #endregion 169 | 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/Client/Unity/ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!13 &1 4 | InputManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Axes: 8 | - serializedVersion: 3 9 | m_Name: Horizontal 10 | descriptiveName: 11 | descriptiveNegativeName: 12 | negativeButton: left 13 | positiveButton: right 14 | altNegativeButton: a 15 | altPositiveButton: d 16 | gravity: 3 17 | dead: 0.001 18 | sensitivity: 3 19 | snap: 1 20 | invert: 0 21 | type: 0 22 | axis: 0 23 | joyNum: 0 24 | - serializedVersion: 3 25 | m_Name: Vertical 26 | descriptiveName: 27 | descriptiveNegativeName: 28 | negativeButton: down 29 | positiveButton: up 30 | altNegativeButton: s 31 | altPositiveButton: w 32 | gravity: 3 33 | dead: 0.001 34 | sensitivity: 3 35 | snap: 1 36 | invert: 0 37 | type: 0 38 | axis: 0 39 | joyNum: 0 40 | - serializedVersion: 3 41 | m_Name: Fire1 42 | descriptiveName: 43 | descriptiveNegativeName: 44 | negativeButton: 45 | positiveButton: left ctrl 46 | altNegativeButton: 47 | altPositiveButton: mouse 0 48 | gravity: 1000 49 | dead: 0.001 50 | sensitivity: 1000 51 | snap: 0 52 | invert: 0 53 | type: 0 54 | axis: 0 55 | joyNum: 0 56 | - serializedVersion: 3 57 | m_Name: Fire2 58 | descriptiveName: 59 | descriptiveNegativeName: 60 | negativeButton: 61 | positiveButton: left alt 62 | altNegativeButton: 63 | altPositiveButton: mouse 1 64 | gravity: 1000 65 | dead: 0.001 66 | sensitivity: 1000 67 | snap: 0 68 | invert: 0 69 | type: 0 70 | axis: 0 71 | joyNum: 0 72 | - serializedVersion: 3 73 | m_Name: Fire3 74 | descriptiveName: 75 | descriptiveNegativeName: 76 | negativeButton: 77 | positiveButton: left shift 78 | altNegativeButton: 79 | altPositiveButton: mouse 2 80 | gravity: 1000 81 | dead: 0.001 82 | sensitivity: 1000 83 | snap: 0 84 | invert: 0 85 | type: 0 86 | axis: 0 87 | joyNum: 0 88 | - serializedVersion: 3 89 | m_Name: Jump 90 | descriptiveName: 91 | descriptiveNegativeName: 92 | negativeButton: 93 | positiveButton: space 94 | altNegativeButton: 95 | altPositiveButton: 96 | gravity: 1000 97 | dead: 0.001 98 | sensitivity: 1000 99 | snap: 0 100 | invert: 0 101 | type: 0 102 | axis: 0 103 | joyNum: 0 104 | - serializedVersion: 3 105 | m_Name: Mouse X 106 | descriptiveName: 107 | descriptiveNegativeName: 108 | negativeButton: 109 | positiveButton: 110 | altNegativeButton: 111 | altPositiveButton: 112 | gravity: 0 113 | dead: 0 114 | sensitivity: 0.1 115 | snap: 0 116 | invert: 0 117 | type: 1 118 | axis: 0 119 | joyNum: 0 120 | - serializedVersion: 3 121 | m_Name: Mouse Y 122 | descriptiveName: 123 | descriptiveNegativeName: 124 | negativeButton: 125 | positiveButton: 126 | altNegativeButton: 127 | altPositiveButton: 128 | gravity: 0 129 | dead: 0 130 | sensitivity: 0.1 131 | snap: 0 132 | invert: 0 133 | type: 1 134 | axis: 1 135 | joyNum: 0 136 | - serializedVersion: 3 137 | m_Name: Mouse ScrollWheel 138 | descriptiveName: 139 | descriptiveNegativeName: 140 | negativeButton: 141 | positiveButton: 142 | altNegativeButton: 143 | altPositiveButton: 144 | gravity: 0 145 | dead: 0 146 | sensitivity: 0.1 147 | snap: 0 148 | invert: 0 149 | type: 1 150 | axis: 2 151 | joyNum: 0 152 | - serializedVersion: 3 153 | m_Name: Horizontal 154 | descriptiveName: 155 | descriptiveNegativeName: 156 | negativeButton: 157 | positiveButton: 158 | altNegativeButton: 159 | altPositiveButton: 160 | gravity: 0 161 | dead: 0.19 162 | sensitivity: 1 163 | snap: 0 164 | invert: 0 165 | type: 2 166 | axis: 0 167 | joyNum: 0 168 | - serializedVersion: 3 169 | m_Name: Vertical 170 | descriptiveName: 171 | descriptiveNegativeName: 172 | negativeButton: 173 | positiveButton: 174 | altNegativeButton: 175 | altPositiveButton: 176 | gravity: 0 177 | dead: 0.19 178 | sensitivity: 1 179 | snap: 0 180 | invert: 1 181 | type: 2 182 | axis: 1 183 | joyNum: 0 184 | - serializedVersion: 3 185 | m_Name: Fire1 186 | descriptiveName: 187 | descriptiveNegativeName: 188 | negativeButton: 189 | positiveButton: joystick button 0 190 | altNegativeButton: 191 | altPositiveButton: 192 | gravity: 1000 193 | dead: 0.001 194 | sensitivity: 1000 195 | snap: 0 196 | invert: 0 197 | type: 0 198 | axis: 0 199 | joyNum: 0 200 | - serializedVersion: 3 201 | m_Name: Fire2 202 | descriptiveName: 203 | descriptiveNegativeName: 204 | negativeButton: 205 | positiveButton: joystick button 1 206 | altNegativeButton: 207 | altPositiveButton: 208 | gravity: 1000 209 | dead: 0.001 210 | sensitivity: 1000 211 | snap: 0 212 | invert: 0 213 | type: 0 214 | axis: 0 215 | joyNum: 0 216 | - serializedVersion: 3 217 | m_Name: Fire3 218 | descriptiveName: 219 | descriptiveNegativeName: 220 | negativeButton: 221 | positiveButton: joystick button 2 222 | altNegativeButton: 223 | altPositiveButton: 224 | gravity: 1000 225 | dead: 0.001 226 | sensitivity: 1000 227 | snap: 0 228 | invert: 0 229 | type: 0 230 | axis: 0 231 | joyNum: 0 232 | - serializedVersion: 3 233 | m_Name: Jump 234 | descriptiveName: 235 | descriptiveNegativeName: 236 | negativeButton: 237 | positiveButton: joystick button 3 238 | altNegativeButton: 239 | altPositiveButton: 240 | gravity: 1000 241 | dead: 0.001 242 | sensitivity: 1000 243 | snap: 0 244 | invert: 0 245 | type: 0 246 | axis: 0 247 | joyNum: 0 248 | - serializedVersion: 3 249 | m_Name: Submit 250 | descriptiveName: 251 | descriptiveNegativeName: 252 | negativeButton: 253 | positiveButton: return 254 | altNegativeButton: 255 | altPositiveButton: joystick button 0 256 | gravity: 1000 257 | dead: 0.001 258 | sensitivity: 1000 259 | snap: 0 260 | invert: 0 261 | type: 0 262 | axis: 0 263 | joyNum: 0 264 | - serializedVersion: 3 265 | m_Name: Submit 266 | descriptiveName: 267 | descriptiveNegativeName: 268 | negativeButton: 269 | positiveButton: enter 270 | altNegativeButton: 271 | altPositiveButton: space 272 | gravity: 1000 273 | dead: 0.001 274 | sensitivity: 1000 275 | snap: 0 276 | invert: 0 277 | type: 0 278 | axis: 0 279 | joyNum: 0 280 | - serializedVersion: 3 281 | m_Name: Cancel 282 | descriptiveName: 283 | descriptiveNegativeName: 284 | negativeButton: 285 | positiveButton: escape 286 | altNegativeButton: 287 | altPositiveButton: joystick button 1 288 | gravity: 1000 289 | dead: 0.001 290 | sensitivity: 1000 291 | snap: 0 292 | invert: 0 293 | type: 0 294 | axis: 0 295 | joyNum: 0 296 | -------------------------------------------------------------------------------- /src/cloud/functions/leaderboards/around-me/leaderboard/run.csx: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Configuration; 5 | using System.Linq; 6 | using System.Net; 7 | using Microsoft.Azure.Documents; 8 | using Microsoft.Azure.Documents.Client; 9 | using Newtonsoft.Json; 10 | using System.Collections.Generic; 11 | 12 | // Read application settings 13 | private static string db = ConfigurationManager.AppSettings["COSMOSDB_DBNAME"]; 14 | private static string endpoint = ConfigurationManager.AppSettings["COSMOSDB_ENDPOINT"]; 15 | private static string key = ConfigurationManager.AppSettings["COSMOSDB_PRIMARY_MASTER_KEY"]; 16 | private static string baseArchitectureVersion = ConfigurationManager.AppSettings["BASE_ARCHITECTURE_VERSION"]; 17 | private const string requiredBaseArchitectureVersion = "1.1"; 18 | 19 | private const string collection = "scores"; 20 | private const int radiusOfLeaderboard = 5; 21 | private static bool runOnce = true; 22 | private static DocumentClient client; 23 | 24 | public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, string leaderboard, string playerId, TraceWriter log) 25 | { 26 | // Run initialization only once. 27 | // Remarks: This initialization will run once on every instance and on every recompile of this function 28 | if (runOnce) 29 | { 30 | log.Info("Running initialization"); 31 | 32 | if (string.IsNullOrWhiteSpace(baseArchitectureVersion) || 33 | !baseArchitectureVersion.StartsWith(requiredBaseArchitectureVersion)) log.Error($"The base architecture version doesn't match the expected version {requiredBaseArchitectureVersion}"); 34 | 35 | // Check required application settings 36 | if (string.IsNullOrWhiteSpace(db)) log.Error("COSMOSDB_DBNAME settings wasn't provided"); 37 | if (string.IsNullOrWhiteSpace(endpoint)) log.Error("COSMOSDB_ENDPOINT settings wasn't provided"); 38 | if (string.IsNullOrWhiteSpace(key)) log.Error("COSMOSDB_PRIMARY_MASTER_KEY settings wasn't provided"); 39 | 40 | // Create Cosmos DB Client from settings 41 | client = new DocumentClient(new Uri(endpoint), key); 42 | 43 | // Create Database and Collection in Cosmos DB Account if they don't exist 44 | await client.CreateDatabaseIfNotExistsAsync(new Database { Id = db }); 45 | await client.CreateDocumentCollectionIfNotExistsAsync( 46 | UriFactory.CreateDatabaseUri(db), 47 | new DocumentCollection { Id = collection }); 48 | 49 | runOnce = false; 50 | 51 | log.Info("Initialization done!"); 52 | } 53 | 54 | if (string.IsNullOrWhiteSpace(leaderboard) || string.IsNullOrWhiteSpace(playerId)) 55 | return req.CreateResponse(HttpStatusCode.BadRequest, "Both playerId and leaderboard should be provided in URL path, format is leaderboard/playerId"); 56 | 57 | try 58 | { 59 | 60 | var scores = client.CreateDocumentQuery<ScoreItem>( 61 | UriFactory.CreateDocumentCollectionUri(db, collection), new FeedOptions { EnableCrossPartitionQuery = true }); 62 | 63 | // Get score for the current player by playerId 64 | var queryGetPlayerById = 65 | (from s in scores 66 | where s.PlayerId == playerId && s.Leaderboard == leaderboard 67 | select s); 68 | 69 | var player = queryGetPlayerById.ToList(); 70 | if (player.Count < 1) 71 | return req.CreateResponse(HttpStatusCode.BadRequest, $"Player with Id = {playerId} in Leaderboard = {leaderboard} does not exist in the database"); 72 | 73 | if (player.Count > 1) 74 | return req.CreateResponse(HttpStatusCode.BadRequest, $"There are more than one player with Id = {playerId} in Leaderboard = {leaderboard}. This is DB confuguration error - this combination should be unique"); 75 | 76 | var currentPlayer = player.First(); 77 | 78 | // Calculate global rank for the current player by playerId 79 | int globalRank; 80 | 81 | List<LeaderboardItem> sortedResult = new List<LeaderboardItem>(); //Sorted list from highest score (start of list) to lowest for output 82 | 83 | var queryGetCountOfPlayersWithHigherScore = (from c in scores 84 | where c.Score > currentPlayer.Score && c.Leaderboard == leaderboard 85 | select c).Count<ScoreItem>(); 86 | 87 | globalRank = queryGetCountOfPlayersWithHigherScore + 1; 88 | 89 | if (globalRank > 1) //if current player is not number 1 in global rank, otherwise we can skip retrieveing people with scores higher than player's 90 | { 91 | // Get and add to output specific number of players (radiusOfLeaderboard constant) with scores above the current player) 92 | var queryGetPlayersWithHigherScores = (from s in scores 93 | where s.Score > currentPlayer.Score && s.Leaderboard == leaderboard 94 | orderby s.Score ascending 95 | select s).Take(radiusOfLeaderboard); 96 | 97 | var sortedListPositionsAboveCurrent = queryGetPlayersWithHigherScores.ToList<ScoreItem>(); 98 | 99 | for (int i = sortedListPositionsAboveCurrent.Count - 1; i >= 0; i--) //sort list from highest score to lowest 100 | { 101 | sortedResult.Add(new LeaderboardItem { Rank = globalRank - 1, Player = sortedListPositionsAboveCurrent[i].Player, Score = sortedListPositionsAboveCurrent[i].Score }); 102 | } 103 | }; 104 | 105 | // Add current player to output 106 | sortedResult.Add(new LeaderboardItem { Rank = globalRank, Player = currentPlayer.Player, Score = currentPlayer.Score }); 107 | int currentPlayerIndex = sortedResult.Count - 1; 108 | 109 | // Get and add to output specific number of players (radiusOfLeaderboard constant) with scores below the current player) 110 | var queryGetPlayersWithLowerScores = (from s in scores 111 | where s.Score <= currentPlayer.Score && s.Leaderboard == leaderboard && s.PlayerId != currentPlayer.PlayerId 112 | orderby s.Score descending 113 | select s).Take(radiusOfLeaderboard); 114 | 115 | var sortedListPositionsBelowCurrent = queryGetPlayersWithLowerScores.ToList<ScoreItem>(); 116 | 117 | if (!(sortedListPositionsBelowCurrent is null)) 118 | { 119 | foreach (ScoreItem scr in sortedListPositionsBelowCurrent) 120 | { 121 | sortedResult.Add(new LeaderboardItem { Rank = 0, Player = scr.Player, Score = scr.Score }); 122 | } 123 | } 124 | 125 | int currentRank = 1; 126 | int sameScoreCount = 0; 127 | sortedResult[0].Rank = currentRank; 128 | for (int i = 1; i < sortedResult.Count; i++) //calculate relative ranking in result set 129 | { 130 | if (sortedResult[i].Score < sortedResult[i - 1].Score) 131 | { 132 | currentRank += 1 + sameScoreCount; 133 | sameScoreCount = 0; 134 | } 135 | else 136 | { 137 | sameScoreCount++; 138 | } 139 | sortedResult[i].Rank = currentRank; 140 | } 141 | 142 | int diffLocalVsGlobalRank = globalRank - sortedResult[currentPlayerIndex].Rank; //calculate difference of local ranking vs global for current player 143 | 144 | //adjust local ranking with global ranking values 145 | for (int i = 0; i < sortedResult.Count; i++) 146 | { 147 | sortedResult[i].Rank = sortedResult[i].Rank + diffLocalVsGlobalRank; 148 | } 149 | 150 | return req.CreateResponse(HttpStatusCode.OK, sortedResult); 151 | 152 | } 153 | catch (DocumentClientException ex) 154 | { 155 | log.Info(ex.ToString()); 156 | 157 | if (ex.StatusCode == HttpStatusCode.NotFound) 158 | return req.CreateResponse(HttpStatusCode.BadRequest, "This user does not exist in the database."); 159 | 160 | return req.CreateResponse(HttpStatusCode.BadRequest, $"An unknown error has occured. Message: {ex.Message}"); 161 | } 162 | } 163 | 164 | public class ScoreItem 165 | { 166 | [JsonProperty(PropertyName = "id")] 167 | public string Id { get; set; } 168 | [JsonProperty(PropertyName = "leaderboard")] 169 | public string Leaderboard { get; set; } 170 | [JsonProperty(PropertyName = "player")] 171 | public string Player { get; set; } 172 | [JsonProperty(PropertyName = "playerId")] 173 | public string PlayerId { get; set; } 174 | [JsonProperty(PropertyName = "score")] 175 | public double Score { get; set; } 176 | } 177 | 178 | public class LeaderboardItem 179 | { 180 | [JsonProperty(PropertyName = "rank")] 181 | public int Rank { get; set; } 182 | [JsonProperty(PropertyName = "player")] 183 | public string Player { get; set; } 184 | [JsonProperty(PropertyName = "score")] 185 | public double Score { get; set; } 186 | } 187 | -------------------------------------------------------------------------------- /src/Client/Unity/Assets/Nether/Leaderboard/LeaderboardManager.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Azure.AppServices; 5 | using Azure.Functions; 6 | using RESTClient; 7 | using System.Collections; 8 | using System.Collections.Generic; 9 | using Tacticsoft; 10 | using UnityEngine; 11 | using UnityEngine.SceneManagement; 12 | 13 | 14 | namespace Nether { 15 | public class LeaderboardManager : MonoBehaviour, ITableViewDataSource { 16 | // Login delegates 17 | public delegate void LoginSuccess(); 18 | public delegate void LoginFail(); 19 | public static event LoginSuccess OnLoginSuccess; 20 | public static event LoginFail OnLoginFail; 21 | 22 | // Logout delegates 23 | public delegate void LogoutSuccess(); 24 | public delegate void LogoutFail(); 25 | public static event LoginSuccess OnLogoutSuccess; 26 | public static event LoginFail OnLogoutFail; 27 | 28 | // Leaderboard delegates 29 | public delegate void LoadLeaderboardSuccess(LeaderboardItem[] scores); 30 | public delegate void LoadLeaderboardFail(); 31 | public static event LoadLeaderboardSuccess OnLoadLeaderboardSuccess; 32 | public static event LoadLeaderboardFail OnLoadLeaderboardFail; 33 | 34 | // Score delegates 35 | public delegate void SubmitScoreSuccess(); 36 | public delegate void SubmitScoreFail(); 37 | public static event SubmitScoreSuccess OnSubmitScoreSuccess; 38 | public static event SubmitScoreFail OnSubmitScoreFail; 39 | 40 | [Header("Azure Functions")] 41 | [SerializeField] 42 | private string account; 43 | 44 | [Space(10)] 45 | [SerializeField] 46 | private string leaderboardFunction = "Leaderboard"; 47 | [SerializeField] 48 | private string leaderboardKey; 49 | 50 | [Space(10)] 51 | [SerializeField] 52 | private string scoreFunction = "Score"; 53 | [SerializeField] 54 | private string scoreKey; 55 | 56 | [Header("Unity UI")] 57 | [SerializeField] 58 | private Canvas canvas; 59 | 60 | [Header("TSTableView")] 61 | 62 | [SerializeField] 63 | private TableView tableViewPrefab; 64 | [SerializeField] 65 | private ScoreCell tableViewCellPrefab; 66 | private TableView tableView; 67 | private List<LeaderboardItem> highscores = new List<LeaderboardItem>(); 68 | 69 | private AzureFunctionClient client; 70 | private AzureFunction leaderboardService; 71 | private AzureFunction scoreService; 72 | 73 | private IEnumerator coroutine; 74 | 75 | private static string kTAG = "Nether"; 76 | 77 | // Use this for initialization 78 | void Start() { 79 | if (canvas == null) { 80 | Debug.unityLogger.LogError(kTAG, "Attach 'canvas' property to root Canvas game object in hierarchy."); 81 | return; 82 | } 83 | 84 | if (string.IsNullOrEmpty(account) || string.IsNullOrEmpty(leaderboardKey) || string.IsNullOrEmpty(scoreKey) ) { 85 | Debug.unityLogger.LogError(kTAG, "Azure Function account and key required."); 86 | return; 87 | } 88 | 89 | if (tableViewPrefab == null || tableViewCellPrefab == null) { 90 | Debug.unityLogger.LogError(kTAG, "To use the table view the associated prefabs must be attached."); 91 | return; 92 | } 93 | 94 | client = AzureFunctionClient.Create(account); 95 | leaderboardService = new AzureFunction(leaderboardFunction, client, leaderboardKey); 96 | scoreService = new AzureFunction(scoreFunction, client, scoreKey); 97 | } 98 | 99 | // Update is called once per frame 100 | void Update() { 101 | 102 | } 103 | 104 | #region User Authentication 105 | 106 | public void Login(AuthenticationProvider provider, string accessToken, string secretToken = null) { 107 | accessToken = accessToken.Trim(); 108 | if (!string.IsNullOrEmpty(secretToken)) { 109 | secretToken = secretToken.Trim(); 110 | } 111 | switch (provider) { 112 | case AuthenticationProvider.Facebook: 113 | StartCoroutine(client.LoginWithFacebook(accessToken, LoginCompleted)); 114 | break; 115 | case AuthenticationProvider.Twitter: 116 | if (string.IsNullOrEmpty(secretToken)) { 117 | Debug.LogError("Twitter login requires access token secret"); 118 | } 119 | StartCoroutine(client.LoginWithTwitter(accessToken, secretToken, LoginCompleted)); 120 | break; 121 | case AuthenticationProvider.Google: 122 | if (string.IsNullOrEmpty(secretToken)) { 123 | Debug.LogError("Google+ login requires id token"); 124 | } 125 | StartCoroutine(client.LoginWithGoogle(accessToken, secretToken, LoginCompleted)); 126 | break; 127 | case AuthenticationProvider.MicrosoftAccount: 128 | StartCoroutine(client.LoginWithMicrosoftAccount(accessToken, LoginCompleted)); 129 | break; 130 | } 131 | } 132 | 133 | private void LoginCompleted(IRestResponse<AuthenticatedUser> response) { 134 | if (response.IsError) { 135 | Debug.unityLogger.LogError(kTAG, "Error login failed. " + response.ErrorMessage); 136 | OnLoginFail(); 137 | return; 138 | } 139 | OnLoginSuccess(); 140 | } 141 | 142 | public void Logout() { 143 | StartCoroutine(client.Logout(LogoutCompleted)); 144 | } 145 | 146 | public void LogoutCompleted(IRestResponse<string> response) { 147 | if (response.IsError) { 148 | Debug.unityLogger.LogError(kTAG, "Error logout failed. " + response.ErrorMessage); 149 | OnLogoutFail(); 150 | return; 151 | } 152 | OnLogoutSuccess(); 153 | } 154 | 155 | #endregion 156 | 157 | #region Show/hide leaderboard 158 | 159 | public bool IsLeaderboardOpen() { 160 | if (tableView != null && tableView.enabled) { 161 | return true; 162 | } 163 | return false; 164 | } 165 | 166 | public void ToggleLeaderboard() { 167 | if (tableView == null) { 168 | CreateLeaderboard(); 169 | LoadLeaderboard(); 170 | } else { 171 | RemoveLeaderboard(); 172 | } 173 | } 174 | 175 | private void CreateLeaderboard() { 176 | if (tableView == null) { 177 | tableView = Instantiate<TableView>(tableViewPrefab, canvas.transform); 178 | tableView.dataSource = this; 179 | // move to back in Canvas 180 | tableView.transform.SetAsFirstSibling(); 181 | } 182 | } 183 | 184 | private void RemoveLeaderboard() { 185 | if (tableView != null) { 186 | tableView.enabled = false; 187 | // cancel async tasks associated with Unity game object to be destroyed 188 | StopCoroutine(coroutine); 189 | Destroy(tableView.gameObject); 190 | } 191 | } 192 | 193 | #endregion 194 | 195 | #region Load highscores 196 | 197 | public void LoadLeaderboard() { 198 | coroutine = leaderboardService.GetArray<LeaderboardItem>(LoadLeaderboardCompleted); 199 | StartCoroutine(coroutine); 200 | } 201 | 202 | private void LoadLeaderboardCompleted(IRestResponse<LeaderboardItem[]> response) { 203 | if (response.IsError) { 204 | Debug.unityLogger.LogError(kTAG, "Error loading leaderboard. " + response.ErrorMessage); 205 | OnLoadLeaderboardFail(); 206 | return; 207 | } 208 | highscores = new List<LeaderboardItem>(response.Data); 209 | Debug.unityLogger.Log("Successfully loaded leaderboard."); 210 | if (tableView != null) { 211 | tableView.ReloadData(); 212 | } 213 | OnLoadLeaderboardSuccess(highscores.ToArray()); 214 | } 215 | 216 | #endregion 217 | 218 | #region Submit new highscore 219 | 220 | public void SubmitScore(string player, double score) { 221 | string userId = client.User != null ? client.User.user.userId : player.ToLower(); 222 | ScoreItem body = new ScoreItem(); 223 | body.player = player; 224 | body.score = score; 225 | body.playerId = userId; 226 | StartCoroutine(scoreService.Post<ScoreItem, string>(body, SubmitScoreCompleted)); 227 | } 228 | 229 | private void SubmitScoreCompleted(IRestResponse<string> response) { 230 | if (response.IsError) { 231 | Debug.unityLogger.LogError(kTAG, "Error sending score. " + response.ErrorMessage); 232 | OnSubmitScoreFail(); 233 | return; 234 | } 235 | Debug.unityLogger.Log("Successfully submitted score: \n" + response.Content); 236 | OnSubmitScoreSuccess(); 237 | if (tableView != null) { 238 | LoadLeaderboard(); 239 | } 240 | } 241 | 242 | #endregion 243 | 244 | #region TSTableView methods 245 | 246 | public int GetNumberOfRowsForTableView(TableView tableView) { 247 | return highscores.Count; 248 | } 249 | 250 | public float GetHeightForRowInTableView(TableView tableView, int row) { 251 | return (tableViewCellPrefab.transform as RectTransform).rect.height; 252 | } 253 | 254 | public TableViewCell GetCellForRowInTableView(TableView tableView, int row) { 255 | ScoreCell cell = tableView.GetReusableCell(tableViewCellPrefab.reuseIdentifier) as ScoreCell; 256 | if (cell == null) { 257 | cell = (ScoreCell)GameObject.Instantiate(tableViewCellPrefab); 258 | } 259 | LeaderboardItem data = highscores[row]; 260 | cell.Name.text = data.player; 261 | cell.Score.text = data.score.ToString(); 262 | cell.Rank.text = data.rank.ToString(); 263 | return cell; 264 | } 265 | 266 | #endregion 267 | } 268 | } 269 | --------------------------------------------------------------------------------