├── .arcconfig ├── BasicSample ├── README.md └── basic_sample.js ├── GetPlayersInSegmentSample ├── README.md └── get_players_in_segment_api_sample.js ├── LICENSE ├── Photon-Cloud-Integration └── README.txt ├── README.md ├── Rewards ├── CloudScript_Rewards.js └── README.txt └── genConfig.json /.arcconfig: -------------------------------------------------------------------------------- 1 | { 2 | "phabricator.uri" : "https://phab.playfabdev.com/" 3 | } -------------------------------------------------------------------------------- /BasicSample/README.md: -------------------------------------------------------------------------------- 1 | Cloud Script Basic Sample (basic_sample.js): 2 | ---- 3 | 4 | Please note that the Cloud Script automatically loaded as Revision 1 in all new titles is not specifically copied from this source. We do make an effort to keep them in sync, but if you do notice any differences, please feel free to let us know via the PlayFab forums. 5 | 6 | This file provides basic Cloud Script examples of: 7 | 8 | * helloWorld - Using the currentPlayerId (the logged-in user), output logging, and returning values 9 | * completedLevel - Updating user statistics and user internal data (data which cannot be read or written by the client) 10 | * updatePlayerMove, processPlayerMove - Calling a function from within Cloud Script, reading and updating user statistics, updating user internal data, basic server-side validation (checking that the reported value is within reason) 11 | * RoomCreated, RoomJoined, RoomLeft, RoomClosed, RoomEventRaised - Handlers for managing webhook calls from a Photon Cloud server (see this document for more information: https://playfab.com/using-photon-playfab) 12 | 13 | For more information on using Cloud Script in PlayFab, please refer to our Example: 14 | * https://github.com/PlayFab/SdkTestingCloudScript 15 | -------------------------------------------------------------------------------- /BasicSample/basic_sample.js: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Welcome to your first Cloud Script revision! 4 | // 5 | // Cloud Script runs in the PlayFab cloud and has full access to the PlayFab Game Server API 6 | // (https://api.playfab.com/Documentation/Server), and it runs in the context of a securely 7 | // authenticated player, so you can use it to implement logic for your game that is safe from 8 | // client-side exploits. 9 | // 10 | // Cloud Script functions can also make web requests to external HTTP 11 | // endpoints, such as a database or private API for your title, which makes them a flexible 12 | // way to integrate with your existing backend systems. 13 | // 14 | // There are several different options for calling Cloud Script functions: 15 | // 16 | // 1) Your game client calls them directly using the "ExecuteCloudScript" API, 17 | // passing in the function name and arguments in the request and receiving the 18 | // function return result in the response. 19 | // (https://api.playfab.com/Documentation/Client/method/ExecuteCloudScript) 20 | // 21 | // 2) You create PlayStream event actions that call them when a particular 22 | // event occurs, passing in the event and associated player profile data. 23 | // (https://api.playfab.com/playstream/docs) 24 | // 25 | // 3) For titles using the Photon Add-on (https://playfab.com/marketplace/photon/), 26 | // Photon room events trigger webhooks which call corresponding Cloud Script functions. 27 | // 28 | // The following examples demonstrate all three options. 29 | // 30 | /////////////////////////////////////////////////////////////////////////////////////////////////////// 31 | 32 | 33 | // This is a Cloud Script function. "args" is set to the value of the "FunctionParameter" 34 | // parameter of the ExecuteCloudScript API. 35 | // (https://api.playfab.com/Documentation/Client/method/ExecuteCloudScript) 36 | // "context" contains additional information when the Cloud Script function is called from a PlayStream action. 37 | handlers.helloWorld = function (args, context) { 38 | 39 | // The pre-defined "currentPlayerId" variable is initialized to the PlayFab ID of the player logged-in on the game client. 40 | // Cloud Script handles authenticating the player automatically. 41 | var message = "Hello " + currentPlayerId + "!"; 42 | 43 | // You can use the "log" object to write out debugging statements. It has 44 | // three functions corresponding to logging level: debug, info, and error. These functions 45 | // take a message string and an optional object. 46 | log.info(message); 47 | var inputValue = null; 48 | if (args && args.inputValue) 49 | inputValue = args.inputValue; 50 | log.debug("helloWorld:", { input: inputValue }); 51 | 52 | // The value you return from a Cloud Script function is passed back 53 | // to the game client in the ExecuteCloudScript API response, along with any log statements 54 | // and additional diagnostic information, such as any errors returned by API calls or external HTTP 55 | // requests. They are also included in the optional player_executed_cloudscript PlayStream event 56 | // generated by the function execution. 57 | // (https://api.playfab.com/playstream/docs/PlayStreamEventModels/player/player_executed_cloudscript) 58 | return { messageValue: message }; 59 | }; 60 | 61 | // This is a simple example of making a PlayFab server API call 62 | handlers.makeAPICall = function (args, context) { 63 | var request = { 64 | PlayFabId: currentPlayerId, Statistics: [{ 65 | StatisticName: "Level", 66 | Value: 2 67 | }] 68 | }; 69 | // The pre-defined "server" object has functions corresponding to each PlayFab server API 70 | // (https://api.playfab.com/Documentation/Server). It is automatically 71 | // authenticated as your title and handles all communication with 72 | // the PlayFab API, so you don't have to write extra code to issue HTTP requests. 73 | var playerStatResult = server.UpdatePlayerStatistics(request); 74 | }; 75 | 76 | // This is a simple example of making a web request to an external HTTP API. 77 | handlers.makeHTTPRequest = function (args, context) { 78 | var headers = { 79 | "X-MyCustomHeader": "Some Value" 80 | }; 81 | 82 | var body = { 83 | input: args, 84 | userId: currentPlayerId, 85 | mode: "foobar" 86 | }; 87 | 88 | var url = "http://httpbin.org/status/200"; 89 | var content = JSON.stringify(body); 90 | var httpMethod = "post"; 91 | var contentType = "application/json"; 92 | 93 | // The pre-defined http object makes synchronous HTTP requests 94 | var response = http.request(url, httpMethod, content, contentType, headers); 95 | return { responseContent: response }; 96 | }; 97 | 98 | // This is a simple example of a function that is called from a 99 | // PlayStream event action. (https://playfab.com/introducing-playstream/) 100 | handlers.handlePlayStreamEventAndProfile = function (args, context) { 101 | 102 | // The event that triggered the action 103 | // (https://api.playfab.com/playstream/docs/PlayStreamEventModels) 104 | var psEvent = context.playStreamEvent; 105 | 106 | // The profile data of the player associated with the event 107 | // (https://api.playfab.com/playstream/docs/PlayStreamProfileModels) 108 | var profile = context.playerProfile; 109 | 110 | // Post data about the event to an external API 111 | var content = JSON.stringify({ user: profile.PlayerId, event: psEvent.EventName }); 112 | var response = http.request('https://httpbin.org/status/200', 'post', content, 'application/json', null); 113 | 114 | return { externalAPIResponse: response }; 115 | }; 116 | 117 | 118 | // Below are some examples of using Cloud Script in slightly more realistic scenarios 119 | 120 | // This is a function that the game client would call whenever a player completes 121 | // a level. It updates a setting in the player's data that only game server 122 | // code can write - it is read-only on the client - and it updates a player 123 | // statistic that can be used for leaderboards. 124 | // 125 | // A funtion like this could be extended to perform validation on the 126 | // level completion data to detect cheating. It could also do things like 127 | // award the player items from the game catalog based on their performance. 128 | handlers.completedLevel = function (args, context) { 129 | var level = args.levelName; 130 | var monstersKilled = args.monstersKilled; 131 | 132 | var updateUserDataResult = server.UpdateUserInternalData({ 133 | PlayFabId: currentPlayerId, 134 | Data: { 135 | lastLevelCompleted: level 136 | } 137 | }); 138 | 139 | log.debug("Set lastLevelCompleted for player " + currentPlayerId + " to " + level); 140 | var request = { 141 | PlayFabId: currentPlayerId, Statistics: [{ 142 | StatisticName: "level_monster_kills", 143 | Value: monstersKilled 144 | }] 145 | }; 146 | server.UpdatePlayerStatistics(request); 147 | log.debug("Updated level_monster_kills stat for player " + currentPlayerId + " to " + monstersKilled); 148 | }; 149 | 150 | 151 | // In addition to the Cloud Script handlers, you can define your own functions and call them from your handlers. 152 | // This makes it possible to share code between multiple handlers and to improve code organization. 153 | handlers.updatePlayerMove = function (args) { 154 | var validMove = processPlayerMove(args); 155 | return { validMove: validMove }; 156 | }; 157 | 158 | 159 | // This is a helper function that verifies that the player's move wasn't made 160 | // too quickly following their previous move, according to the rules of the game. 161 | // If the move is valid, then it updates the player's statistics and profile data. 162 | // This function is called from the "UpdatePlayerMove" handler above and also is 163 | // triggered by the "RoomEventRaised" Photon room event in the Webhook handler 164 | // below. 165 | // 166 | // For this example, the script defines the cooldown period (playerMoveCooldownInSeconds) 167 | // as 15 seconds. A recommended approach for values like this would be to create them in Title 168 | // Data, so that they can be queries in the script with a call to GetTitleData 169 | // (https://api.playfab.com/Documentation/Server/method/GetTitleData). This would allow you to 170 | // make adjustments to these values over time, without having to edit, test, and roll out an 171 | // updated script. 172 | function processPlayerMove(playerMove) { 173 | var now = Date.now(); 174 | var playerMoveCooldownInSeconds = 15; 175 | 176 | var playerData = server.GetUserInternalData({ 177 | PlayFabId: currentPlayerId, 178 | Keys: ["last_move_timestamp"] 179 | }); 180 | 181 | var lastMoveTimestampSetting = playerData.Data["last_move_timestamp"]; 182 | 183 | if (lastMoveTimestampSetting) { 184 | var lastMoveTime = Date.parse(lastMoveTimestampSetting.Value); 185 | var timeSinceLastMoveInSeconds = (now - lastMoveTime) / 1000; 186 | log.debug("lastMoveTime: " + lastMoveTime + " now: " + now + " timeSinceLastMoveInSeconds: " + timeSinceLastMoveInSeconds); 187 | 188 | if (timeSinceLastMoveInSeconds < playerMoveCooldownInSeconds) { 189 | log.error("Invalid move - time since last move: " + timeSinceLastMoveInSeconds + "s less than minimum of " + playerMoveCooldownInSeconds + "s."); 190 | return false; 191 | } 192 | } 193 | 194 | var playerStats = server.GetPlayerStatistics({ 195 | PlayFabId: currentPlayerId 196 | }).Statistics; 197 | var movesMade = 0; 198 | for (var i = 0; i < playerStats.length; i++) 199 | if (playerStats[i].StatisticName === "") 200 | movesMade = playerStats[i].Value; 201 | movesMade += 1; 202 | var request = { 203 | PlayFabId: currentPlayerId, Statistics: [{ 204 | StatisticName: "movesMade", 205 | Value: movesMade 206 | }] 207 | }; 208 | server.UpdatePlayerStatistics(request); 209 | server.UpdateUserInternalData({ 210 | PlayFabId: currentPlayerId, 211 | Data: { 212 | last_move_timestamp: new Date(now).toUTCString(), 213 | last_move: JSON.stringify(playerMove) 214 | } 215 | }); 216 | 217 | return true; 218 | } 219 | 220 | // This is an example of using PlayStream real-time segmentation to trigger 221 | // game logic based on player behavior. (https://playfab.com/introducing-playstream/) 222 | // The function is called when a player_statistic_changed PlayStream event causes a player 223 | // to enter a segment defined for high skill players. It sets a key value in 224 | // the player's internal data which unlocks some new content for the player. 225 | handlers.unlockHighSkillContent = function (args, context) { 226 | var playerStatUpdatedEvent = context.playStreamEvent; 227 | var request = { 228 | PlayFabId: currentPlayerId, 229 | Data: { 230 | "HighSkillContent": "true", 231 | "XPAtHighSkillUnlock": playerStatUpdatedEvent.StatisticValue.toString() 232 | } 233 | }; 234 | var playerInternalData = server.UpdateUserInternalData(request); 235 | log.info('Unlocked HighSkillContent for ' + context.playerProfile.DisplayName); 236 | return { profile: context.playerProfile }; 237 | }; 238 | 239 | // Photon Webhooks Integration 240 | // 241 | // The following functions are examples of Photon Cloud Webhook handlers. 242 | // When you enable the Photon Add-on (https://playfab.com/marketplace/photon/) 243 | // in the Game Manager, your Photon applications are automatically configured 244 | // to authenticate players using their PlayFab accounts and to fire events that 245 | // trigger your Cloud Script Webhook handlers, if defined. 246 | // This makes it easier than ever to incorporate multiplayer server logic into your game. 247 | 248 | 249 | // Triggered automatically when a Photon room is first created 250 | handlers.RoomCreated = function (args) { 251 | server.WritePlayerEvent({ 252 | EventName : "room_created", 253 | PlayFabId: args.UserId, 254 | Body: { 255 | WebHook: { 256 | AppVersion: args.AppVersion, 257 | Region: args.Region, 258 | GameId: args.GameId, 259 | Type: args.Type, 260 | ActorNr: args.ActorNr, 261 | CreateOptions: args.CreateOptions 262 | } 263 | } 264 | }); 265 | }; 266 | 267 | // Triggered automatically when a player joins a Photon room 268 | handlers.RoomJoined = function (args) { 269 | server.WritePlayerEvent({ 270 | EventName: "room_joined", 271 | PlayFabId: args.UserId, 272 | Body: { 273 | WebHook: { 274 | AppVersion: args.AppVersion, 275 | Region: args.Region, 276 | GameId: args.GameId, 277 | ActorNr: args.ActorNr 278 | } 279 | } 280 | }); 281 | }; 282 | 283 | // Triggered automatically when a player leaves a Photon room 284 | handlers.RoomLeft = function (args) { 285 | server.WritePlayerEvent({ 286 | EventName: "room_left", 287 | PlayFabId: args.UserId, 288 | Body: { 289 | WebHook: { 290 | AppVersion: args.AppVersion, 291 | Region: args.Region, 292 | GameId: args.GameId, 293 | Type: args.Type, 294 | ActorNr: args.ActorNr, 295 | IsInactive: args.IsInactive 296 | } 297 | } 298 | }); 299 | }; 300 | 301 | // Triggered automatically when a Photon room closes 302 | // Note: currentPlayerId is undefined in this function 303 | handlers.RoomClosed = function (args) { 304 | server.WriteTitleEvent({ 305 | EventName: "room_closed", 306 | Body: { 307 | WebHook: { 308 | AppVersion: args.AppVersion, 309 | Region: args.Region, 310 | GameId: args.GameId, 311 | Type: args.Type, 312 | ActorCount: args.ActorCount 313 | } 314 | } 315 | }); 316 | }; 317 | 318 | // Triggered automatically when a Photon room game property is updated. 319 | handlers.RoomPropertyUpdated = function (args) { 320 | if (args.Type === "Game") { 321 | server.WritePlayerEvent({ 322 | EventName: "room_properties_updated", 323 | PlayFabId: args.UserId, 324 | Body: { 325 | WebHook: { 326 | AppVersion: args.AppVersion, 327 | Region: args.Region, 328 | GameId: args.GameId, 329 | ActorNr: args.ActorNr, 330 | Properties: args.Properties 331 | } 332 | } 333 | }); 334 | } else { // "Actor" 335 | server.WritePlayerEvent({ 336 | EventName: "player_roperties_updated", 337 | PlayFabId: args.UserId, 338 | Body: { 339 | WebHook: { 340 | AppVersion: args.AppVersion, 341 | Region: args.Region, 342 | GameId: args.GameId, 343 | ActorNr: args.ActorNr, 344 | TargetActor: args.TargetActor, 345 | Properties: args.Properties 346 | } 347 | } 348 | }); 349 | } 350 | }; 351 | 352 | // Triggered by calling "OpRaiseEvent" on the Photon client. The "args.Data" property is 353 | // set to the value of the "customEventContent" HashTable parameter, so you can use 354 | // it to pass in arbitrary data. 355 | handlers.RoomEventRaised = function (args) { 356 | server.WritePlayerEvent({ 357 | EventName: "event_raised", 358 | PlayFabId: args.UserId, 359 | Body: { 360 | WebHook: { 361 | AppVersion: args.AppVersion, 362 | Region: args.Region, 363 | GameId: args.GameId, 364 | ActorNr: args.ActorNr, 365 | EvCode: args.EvCode 366 | } 367 | } 368 | }); 369 | 370 | var eventData = args.Data; 371 | switch (eventData.eventType) { // use args.EvCode instead of embedding eventType in payload 372 | case "playerMove": 373 | processPlayerMove(eventData); 374 | break; 375 | 376 | default: 377 | break; 378 | } 379 | }; 380 | -------------------------------------------------------------------------------- /GetPlayersInSegmentSample/README.md: -------------------------------------------------------------------------------- 1 | ## Samples for GetPlayersInSegment API usage in CloudScript: 2 | 3 | #### API doc: [Get Players In Segment](https://learn.microsoft.com/en-us/rest/api/playfab/server/play-stream/get-players-in-segment?view=playfab-rest) 4 | 5 | #### The file get_players_in_segment_api_sample.js provides examples of: 6 | 7 | - GetPlayersInSegmentSample: Using the GetPlayersInSegment API to get all the player profiles in a Segment and do some processing on the profiles 8 | - GetSegmentPlayerCountSample: Using the GetPlayersInSegment API to get the count of player profiles in a Segment -------------------------------------------------------------------------------- /GetPlayersInSegmentSample/get_players_in_segment_api_sample.js: -------------------------------------------------------------------------------- 1 | handlers.GetPlayersInSegmentSample = function (args, context) { 2 | 3 | /* 4 | Sample code to use the GetPlayersInSegment API to process the player profiles in a Segment. 5 | The GetPlayersInSegment API pages through the all the player profiles 6 | in the Segment in batches of size 'MaxBatchSize'. 7 | API Doc: https://learn.microsoft.com/en-us/rest/api/playfab/server/play-stream/get-players-in-segment?view=playfab-rest 8 | */ 9 | 10 | var request = { 11 | GetProfilesAsync: true, // setting to 'true' is highly recommended to avoid network timeouts 12 | MaxBatchSize: 1000, // 1000 is the default value. Maximum is 10,000 13 | SegmentId: "AAAAAAAAA" // provide your SegmentId here OR you can add SegmentId in the JSON args sent from PlayFab caller/game client and use that 14 | } 15 | 16 | // make the first GetPlayersInSegment API call 17 | var playersInSegmentResult = server.GetPlayersInSegment(request); 18 | 19 | // process until continuation token is not null to get all the profiles in this Segment 20 | while (playersInSegmentResult.ContinuationToken != null) 21 | { 22 | // get the current batch of player profiles 23 | var playerProfiles = playersInSegmentResult.PlayerProfiles; 24 | 25 | if (playerProfiles && playerProfiles.length > 0) 26 | { 27 | for(let i=0;i Cloud Script. 26 | * BasicSample/basic_sample.js -- Upload it to your title via the PlayFab Game Manager by going to Servers > Cloud Script. 27 | * Photon-Cloud-Integration -- This is a pointer to our repro showing the full [Photon Cloud sample for PlayFab](https://github.com/PlayFab/Photon-Cloud-Integration). 28 | 29 | 5. Usage Instructions: 30 | ---- 31 | * Rewards/CloudScript_Rewards.js -- As with any Cloud Script file, you can trigger any handlers._____ method from [RunCloudScript](https://api.playfab.com/Documentation/Client/method/RunCloudScript). Note that you must first establish the correct URL for your Cloud Script via a call to [GetCloudScriptUrl](https://api.playfab.com/Documentation/Client/method/GetCloudScriptUrl). 32 | * BasicSample/basic_sample.js -- As with any Cloud Script file, you can trigger any handlers._____ method from [RunCloudScript](https://api.playfab.com/Documentation/Client/method/RunCloudScript). Note that you must first establish the correct URL for your Cloud Script via a call to [GetCloudScriptUrl](https://api.playfab.com/Documentation/Client/method/GetCloudScriptUrl). 33 | * Photon-Cloud-Integration -- Please see the [Photon Cloud sample for PlayFab](https://github.com/PlayFab/Photon-Cloud-Integration). 34 | 35 | 6. Troubleshooting: 36 | ---- 37 | For a complete list of available APIs, check out the [online documentation](http://api.playfab.com/). 38 | 39 | #### Contact Us 40 | We love to hear from our developer community! 41 | Do you have ideas on how we can make our products and services better? 42 | 43 | Our Developer Success Team can assist with answering any questions as well as process any feedback you have about PlayFab services. 44 | 45 | [Forums, Support and Knowledge Base](https://community.playfab.com/) 46 | 47 | 48 | 7. Copyright and Licensing Information: 49 | ---- 50 | Apache License -- 51 | Version 2.0, January 2004 52 | http://www.apache.org/licenses/ 53 | 54 | Full details available within the LICENSE file. 55 | 56 | 57 | 8. Version History: 58 | ---- 59 | * (v1.00) Initial Release 60 | * (v1.10) Updated for latest changes to examples 61 | -------------------------------------------------------------------------------- /Rewards/CloudScript_Rewards.js: -------------------------------------------------------------------------------- 1 | var LevelRewards = 2 | [ 3 | ["TestItem1"], 4 | ["TestItem2"], 5 | ["TestItem3"], 6 | ["TestItem1", "TestItem2"], 7 | ["TestItem2", "TestItem2"], 8 | ["TestItem3", "TestItem3"] 9 | ] 10 | 11 | handlers.onLevelComplete = function(args) 12 | { 13 | var levelNum = args.level; 14 | 15 | // Do some basic input validation 16 | if(levelNum < 0 || levelNum >= LevelRewards.length) 17 | { 18 | log.info("Invalid level "+levelNum+" completed by "+currentPlayerId); 19 | return {}; 20 | } 21 | 22 | var levelCompleteKey = "LevelCompleted"+levelNum; 23 | 24 | // Get the user's internal data 25 | var playerInternalData = server.GetUserInternalData( 26 | { 27 | PlayFabId: currentPlayerId, 28 | Keys: [levelCompleteKey] 29 | }); 30 | 31 | // Did they already complete this level? 32 | if(playerInternalData.Data[levelCompleteKey]) 33 | { 34 | log.info("Player "+currentPlayerId+" already completed level "+levelNum); 35 | return {}; 36 | } 37 | 38 | var rewards = LevelRewards[levelNum]; 39 | 40 | var resultItems = null; 41 | if(rewards) 42 | { 43 | // Grant reward items to player for completing the level 44 | var itemGrantResult = server.GrantItemsToUser( 45 | { 46 | PlayFabId: currentPlayerId, 47 | Annotation: "Given by completing level "+levelNum, 48 | ItemIds: rewards 49 | }); 50 | 51 | resultItems = itemGrantResult.ItemGrantResults; 52 | } 53 | 54 | // Mark the level as being completed so they can't get the reward again 55 | var saveData = {}; 56 | saveData[levelCompleteKey] = "true"; 57 | server.UpdateUserInternalData( 58 | { 59 | PlayFabId: currentPlayerId, 60 | Data: saveData 61 | }); 62 | 63 | // Return the results of the item grant so the client can see what they got 64 | return { 65 | rewards: resultItems 66 | }; 67 | } 68 | 69 | var monsterRewards = 70 | { 71 | "skrill" : { "ChumpCoins" : 100}, 72 | "lumpur" : { "ChumpCoins" : 200} 73 | } 74 | 75 | var killCoolDown = 60; 76 | 77 | function currTimeSeconds() 78 | { 79 | var now = new Date(); 80 | return now.getTime() / 1000; 81 | } 82 | 83 | handlers.onMonsterKilled = function(args) 84 | { 85 | var monsterType = args.type; 86 | 87 | var now = currTimeSeconds(); 88 | 89 | // Get the user's internal data 90 | var playerInternalData = server.GetUserInternalData( 91 | { 92 | PlayFabId: currentPlayerId, 93 | Keys: ["lastKill"] 94 | }); 95 | 96 | // Check when the last time they killed a monster was 97 | var lastKill = playerInternalData.Data["lastKill"]; 98 | if(lastKill) 99 | { 100 | // We have a value, see when it is 101 | var lastKillTime = parseInt(lastKill.Value); 102 | if(now - lastKillTime < killCoolDown) 103 | { 104 | // In this particular game, it should not be possible to kill a monster more often than once a minute, so they might be cheating 105 | log.info("Player "+currentPlayerId+" killed "+monsterType+" again too quickly!"); 106 | return {}; 107 | } 108 | } 109 | 110 | var killReward = monsterRewards[monsterType]; 111 | 112 | if(killReward) 113 | { 114 | for(var currency in killReward) 115 | { 116 | var amount = killReward[currency]; 117 | server.AddUserVirtualCurrency({ PlayFabId: currentPlayerId, VirtualCurrency: currency, Amount: amount }); 118 | } 119 | } 120 | 121 | // Reset the kill timer 122 | server.UpdateUserInternalData( 123 | { 124 | PlayFabId: currentPlayerId, 125 | Data: { 126 | "lastKill" : String(now) 127 | } 128 | }); 129 | 130 | return { 131 | rewards: killReward 132 | }; 133 | } 134 | -------------------------------------------------------------------------------- /Rewards/README.txt: -------------------------------------------------------------------------------- 1 | Cloud Script Rewards Example (CloudScript_Rewards.js): 2 | ---------------------------------------------------------------------- 3 | This file provides basic Cloud Script examples for two reward scenarios in games: 4 | 5 | 1. Player completes a game level (onLevelComplete) 6 | 2. Player kills a monster (onMonsterKilled) 7 | 8 | In each case, the player in rewarded with inventory items or virtual currency as a result. Please note that these items need to be created in your title's Catalog prior to testing, and that a shipping title should take advantage of the server-side authority that Cloud Script enables to make validation checks on the player actions (could the player have inflicted the damage necessary in the time since the last kill, etc.). 9 | 10 | For more information on using Cloud Script in PlayFab, please refer to this guide: 11 | https://playfab.com/cloud-script 12 | -------------------------------------------------------------------------------- /genConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": { 3 | "templateFolder": "SdkTestingCloudScript", 4 | "versionKey": "SdkTestingCloudScript" 5 | } 6 | } 7 | --------------------------------------------------------------------------------