[U] add PlayFab SDK and SNS login improvements
- Add PlayFabSDK as local package dependency - Add PlayFabTool.cs for PlayFab API integration - Implement LoginBySns method in TYSdkFacade - Add Android SNS login support in SDKManager and UnityBridgeFunc - Add Build Android With Debug menu option - Improve exception handling and timeout management 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using PlayFab.Internal;
|
||||
|
||||
namespace PlayFab.Json
|
||||
{
|
||||
public class SimpleJsonInstance : ISerializerPlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Most users shouldn't access this
|
||||
/// JsonWrapper.Serialize, and JsonWrapper.Deserialize will always use it automatically (Unless you deliberately mess with them)
|
||||
/// Any Serialization of an object in the PlayFab namespace should just use JsonWrapper
|
||||
/// </summary>
|
||||
public static PlayFabSimpleJsonCuztomization ApiSerializerStrategy = new PlayFabSimpleJsonCuztomization();
|
||||
public class PlayFabSimpleJsonCuztomization : PocoJsonSerializerStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert the json value into the destination field/property
|
||||
/// </summary>
|
||||
public override object DeserializeObject(object value, Type type)
|
||||
{
|
||||
var valueStr = value as string;
|
||||
if (valueStr == null) // For all of our custom conversions, value is a string
|
||||
return base.DeserializeObject(value, type);
|
||||
|
||||
var underType = Nullable.GetUnderlyingType(type);
|
||||
if (underType != null)
|
||||
return DeserializeObject(value, underType);
|
||||
else if (type.GetTypeInfo().IsEnum)
|
||||
return Enum.Parse(type, (string)value, true);
|
||||
else if (type == typeof(DateTime))
|
||||
{
|
||||
DateTime output;
|
||||
var result = DateTime.TryParseExact(valueStr, PlayFabUtil._defaultDateTimeFormats, CultureInfo.InvariantCulture, PlayFabUtil.DateTimeStyles, out output);
|
||||
if (result)
|
||||
return output;
|
||||
}
|
||||
else if (type == typeof(DateTimeOffset))
|
||||
{
|
||||
DateTimeOffset output;
|
||||
var result = DateTimeOffset.TryParseExact(valueStr, PlayFabUtil._defaultDateTimeFormats, CultureInfo.InvariantCulture, PlayFabUtil.DateTimeStyles, out output);
|
||||
if (result)
|
||||
return output;
|
||||
}
|
||||
else if (type == typeof(TimeSpan))
|
||||
{
|
||||
double seconds;
|
||||
if (double.TryParse(valueStr, out seconds))
|
||||
return TimeSpan.FromSeconds(seconds);
|
||||
}
|
||||
return base.DeserializeObject(value, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set output to a string that represents the input object
|
||||
/// </summary>
|
||||
protected override bool TrySerializeKnownTypes(object input, out object output)
|
||||
{
|
||||
if (input.GetType().GetTypeInfo().IsEnum)
|
||||
{
|
||||
output = input.ToString();
|
||||
return true;
|
||||
}
|
||||
else if (input is DateTime)
|
||||
{
|
||||
output = ((DateTime)input).ToString(PlayFabUtil._defaultDateTimeFormats[PlayFabUtil.DEFAULT_UTC_OUTPUT_INDEX], CultureInfo.InvariantCulture);
|
||||
return true;
|
||||
}
|
||||
else if (input is DateTimeOffset)
|
||||
{
|
||||
output = ((DateTimeOffset)input).ToString(PlayFabUtil._defaultDateTimeFormats[PlayFabUtil.DEFAULT_UTC_OUTPUT_INDEX], CultureInfo.InvariantCulture);
|
||||
return true;
|
||||
}
|
||||
else if (input is TimeSpan)
|
||||
{
|
||||
output = ((TimeSpan)input).TotalSeconds;
|
||||
return true;
|
||||
}
|
||||
return base.TrySerializeKnownTypes(input, out output);
|
||||
}
|
||||
}
|
||||
|
||||
public T DeserializeObject<T>(string json)
|
||||
{
|
||||
return PlayFabSimpleJson.DeserializeObject<T>(json, ApiSerializerStrategy);
|
||||
}
|
||||
|
||||
public T DeserializeObject<T>(string json, object jsonSerializerStrategy)
|
||||
{
|
||||
return PlayFabSimpleJson.DeserializeObject<T>(json, (IJsonSerializerStrategy)jsonSerializerStrategy);
|
||||
}
|
||||
|
||||
public object DeserializeObject(string json)
|
||||
{
|
||||
return PlayFabSimpleJson.DeserializeObject(json, typeof(object), ApiSerializerStrategy);
|
||||
}
|
||||
|
||||
public string SerializeObject(object json)
|
||||
{
|
||||
return PlayFabSimpleJson.SerializeObject(json, ApiSerializerStrategy);
|
||||
}
|
||||
|
||||
public string SerializeObject(object json, object jsonSerializerStrategy)
|
||||
{
|
||||
return PlayFabSimpleJson.SerializeObject(json, (IJsonSerializerStrategy)jsonSerializerStrategy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1337f8c156b41834691b131f3b6774f9
|
||||
timeCreated: 1462682372
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
|
||||
namespace PlayFab.Internal
|
||||
{
|
||||
[Obsolete("This logging utility has been deprecated. Use UnityEngine.Debug.Log")]
|
||||
public static class Log
|
||||
{
|
||||
[Obsolete("Debug is deprecated.")]
|
||||
public static void Debug(string text, params object[] args)
|
||||
{
|
||||
if ((PlayFabSettings.LogLevel & PlayFabLogLevel.Debug) != 0)
|
||||
{
|
||||
UnityEngine.Debug.Log(PlayFabUtil.timeStamp + " DEBUG: " + PlayFabUtil.Format(text, args));
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Info is deprecated.")]
|
||||
public static void Info(string text, params object[] args)
|
||||
{
|
||||
if ((PlayFabSettings.LogLevel & PlayFabLogLevel.Info) != 0)
|
||||
{
|
||||
UnityEngine.Debug.Log(PlayFabUtil.timeStamp + " INFO: " + PlayFabUtil.Format(text, args));
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Warning is deprecated.")]
|
||||
public static void Warning(string text, params object[] args)
|
||||
{
|
||||
if ((PlayFabSettings.LogLevel & PlayFabLogLevel.Warning) != 0)
|
||||
{
|
||||
UnityEngine.Debug.LogWarning(PlayFabUtil.timeStamp + " WARNING: " + PlayFabUtil.Format(text, args));
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Error is deprecated.")]
|
||||
public static void Error(string text, params object[] args)
|
||||
{
|
||||
if ((PlayFabSettings.LogLevel & PlayFabLogLevel.Error) != 0)
|
||||
{
|
||||
UnityEngine.Debug.LogError(PlayFabUtil.timeStamp + " ERROR: " + PlayFabUtil.Format(text, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b55790eeab1b3c41a4f1381cbea1213
|
||||
timeCreated: 1462682372
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,808 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace PlayFab
|
||||
{
|
||||
/// <summary>
|
||||
/// Error codes returned by PlayFabAPIs
|
||||
/// </summary>
|
||||
public enum PlayFabErrorCode
|
||||
{
|
||||
Unknown = 1,
|
||||
ConnectionError = 2,
|
||||
JsonParseError = 3,
|
||||
Success = 0,
|
||||
UnkownError = 500,
|
||||
InvalidParams = 1000,
|
||||
AccountNotFound = 1001,
|
||||
AccountBanned = 1002,
|
||||
InvalidUsernameOrPassword = 1003,
|
||||
InvalidTitleId = 1004,
|
||||
InvalidEmailAddress = 1005,
|
||||
EmailAddressNotAvailable = 1006,
|
||||
InvalidUsername = 1007,
|
||||
InvalidPassword = 1008,
|
||||
UsernameNotAvailable = 1009,
|
||||
InvalidSteamTicket = 1010,
|
||||
AccountAlreadyLinked = 1011,
|
||||
LinkedAccountAlreadyClaimed = 1012,
|
||||
InvalidFacebookToken = 1013,
|
||||
AccountNotLinked = 1014,
|
||||
FailedByPaymentProvider = 1015,
|
||||
CouponCodeNotFound = 1016,
|
||||
InvalidContainerItem = 1017,
|
||||
ContainerNotOwned = 1018,
|
||||
KeyNotOwned = 1019,
|
||||
InvalidItemIdInTable = 1020,
|
||||
InvalidReceipt = 1021,
|
||||
ReceiptAlreadyUsed = 1022,
|
||||
ReceiptCancelled = 1023,
|
||||
GameNotFound = 1024,
|
||||
GameModeNotFound = 1025,
|
||||
InvalidGoogleToken = 1026,
|
||||
UserIsNotPartOfDeveloper = 1027,
|
||||
InvalidTitleForDeveloper = 1028,
|
||||
TitleNameConflicts = 1029,
|
||||
UserisNotValid = 1030,
|
||||
ValueAlreadyExists = 1031,
|
||||
BuildNotFound = 1032,
|
||||
PlayerNotInGame = 1033,
|
||||
InvalidTicket = 1034,
|
||||
InvalidDeveloper = 1035,
|
||||
InvalidOrderInfo = 1036,
|
||||
RegistrationIncomplete = 1037,
|
||||
InvalidPlatform = 1038,
|
||||
UnknownError = 1039,
|
||||
SteamApplicationNotOwned = 1040,
|
||||
WrongSteamAccount = 1041,
|
||||
TitleNotActivated = 1042,
|
||||
RegistrationSessionNotFound = 1043,
|
||||
NoSuchMod = 1044,
|
||||
FileNotFound = 1045,
|
||||
DuplicateEmail = 1046,
|
||||
ItemNotFound = 1047,
|
||||
ItemNotOwned = 1048,
|
||||
ItemNotRecycleable = 1049,
|
||||
ItemNotAffordable = 1050,
|
||||
InvalidVirtualCurrency = 1051,
|
||||
WrongVirtualCurrency = 1052,
|
||||
WrongPrice = 1053,
|
||||
NonPositiveValue = 1054,
|
||||
InvalidRegion = 1055,
|
||||
RegionAtCapacity = 1056,
|
||||
ServerFailedToStart = 1057,
|
||||
NameNotAvailable = 1058,
|
||||
InsufficientFunds = 1059,
|
||||
InvalidDeviceID = 1060,
|
||||
InvalidPushNotificationToken = 1061,
|
||||
NoRemainingUses = 1062,
|
||||
InvalidPaymentProvider = 1063,
|
||||
PurchaseInitializationFailure = 1064,
|
||||
DuplicateUsername = 1065,
|
||||
InvalidBuyerInfo = 1066,
|
||||
NoGameModeParamsSet = 1067,
|
||||
BodyTooLarge = 1068,
|
||||
ReservedWordInBody = 1069,
|
||||
InvalidTypeInBody = 1070,
|
||||
InvalidRequest = 1071,
|
||||
ReservedEventName = 1072,
|
||||
InvalidUserStatistics = 1073,
|
||||
NotAuthenticated = 1074,
|
||||
StreamAlreadyExists = 1075,
|
||||
ErrorCreatingStream = 1076,
|
||||
StreamNotFound = 1077,
|
||||
InvalidAccount = 1078,
|
||||
PurchaseDoesNotExist = 1080,
|
||||
InvalidPurchaseTransactionStatus = 1081,
|
||||
APINotEnabledForGameClientAccess = 1082,
|
||||
NoPushNotificationARNForTitle = 1083,
|
||||
BuildAlreadyExists = 1084,
|
||||
BuildPackageDoesNotExist = 1085,
|
||||
CustomAnalyticsEventsNotEnabledForTitle = 1087,
|
||||
InvalidSharedGroupId = 1088,
|
||||
NotAuthorized = 1089,
|
||||
MissingTitleGoogleProperties = 1090,
|
||||
InvalidItemProperties = 1091,
|
||||
InvalidPSNAuthCode = 1092,
|
||||
InvalidItemId = 1093,
|
||||
PushNotEnabledForAccount = 1094,
|
||||
PushServiceError = 1095,
|
||||
ReceiptDoesNotContainInAppItems = 1096,
|
||||
ReceiptContainsMultipleInAppItems = 1097,
|
||||
InvalidBundleID = 1098,
|
||||
JavascriptException = 1099,
|
||||
InvalidSessionTicket = 1100,
|
||||
UnableToConnectToDatabase = 1101,
|
||||
InternalServerError = 1110,
|
||||
InvalidReportDate = 1111,
|
||||
ReportNotAvailable = 1112,
|
||||
DatabaseThroughputExceeded = 1113,
|
||||
InvalidGameTicket = 1115,
|
||||
ExpiredGameTicket = 1116,
|
||||
GameTicketDoesNotMatchLobby = 1117,
|
||||
LinkedDeviceAlreadyClaimed = 1118,
|
||||
DeviceAlreadyLinked = 1119,
|
||||
DeviceNotLinked = 1120,
|
||||
PartialFailure = 1121,
|
||||
PublisherNotSet = 1122,
|
||||
ServiceUnavailable = 1123,
|
||||
VersionNotFound = 1124,
|
||||
RevisionNotFound = 1125,
|
||||
InvalidPublisherId = 1126,
|
||||
DownstreamServiceUnavailable = 1127,
|
||||
APINotIncludedInTitleUsageTier = 1128,
|
||||
DAULimitExceeded = 1129,
|
||||
APIRequestLimitExceeded = 1130,
|
||||
InvalidAPIEndpoint = 1131,
|
||||
BuildNotAvailable = 1132,
|
||||
ConcurrentEditError = 1133,
|
||||
ContentNotFound = 1134,
|
||||
CharacterNotFound = 1135,
|
||||
CloudScriptNotFound = 1136,
|
||||
ContentQuotaExceeded = 1137,
|
||||
InvalidCharacterStatistics = 1138,
|
||||
PhotonNotEnabledForTitle = 1139,
|
||||
PhotonApplicationNotFound = 1140,
|
||||
PhotonApplicationNotAssociatedWithTitle = 1141,
|
||||
InvalidEmailOrPassword = 1142,
|
||||
FacebookAPIError = 1143,
|
||||
InvalidContentType = 1144,
|
||||
KeyLengthExceeded = 1145,
|
||||
DataLengthExceeded = 1146,
|
||||
TooManyKeys = 1147,
|
||||
FreeTierCannotHaveVirtualCurrency = 1148,
|
||||
MissingAmazonSharedKey = 1149,
|
||||
AmazonValidationError = 1150,
|
||||
InvalidPSNIssuerId = 1151,
|
||||
PSNInaccessible = 1152,
|
||||
ExpiredAuthToken = 1153,
|
||||
FailedToGetEntitlements = 1154,
|
||||
FailedToConsumeEntitlement = 1155,
|
||||
TradeAcceptingUserNotAllowed = 1156,
|
||||
TradeInventoryItemIsAssignedToCharacter = 1157,
|
||||
TradeInventoryItemIsBundle = 1158,
|
||||
TradeStatusNotValidForCancelling = 1159,
|
||||
TradeStatusNotValidForAccepting = 1160,
|
||||
TradeDoesNotExist = 1161,
|
||||
TradeCancelled = 1162,
|
||||
TradeAlreadyFilled = 1163,
|
||||
TradeWaitForStatusTimeout = 1164,
|
||||
TradeInventoryItemExpired = 1165,
|
||||
TradeMissingOfferedAndAcceptedItems = 1166,
|
||||
TradeAcceptedItemIsBundle = 1167,
|
||||
TradeAcceptedItemIsStackable = 1168,
|
||||
TradeInventoryItemInvalidStatus = 1169,
|
||||
TradeAcceptedCatalogItemInvalid = 1170,
|
||||
TradeAllowedUsersInvalid = 1171,
|
||||
TradeInventoryItemDoesNotExist = 1172,
|
||||
TradeInventoryItemIsConsumed = 1173,
|
||||
TradeInventoryItemIsStackable = 1174,
|
||||
TradeAcceptedItemsMismatch = 1175,
|
||||
InvalidKongregateToken = 1176,
|
||||
FeatureNotConfiguredForTitle = 1177,
|
||||
NoMatchingCatalogItemForReceipt = 1178,
|
||||
InvalidCurrencyCode = 1179,
|
||||
NoRealMoneyPriceForCatalogItem = 1180,
|
||||
TradeInventoryItemIsNotTradable = 1181,
|
||||
TradeAcceptedCatalogItemIsNotTradable = 1182,
|
||||
UsersAlreadyFriends = 1183,
|
||||
LinkedIdentifierAlreadyClaimed = 1184,
|
||||
CustomIdNotLinked = 1185,
|
||||
TotalDataSizeExceeded = 1186,
|
||||
DeleteKeyConflict = 1187,
|
||||
InvalidXboxLiveToken = 1188,
|
||||
ExpiredXboxLiveToken = 1189,
|
||||
ResettableStatisticVersionRequired = 1190,
|
||||
NotAuthorizedByTitle = 1191,
|
||||
NoPartnerEnabled = 1192,
|
||||
InvalidPartnerResponse = 1193,
|
||||
APINotEnabledForGameServerAccess = 1194,
|
||||
StatisticNotFound = 1195,
|
||||
StatisticNameConflict = 1196,
|
||||
StatisticVersionClosedForWrites = 1197,
|
||||
StatisticVersionInvalid = 1198,
|
||||
APIClientRequestRateLimitExceeded = 1199,
|
||||
InvalidJSONContent = 1200,
|
||||
InvalidDropTable = 1201,
|
||||
StatisticVersionAlreadyIncrementedForScheduledInterval = 1202,
|
||||
StatisticCountLimitExceeded = 1203,
|
||||
StatisticVersionIncrementRateExceeded = 1204,
|
||||
ContainerKeyInvalid = 1205,
|
||||
CloudScriptExecutionTimeLimitExceeded = 1206,
|
||||
NoWritePermissionsForEvent = 1207,
|
||||
CloudScriptFunctionArgumentSizeExceeded = 1208,
|
||||
CloudScriptAPIRequestCountExceeded = 1209,
|
||||
CloudScriptAPIRequestError = 1210,
|
||||
CloudScriptHTTPRequestError = 1211,
|
||||
InsufficientGuildRole = 1212,
|
||||
GuildNotFound = 1213,
|
||||
OverLimit = 1214,
|
||||
EventNotFound = 1215,
|
||||
InvalidEventField = 1216,
|
||||
InvalidEventName = 1217,
|
||||
CatalogNotConfigured = 1218,
|
||||
OperationNotSupportedForPlatform = 1219,
|
||||
SegmentNotFound = 1220,
|
||||
StoreNotFound = 1221,
|
||||
InvalidStatisticName = 1222,
|
||||
TitleNotQualifiedForLimit = 1223,
|
||||
InvalidServiceLimitLevel = 1224,
|
||||
ServiceLimitLevelInTransition = 1225,
|
||||
CouponAlreadyRedeemed = 1226,
|
||||
GameServerBuildSizeLimitExceeded = 1227,
|
||||
GameServerBuildCountLimitExceeded = 1228,
|
||||
VirtualCurrencyCountLimitExceeded = 1229,
|
||||
VirtualCurrencyCodeExists = 1230,
|
||||
TitleNewsItemCountLimitExceeded = 1231,
|
||||
InvalidTwitchToken = 1232,
|
||||
TwitchResponseError = 1233,
|
||||
ProfaneDisplayName = 1234,
|
||||
UserAlreadyAdded = 1235,
|
||||
InvalidVirtualCurrencyCode = 1236,
|
||||
VirtualCurrencyCannotBeDeleted = 1237,
|
||||
IdentifierAlreadyClaimed = 1238,
|
||||
IdentifierNotLinked = 1239,
|
||||
InvalidContinuationToken = 1240,
|
||||
ExpiredContinuationToken = 1241,
|
||||
InvalidSegment = 1242,
|
||||
InvalidSessionId = 1243,
|
||||
SessionLogNotFound = 1244,
|
||||
InvalidSearchTerm = 1245,
|
||||
TwoFactorAuthenticationTokenRequired = 1246,
|
||||
GameServerHostCountLimitExceeded = 1247,
|
||||
PlayerTagCountLimitExceeded = 1248,
|
||||
RequestAlreadyRunning = 1249,
|
||||
ActionGroupNotFound = 1250,
|
||||
MaximumSegmentBulkActionJobsRunning = 1251,
|
||||
NoActionsOnPlayersInSegmentJob = 1252,
|
||||
DuplicateStatisticName = 1253,
|
||||
ScheduledTaskNameConflict = 1254,
|
||||
ScheduledTaskCreateConflict = 1255,
|
||||
InvalidScheduledTaskName = 1256,
|
||||
InvalidTaskSchedule = 1257,
|
||||
SteamNotEnabledForTitle = 1258,
|
||||
LimitNotAnUpgradeOption = 1259,
|
||||
NoSecretKeyEnabledForCloudScript = 1260,
|
||||
TaskNotFound = 1261,
|
||||
TaskInstanceNotFound = 1262,
|
||||
InvalidIdentityProviderId = 1263,
|
||||
MisconfiguredIdentityProvider = 1264,
|
||||
InvalidScheduledTaskType = 1265,
|
||||
BillingInformationRequired = 1266,
|
||||
LimitedEditionItemUnavailable = 1267,
|
||||
InvalidAdPlacementAndReward = 1268,
|
||||
AllAdPlacementViewsAlreadyConsumed = 1269,
|
||||
GoogleOAuthNotConfiguredForTitle = 1270,
|
||||
GoogleOAuthError = 1271,
|
||||
UserNotFriend = 1272,
|
||||
InvalidSignature = 1273,
|
||||
InvalidPublicKey = 1274,
|
||||
GoogleOAuthNoIdTokenIncludedInResponse = 1275,
|
||||
StatisticUpdateInProgress = 1276,
|
||||
LeaderboardVersionNotAvailable = 1277,
|
||||
StatisticAlreadyHasPrizeTable = 1279,
|
||||
PrizeTableHasOverlappingRanks = 1280,
|
||||
PrizeTableHasMissingRanks = 1281,
|
||||
PrizeTableRankStartsAtZero = 1282,
|
||||
InvalidStatistic = 1283,
|
||||
ExpressionParseFailure = 1284,
|
||||
ExpressionInvokeFailure = 1285,
|
||||
ExpressionTooLong = 1286,
|
||||
DataUpdateRateExceeded = 1287,
|
||||
RestrictedEmailDomain = 1288,
|
||||
EncryptionKeyDisabled = 1289,
|
||||
EncryptionKeyMissing = 1290,
|
||||
EncryptionKeyBroken = 1291,
|
||||
NoSharedSecretKeyConfigured = 1292,
|
||||
SecretKeyNotFound = 1293,
|
||||
PlayerSecretAlreadyConfigured = 1294,
|
||||
APIRequestsDisabledForTitle = 1295,
|
||||
InvalidSharedSecretKey = 1296,
|
||||
PrizeTableHasNoRanks = 1297,
|
||||
ProfileDoesNotExist = 1298,
|
||||
ContentS3OriginBucketNotConfigured = 1299,
|
||||
InvalidEnvironmentForReceipt = 1300,
|
||||
EncryptedRequestNotAllowed = 1301,
|
||||
SignedRequestNotAllowed = 1302,
|
||||
RequestViewConstraintParamsNotAllowed = 1303,
|
||||
BadPartnerConfiguration = 1304,
|
||||
XboxBPCertificateFailure = 1305,
|
||||
XboxXASSExchangeFailure = 1306,
|
||||
InvalidEntityId = 1307,
|
||||
StatisticValueAggregationOverflow = 1308,
|
||||
EmailMessageFromAddressIsMissing = 1309,
|
||||
EmailMessageToAddressIsMissing = 1310,
|
||||
SmtpServerAuthenticationError = 1311,
|
||||
SmtpServerLimitExceeded = 1312,
|
||||
SmtpServerInsufficientStorage = 1313,
|
||||
SmtpServerCommunicationError = 1314,
|
||||
SmtpServerGeneralFailure = 1315,
|
||||
EmailClientTimeout = 1316,
|
||||
EmailClientCanceledTask = 1317,
|
||||
EmailTemplateMissing = 1318,
|
||||
InvalidHostForTitleId = 1319,
|
||||
EmailConfirmationTokenDoesNotExist = 1320,
|
||||
EmailConfirmationTokenExpired = 1321,
|
||||
AccountDeleted = 1322,
|
||||
PlayerSecretNotConfigured = 1323,
|
||||
InvalidSignatureTime = 1324,
|
||||
NoContactEmailAddressFound = 1325,
|
||||
InvalidAuthToken = 1326,
|
||||
AuthTokenDoesNotExist = 1327,
|
||||
AuthTokenExpired = 1328,
|
||||
AuthTokenAlreadyUsedToResetPassword = 1329,
|
||||
MembershipNameTooLong = 1330,
|
||||
MembershipNotFound = 1331,
|
||||
GoogleServiceAccountInvalid = 1332,
|
||||
GoogleServiceAccountParseFailure = 1333,
|
||||
EntityTokenMissing = 1334,
|
||||
EntityTokenInvalid = 1335,
|
||||
EntityTokenExpired = 1336,
|
||||
EntityTokenRevoked = 1337,
|
||||
InvalidProductForSubscription = 1338,
|
||||
XboxInaccessible = 1339,
|
||||
SubscriptionAlreadyTaken = 1340,
|
||||
SmtpAddonNotEnabled = 1341,
|
||||
APIConcurrentRequestLimitExceeded = 1342,
|
||||
XboxRejectedXSTSExchangeRequest = 1343,
|
||||
VariableNotDefined = 1344,
|
||||
TemplateVersionNotDefined = 1345,
|
||||
FileTooLarge = 1346,
|
||||
TitleDeleted = 1347,
|
||||
TitleContainsUserAccounts = 1348,
|
||||
TitleDeletionPlayerCleanupFailure = 1349,
|
||||
EntityFileOperationPending = 1350,
|
||||
NoEntityFileOperationPending = 1351,
|
||||
EntityProfileVersionMismatch = 1352,
|
||||
TemplateVersionTooOld = 1353,
|
||||
MembershipDefinitionInUse = 1354,
|
||||
PaymentPageNotConfigured = 1355,
|
||||
FailedLoginAttemptRateLimitExceeded = 1356,
|
||||
EntityBlockedByGroup = 1357,
|
||||
RoleDoesNotExist = 1358,
|
||||
EntityIsAlreadyMember = 1359,
|
||||
DuplicateRoleId = 1360,
|
||||
GroupInvitationNotFound = 1361,
|
||||
GroupApplicationNotFound = 1362,
|
||||
OutstandingInvitationAcceptedInstead = 1363,
|
||||
OutstandingApplicationAcceptedInstead = 1364,
|
||||
RoleIsGroupDefaultMember = 1365,
|
||||
RoleIsGroupAdmin = 1366,
|
||||
RoleNameNotAvailable = 1367,
|
||||
GroupNameNotAvailable = 1368,
|
||||
EmailReportAlreadySent = 1369,
|
||||
EmailReportRecipientBlacklisted = 1370,
|
||||
EventNamespaceNotAllowed = 1371,
|
||||
EventEntityNotAllowed = 1372,
|
||||
InvalidEntityType = 1373,
|
||||
NullTokenResultFromAad = 1374,
|
||||
InvalidTokenResultFromAad = 1375,
|
||||
NoValidCertificateForAad = 1376,
|
||||
InvalidCertificateForAad = 1377,
|
||||
DuplicateDropTableId = 1378,
|
||||
MultiplayerServerError = 1379,
|
||||
MultiplayerServerTooManyRequests = 1380,
|
||||
MultiplayerServerNoContent = 1381,
|
||||
MultiplayerServerBadRequest = 1382,
|
||||
MultiplayerServerUnauthorized = 1383,
|
||||
MultiplayerServerForbidden = 1384,
|
||||
MultiplayerServerNotFound = 1385,
|
||||
MultiplayerServerConflict = 1386,
|
||||
MultiplayerServerInternalServerError = 1387,
|
||||
MultiplayerServerUnavailable = 1388,
|
||||
ExplicitContentDetected = 1389,
|
||||
PIIContentDetected = 1390,
|
||||
InvalidScheduledTaskParameter = 1391,
|
||||
PerEntityEventRateLimitExceeded = 1392,
|
||||
TitleDefaultLanguageNotSet = 1393,
|
||||
EmailTemplateMissingDefaultVersion = 1394,
|
||||
FacebookInstantGamesIdNotLinked = 1395,
|
||||
InvalidFacebookInstantGamesSignature = 1396,
|
||||
FacebookInstantGamesAuthNotConfiguredForTitle = 1397,
|
||||
EntityProfileConstraintValidationFailed = 1398,
|
||||
TelemetryIngestionKeyPending = 1399,
|
||||
TelemetryIngestionKeyNotFound = 1400,
|
||||
StatisticChildNameInvalid = 1402,
|
||||
DataIntegrityError = 1403,
|
||||
VirtualCurrencyCannotBeSetToOlderVersion = 1404,
|
||||
VirtualCurrencyMustBeWithinIntegerRange = 1405,
|
||||
EmailTemplateInvalidSyntax = 1406,
|
||||
EmailTemplateMissingCallback = 1407,
|
||||
PushNotificationTemplateInvalidPayload = 1408,
|
||||
InvalidLocalizedPushNotificationLanguage = 1409,
|
||||
MissingLocalizedPushNotificationMessage = 1410,
|
||||
PushNotificationTemplateMissingPlatformPayload = 1411,
|
||||
PushNotificationTemplatePayloadContainsInvalidJson = 1412,
|
||||
PushNotificationTemplateContainsInvalidIosPayload = 1413,
|
||||
PushNotificationTemplateContainsInvalidAndroidPayload = 1414,
|
||||
PushNotificationTemplateIosPayloadMissingNotificationBody = 1415,
|
||||
PushNotificationTemplateAndroidPayloadMissingNotificationBody = 1416,
|
||||
PushNotificationTemplateNotFound = 1417,
|
||||
PushNotificationTemplateMissingDefaultVersion = 1418,
|
||||
PushNotificationTemplateInvalidSyntax = 1419,
|
||||
PushNotificationTemplateNoCustomPayloadForV1 = 1420,
|
||||
NoLeaderboardForStatistic = 1421,
|
||||
TitleNewsMissingDefaultLanguage = 1422,
|
||||
TitleNewsNotFound = 1423,
|
||||
TitleNewsDuplicateLanguage = 1424,
|
||||
TitleNewsMissingTitleOrBody = 1425,
|
||||
TitleNewsInvalidLanguage = 1426,
|
||||
EmailRecipientBlacklisted = 1427,
|
||||
InvalidGameCenterAuthRequest = 1428,
|
||||
GameCenterAuthenticationFailed = 1429,
|
||||
CannotEnablePartiesForTitle = 1430,
|
||||
PartyError = 1431,
|
||||
PartyRequests = 1432,
|
||||
PartyNoContent = 1433,
|
||||
PartyBadRequest = 1434,
|
||||
PartyUnauthorized = 1435,
|
||||
PartyForbidden = 1436,
|
||||
PartyNotFound = 1437,
|
||||
PartyConflict = 1438,
|
||||
PartyInternalServerError = 1439,
|
||||
PartyUnavailable = 1440,
|
||||
PartyTooManyRequests = 1441,
|
||||
PushNotificationTemplateMissingName = 1442,
|
||||
CannotEnableMultiplayerServersForTitle = 1443,
|
||||
WriteAttemptedDuringExport = 1444,
|
||||
MultiplayerServerTitleQuotaCoresExceeded = 1445,
|
||||
AutomationRuleNotFound = 1446,
|
||||
EntityAPIKeyLimitExceeded = 1447,
|
||||
EntityAPIKeyNotFound = 1448,
|
||||
EntityAPIKeyOrSecretInvalid = 1449,
|
||||
EconomyServiceUnavailable = 1450,
|
||||
EconomyServiceInternalError = 1451,
|
||||
QueryRateLimitExceeded = 1452,
|
||||
EntityAPIKeyCreationDisabledForEntity = 1453,
|
||||
ForbiddenByEntityPolicy = 1454,
|
||||
UpdateInventoryRateLimitExceeded = 1455,
|
||||
StudioCreationRateLimited = 1456,
|
||||
StudioCreationInProgress = 1457,
|
||||
DuplicateStudioName = 1458,
|
||||
StudioNotFound = 1459,
|
||||
StudioDeleted = 1460,
|
||||
StudioDeactivated = 1461,
|
||||
StudioActivated = 1462,
|
||||
TitleCreationRateLimited = 1463,
|
||||
TitleCreationInProgress = 1464,
|
||||
DuplicateTitleName = 1465,
|
||||
TitleActivationRateLimited = 1466,
|
||||
TitleActivationInProgress = 1467,
|
||||
TitleDeactivated = 1468,
|
||||
TitleActivated = 1469,
|
||||
CloudScriptAzureFunctionsExecutionTimeLimitExceeded = 1470,
|
||||
CloudScriptAzureFunctionsArgumentSizeExceeded = 1471,
|
||||
CloudScriptAzureFunctionsReturnSizeExceeded = 1472,
|
||||
CloudScriptAzureFunctionsHTTPRequestError = 1473,
|
||||
VirtualCurrencyBetaGetError = 1474,
|
||||
VirtualCurrencyBetaCreateError = 1475,
|
||||
VirtualCurrencyBetaInitialDepositSaveError = 1476,
|
||||
VirtualCurrencyBetaSaveError = 1477,
|
||||
VirtualCurrencyBetaDeleteError = 1478,
|
||||
VirtualCurrencyBetaRestoreError = 1479,
|
||||
VirtualCurrencyBetaSaveConflict = 1480,
|
||||
VirtualCurrencyBetaUpdateError = 1481,
|
||||
InsightsManagementDatabaseNotFound = 1482,
|
||||
InsightsManagementOperationNotFound = 1483,
|
||||
InsightsManagementErrorPendingOperationExists = 1484,
|
||||
InsightsManagementSetPerformanceLevelInvalidParameter = 1485,
|
||||
InsightsManagementSetStorageRetentionInvalidParameter = 1486,
|
||||
InsightsManagementGetStorageUsageInvalidParameter = 1487,
|
||||
InsightsManagementGetOperationStatusInvalidParameter = 1488,
|
||||
DuplicatePurchaseTransactionId = 1489,
|
||||
EvaluationModePlayerCountExceeded = 1490,
|
||||
GetPlayersInSegmentRateLimitExceeded = 1491,
|
||||
CloudScriptFunctionNameSizeExceeded = 1492,
|
||||
PaidInsightsFeaturesNotEnabled = 1493,
|
||||
CloudScriptAzureFunctionsQueueRequestError = 1494,
|
||||
EvaluationModeTitleCountExceeded = 1495,
|
||||
InsightsManagementTitleNotInFlight = 1496,
|
||||
LimitNotFound = 1497,
|
||||
LimitNotAvailableViaAPI = 1498,
|
||||
InsightsManagementSetStorageRetentionBelowMinimum = 1499,
|
||||
InsightsManagementSetStorageRetentionAboveMaximum = 1500,
|
||||
AppleNotEnabledForTitle = 1501,
|
||||
InsightsManagementNewActiveEventExportLimitInvalid = 1502,
|
||||
InsightsManagementSetPerformanceRateLimited = 1503,
|
||||
PartyRequestsThrottledFromRateLimiter = 1504,
|
||||
XboxServiceTooManyRequests = 1505,
|
||||
NintendoSwitchNotEnabledForTitle = 1506,
|
||||
RequestMultiplayerServersThrottledFromRateLimiter = 1507,
|
||||
TitleDataOverrideNotFound = 1508,
|
||||
DuplicateKeys = 1509,
|
||||
WasNotCreatedWithCloudRoot = 1510,
|
||||
LegacyMultiplayerServersDeprecated = 1511,
|
||||
VirtualCurrencyCurrentlyUnavailable = 1512,
|
||||
SteamUserNotFound = 1513,
|
||||
ElasticSearchOperationFailed = 1514,
|
||||
NotImplemented = 1515,
|
||||
PublisherNotFound = 1516,
|
||||
PublisherDeleted = 1517,
|
||||
ApiDisabledForMigration = 1518,
|
||||
ResourceNameUpdateNotAllowed = 1519,
|
||||
ApiNotEnabledForTitle = 1520,
|
||||
DuplicateTitleNameForPublisher = 1521,
|
||||
AzureTitleCreationInProgress = 1522,
|
||||
TitleConstraintsPublisherDeletion = 1524,
|
||||
InvalidPlayerAccountPoolId = 1525,
|
||||
PlayerAccountPoolNotFound = 1526,
|
||||
PlayerAccountPoolDeleted = 1527,
|
||||
TitleCleanupInProgress = 1528,
|
||||
AzureResourceConcurrentOperationInProgress = 1529,
|
||||
TitlePublisherUpdateNotAllowed = 1530,
|
||||
AzureResourceManagerNotSupportedInStamp = 1531,
|
||||
ApiNotIncludedInAzurePlayFabFeatureSet = 1532,
|
||||
GoogleServiceAccountFailedAuth = 1533,
|
||||
GoogleAPIServiceUnavailable = 1534,
|
||||
GoogleAPIServiceUnknownError = 1535,
|
||||
NoValidIdentityForAad = 1536,
|
||||
PlayerIdentityLinkNotFound = 1537,
|
||||
PhotonApplicationIdAlreadyInUse = 1538,
|
||||
CloudScriptUnableToDeleteProductionRevision = 1539,
|
||||
CustomIdNotFound = 1540,
|
||||
AutomationInvalidInput = 1541,
|
||||
AutomationInvalidRuleName = 1542,
|
||||
AutomationRuleAlreadyExists = 1543,
|
||||
AutomationRuleLimitExceeded = 1544,
|
||||
InvalidGooglePlayGamesServerAuthCode = 1545,
|
||||
PlayStreamConnectionFailed = 1547,
|
||||
InvalidEventContents = 1548,
|
||||
InsightsV1Deprecated = 1549,
|
||||
AnalysisSubscriptionNotFound = 1550,
|
||||
AnalysisSubscriptionFailed = 1551,
|
||||
AnalysisSubscriptionFoundAlready = 1552,
|
||||
AnalysisSubscriptionManagementInvalidInput = 1553,
|
||||
InvalidGameCenterId = 1554,
|
||||
InvalidNintendoSwitchAccountId = 1555,
|
||||
EntityAPIKeysNotSupported = 1556,
|
||||
IpAddressBanned = 1557,
|
||||
EntityLineageBanned = 1558,
|
||||
NamespaceMismatch = 1559,
|
||||
InvalidServiceConfiguration = 1560,
|
||||
InvalidNamespaceMismatch = 1561,
|
||||
MatchmakingEntityInvalid = 2001,
|
||||
MatchmakingPlayerAttributesInvalid = 2002,
|
||||
MatchmakingQueueNotFound = 2016,
|
||||
MatchmakingMatchNotFound = 2017,
|
||||
MatchmakingTicketNotFound = 2018,
|
||||
MatchmakingAlreadyJoinedTicket = 2028,
|
||||
MatchmakingTicketAlreadyCompleted = 2029,
|
||||
MatchmakingQueueConfigInvalid = 2031,
|
||||
MatchmakingMemberProfileInvalid = 2032,
|
||||
NintendoSwitchDeviceIdNotLinked = 2034,
|
||||
MatchmakingNotEnabled = 2035,
|
||||
MatchmakingPlayerAttributesTooLarge = 2043,
|
||||
MatchmakingNumberOfPlayersInTicketTooLarge = 2044,
|
||||
MatchmakingAttributeInvalid = 2046,
|
||||
MatchmakingPlayerHasNotJoinedTicket = 2053,
|
||||
MatchmakingRateLimitExceeded = 2054,
|
||||
MatchmakingTicketMembershipLimitExceeded = 2055,
|
||||
MatchmakingUnauthorized = 2056,
|
||||
MatchmakingQueueLimitExceeded = 2057,
|
||||
MatchmakingRequestTypeMismatch = 2058,
|
||||
MatchmakingBadRequest = 2059,
|
||||
PubSubFeatureNotEnabledForTitle = 2500,
|
||||
PubSubTooManyRequests = 2501,
|
||||
PubSubConnectionNotFoundForEntity = 2502,
|
||||
PubSubConnectionHandleInvalid = 2503,
|
||||
PubSubSubscriptionLimitExceeded = 2504,
|
||||
TitleConfigNotFound = 3001,
|
||||
TitleConfigUpdateConflict = 3002,
|
||||
TitleConfigSerializationError = 3003,
|
||||
CatalogApiNotImplemented = 4000,
|
||||
CatalogEntityInvalid = 4001,
|
||||
CatalogTitleIdMissing = 4002,
|
||||
CatalogPlayerIdMissing = 4003,
|
||||
CatalogClientIdentityInvalid = 4004,
|
||||
CatalogOneOrMoreFilesInvalid = 4005,
|
||||
CatalogItemMetadataInvalid = 4006,
|
||||
CatalogItemIdInvalid = 4007,
|
||||
CatalogSearchParameterInvalid = 4008,
|
||||
CatalogFeatureDisabled = 4009,
|
||||
CatalogConfigInvalid = 4010,
|
||||
CatalogItemTypeInvalid = 4012,
|
||||
CatalogBadRequest = 4013,
|
||||
CatalogTooManyRequests = 4014,
|
||||
ExportInvalidStatusUpdate = 5000,
|
||||
ExportInvalidPrefix = 5001,
|
||||
ExportBlobContainerDoesNotExist = 5002,
|
||||
ExportNotFound = 5004,
|
||||
ExportCouldNotUpdate = 5005,
|
||||
ExportInvalidStorageType = 5006,
|
||||
ExportAmazonBucketDoesNotExist = 5007,
|
||||
ExportInvalidBlobStorage = 5008,
|
||||
ExportKustoException = 5009,
|
||||
ExportKustoConnectionFailed = 5012,
|
||||
ExportUnknownError = 5013,
|
||||
ExportCantEditPendingExport = 5014,
|
||||
ExportLimitExports = 5015,
|
||||
ExportLimitEvents = 5016,
|
||||
ExportInvalidPartitionStatusModification = 5017,
|
||||
ExportCouldNotCreate = 5018,
|
||||
ExportNoBackingDatabaseFound = 5019,
|
||||
ExportCouldNotDelete = 5020,
|
||||
ExportCannotDetermineEventQuery = 5021,
|
||||
ExportInvalidQuerySchemaModification = 5022,
|
||||
ExportQuerySchemaMissingRequiredColumns = 5023,
|
||||
ExportCannotParseQuery = 5024,
|
||||
ExportControlCommandsNotAllowed = 5025,
|
||||
ExportQueryMissingTableReference = 5026,
|
||||
ExportInsightsV1Deprecated = 5027,
|
||||
ExplorerBasicInvalidQueryName = 5100,
|
||||
ExplorerBasicInvalidQueryDescription = 5101,
|
||||
ExplorerBasicInvalidQueryConditions = 5102,
|
||||
ExplorerBasicInvalidQueryStartDate = 5103,
|
||||
ExplorerBasicInvalidQueryEndDate = 5104,
|
||||
ExplorerBasicInvalidQueryGroupBy = 5105,
|
||||
ExplorerBasicInvalidQueryAggregateType = 5106,
|
||||
ExplorerBasicInvalidQueryAggregateProperty = 5107,
|
||||
ExplorerBasicLoadQueriesError = 5108,
|
||||
ExplorerBasicLoadQueryError = 5109,
|
||||
ExplorerBasicCreateQueryError = 5110,
|
||||
ExplorerBasicDeleteQueryError = 5111,
|
||||
ExplorerBasicUpdateQueryError = 5112,
|
||||
ExplorerBasicSavedQueriesLimit = 5113,
|
||||
ExplorerBasicSavedQueryNotFound = 5114,
|
||||
TenantShardMapperShardNotFound = 5500,
|
||||
TitleNotEnabledForParty = 6000,
|
||||
PartyVersionNotFound = 6001,
|
||||
MultiplayerServerBuildReferencedByMatchmakingQueue = 6002,
|
||||
MultiplayerServerBuildReferencedByBuildAlias = 6003,
|
||||
MultiplayerServerBuildAliasReferencedByMatchmakingQueue = 6004,
|
||||
ExperimentationExperimentStopped = 7000,
|
||||
ExperimentationExperimentRunning = 7001,
|
||||
ExperimentationExperimentNotFound = 7002,
|
||||
ExperimentationExperimentNeverStarted = 7003,
|
||||
ExperimentationExperimentDeleted = 7004,
|
||||
ExperimentationClientTimeout = 7005,
|
||||
ExperimentationInvalidVariantConfiguration = 7006,
|
||||
ExperimentationInvalidVariableConfiguration = 7007,
|
||||
ExperimentInvalidId = 7008,
|
||||
ExperimentationNoScorecard = 7009,
|
||||
ExperimentationTreatmentAssignmentFailed = 7010,
|
||||
ExperimentationTreatmentAssignmentDisabled = 7011,
|
||||
ExperimentationInvalidDuration = 7012,
|
||||
ExperimentationMaxExperimentsReached = 7013,
|
||||
ExperimentationExperimentSchedulingInProgress = 7014,
|
||||
ExperimentationInvalidEndDate = 7015,
|
||||
ExperimentationInvalidStartDate = 7016,
|
||||
ExperimentationMaxDurationExceeded = 7017,
|
||||
ExperimentationExclusionGroupNotFound = 7018,
|
||||
ExperimentationExclusionGroupInsufficientCapacity = 7019,
|
||||
ExperimentationExclusionGroupCannotDelete = 7020,
|
||||
ExperimentationExclusionGroupInvalidTrafficAllocation = 7021,
|
||||
ExperimentationExclusionGroupInvalidName = 7022,
|
||||
MaxActionDepthExceeded = 8000,
|
||||
TitleNotOnUpdatedPricingPlan = 9000,
|
||||
SegmentManagementTitleNotInFlight = 10000,
|
||||
SegmentManagementNoExpressionTree = 10001,
|
||||
SegmentManagementTriggerActionCountOverLimit = 10002,
|
||||
SegmentManagementSegmentCountOverLimit = 10003,
|
||||
SegmentManagementInvalidSegmentId = 10004,
|
||||
SegmentManagementInvalidInput = 10005,
|
||||
SegmentManagementInvalidSegmentName = 10006,
|
||||
DeleteSegmentRateLimitExceeded = 10007,
|
||||
CreateSegmentRateLimitExceeded = 10008,
|
||||
UpdateSegmentRateLimitExceeded = 10009,
|
||||
GetSegmentsRateLimitExceeded = 10010,
|
||||
AsyncExportNotInFlight = 10011,
|
||||
AsyncExportNotFound = 10012,
|
||||
AsyncExportRateLimitExceeded = 10013,
|
||||
AnalyticsSegmentCountOverLimit = 10014,
|
||||
SnapshotNotFound = 11000,
|
||||
InventoryApiNotImplemented = 12000,
|
||||
LobbyDoesNotExist = 13000,
|
||||
LobbyRateLimitExceeded = 13001,
|
||||
LobbyPlayerAlreadyJoined = 13002,
|
||||
LobbyNotJoinable = 13003,
|
||||
LobbyMemberCannotRejoin = 13004,
|
||||
LobbyCurrentPlayersMoreThanMaxPlayers = 13005,
|
||||
LobbyPlayerNotPresent = 13006,
|
||||
LobbyBadRequest = 13007,
|
||||
LobbyPlayerMaxLobbyLimitExceeded = 13008,
|
||||
LobbyNewOwnerMustBeConnected = 13009,
|
||||
LobbyCurrentOwnerStillConnected = 13010,
|
||||
LobbyMemberIsNotOwner = 13011,
|
||||
EventSamplingInvalidRatio = 14000,
|
||||
EventSamplingInvalidEventNamespace = 14001,
|
||||
EventSamplingInvalidEventName = 14002,
|
||||
EventSamplingRatioNotFound = 14003,
|
||||
TelemetryKeyNotFound = 14200,
|
||||
TelemetryKeyInvalidName = 14201,
|
||||
TelemetryKeyAlreadyExists = 14202,
|
||||
TelemetryKeyInvalid = 14203,
|
||||
TelemetryKeyCountOverLimit = 14204,
|
||||
TelemetryKeyDeactivated = 14205,
|
||||
TelemetryKeyLongInsightsRetentionNotAllowed = 14206,
|
||||
EventSinkConnectionInvalid = 15000,
|
||||
EventSinkConnectionUnauthorized = 15001,
|
||||
EventSinkRegionInvalid = 15002,
|
||||
EventSinkLimitExceeded = 15003,
|
||||
EventSinkSasTokenInvalid = 15004,
|
||||
EventSinkNotFound = 15005,
|
||||
EventSinkNameInvalid = 15006,
|
||||
EventSinkSasTokenPermissionInvalid = 15007,
|
||||
EventSinkSecretInvalid = 15008,
|
||||
EventSinkTenantNotFound = 15009,
|
||||
EventSinkAadNotFound = 15010,
|
||||
EventSinkDatabaseNotFound = 15011,
|
||||
OperationCanceled = 16000,
|
||||
InvalidDisplayNameRandomSuffixLength = 17000,
|
||||
AllowNonUniquePlayerDisplayNamesDisableNotAllowed = 17001,
|
||||
PartitionedEventInvalid = 18000,
|
||||
PartitionedEventCountOverLimit = 18001,
|
||||
PlayerCustomPropertiesPropertyNameTooLong = 19000,
|
||||
PlayerCustomPropertiesPropertyNameIsInvalid = 19001,
|
||||
PlayerCustomPropertiesStringPropertyValueTooLong = 19002,
|
||||
PlayerCustomPropertiesValueIsInvalidType = 19003,
|
||||
PlayerCustomPropertiesVersionMismatch = 19004,
|
||||
PlayerCustomPropertiesPropertyCountTooHigh = 19005,
|
||||
PlayerCustomPropertiesDuplicatePropertyName = 19006,
|
||||
PlayerCustomPropertiesPropertyDoesNotExist = 19007
|
||||
}
|
||||
|
||||
public class PlayFabError
|
||||
{
|
||||
public string ApiEndpoint;
|
||||
public int HttpCode;
|
||||
public string HttpStatus;
|
||||
public PlayFabErrorCode Error;
|
||||
public string ErrorMessage;
|
||||
public Dictionary<string, List<string>> ErrorDetails;
|
||||
public object CustomData;
|
||||
public uint? RetryAfterSeconds = null;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return GenerateErrorReport();
|
||||
}
|
||||
|
||||
[ThreadStatic]
|
||||
private static StringBuilder _tempSb;
|
||||
/// <summary>
|
||||
/// This converts the PlayFabError into a human readable string describing the error.
|
||||
/// If error is not found, it will return the http code, status, and error
|
||||
/// </summary>
|
||||
/// <returns>A description of the error that we just incur.</returns>
|
||||
public string GenerateErrorReport()
|
||||
{
|
||||
if (_tempSb == null)
|
||||
_tempSb = new StringBuilder();
|
||||
_tempSb.Length = 0;
|
||||
if (String.IsNullOrEmpty(ErrorMessage))
|
||||
{
|
||||
_tempSb.Append(ApiEndpoint).Append(": ").Append("Http Code: ").Append(HttpCode.ToString()).Append("\nHttp Status: ").Append(HttpStatus).Append("\nError: ").Append(Error.ToString()).Append("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
_tempSb.Append(ApiEndpoint).Append(": ").Append(ErrorMessage);
|
||||
}
|
||||
|
||||
if (ErrorDetails != null)
|
||||
foreach (var pair in ErrorDetails)
|
||||
foreach (var msg in pair.Value)
|
||||
_tempSb.Append("\n").Append(pair.Key).Append(": ").Append(msg);
|
||||
return _tempSb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class PlayFabException : Exception
|
||||
{
|
||||
public readonly PlayFabExceptionCode Code;
|
||||
public PlayFabException(PlayFabExceptionCode code, string message) : base(message)
|
||||
{
|
||||
Code = code;
|
||||
}
|
||||
}
|
||||
|
||||
public enum PlayFabExceptionCode
|
||||
{
|
||||
AuthContextRequired,
|
||||
BuildError,
|
||||
DeveloperKeyNotSet,
|
||||
EntityTokenNotSet,
|
||||
NotLoggedIn,
|
||||
TitleNotSet,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed146f2193bb8ef49ad1200eefdab503
|
||||
timeCreated: 1468524876
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6de758a294727f04c82bf319fdd54c60
|
||||
folderAsset: yes
|
||||
timeCreated: 1462746198
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using PlayFab.SharedModels;
|
||||
|
||||
namespace PlayFab.Internal
|
||||
{
|
||||
public enum AuthType
|
||||
{
|
||||
None,
|
||||
PreLoginSession, // Not yet defined
|
||||
LoginSession, // "X-Authorization"
|
||||
DevSecretKey, // "X-SecretKey"
|
||||
EntityToken, // "X-EntityToken"
|
||||
}
|
||||
|
||||
public enum HttpRequestState
|
||||
{
|
||||
Sent,
|
||||
Received,
|
||||
Idle,
|
||||
Error
|
||||
}
|
||||
|
||||
public class CallRequestContainer
|
||||
{
|
||||
#if !UNITY_WSA && !UNITY_WP8
|
||||
public HttpRequestState HttpState = HttpRequestState.Idle;
|
||||
public System.Net.HttpWebRequest HttpRequest = null;
|
||||
#endif
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
public PlayFabHttp.RequestTiming Timing;
|
||||
public System.Diagnostics.Stopwatch Stopwatch;
|
||||
#endif
|
||||
|
||||
// This class stores the state of the request and all associated data
|
||||
public string ApiEndpoint = null;
|
||||
public string FullUrl = null;
|
||||
public byte[] Payload = null;
|
||||
public string JsonResponse = null;
|
||||
public PlayFabRequestCommon ApiRequest;
|
||||
public Dictionary<string, string> RequestHeaders;
|
||||
public PlayFabResultCommon ApiResult;
|
||||
public PlayFabError Error;
|
||||
public Action DeserializeResultJson;
|
||||
public Action InvokeSuccessCallback;
|
||||
public Action<PlayFabError> ErrorCallback;
|
||||
public object CustomData = null;
|
||||
public PlayFabApiSettings settings;
|
||||
public PlayFabAuthenticationContext context;
|
||||
public IPlayFabInstanceApi instanceApi;
|
||||
public bool CalledGetResponse = false;
|
||||
|
||||
public CallRequestContainer()
|
||||
{
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
Stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aeac58284b4b1cd4ab93ab0e71ba8540
|
||||
timeCreated: 1462745280
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,500 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using PlayFab.Public;
|
||||
using PlayFab.SharedModels;
|
||||
using UnityEngine;
|
||||
|
||||
namespace PlayFab.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a wrapper for Http So we can better separate the functionaity of Http Requests delegated to WWW or HttpWebRequest
|
||||
/// </summary>
|
||||
public class PlayFabHttp : SingletonMonoBehaviour<PlayFabHttp>
|
||||
{
|
||||
private static List<CallRequestContainer> _apiCallQueue = new List<CallRequestContainer>(); // Starts initialized, and is nulled when it's flushed
|
||||
|
||||
public delegate void ApiProcessingEvent<in TEventArgs>(TEventArgs e);
|
||||
public delegate void ApiProcessErrorEvent(PlayFabRequestCommon request, PlayFabError error);
|
||||
public static event ApiProcessingEvent<ApiProcessingEventArgs> ApiProcessingEventHandler;
|
||||
public static event ApiProcessErrorEvent ApiProcessingErrorEventHandler;
|
||||
public static readonly Dictionary<string, string> GlobalHeaderInjection = new Dictionary<string, string>();
|
||||
|
||||
private static IPlayFabLogger _logger;
|
||||
#if !DISABLE_PLAYFABENTITY_API && !DISABLE_PLAYFABCLIENT_API
|
||||
private static IScreenTimeTracker screenTimeTracker = new ScreenTimeTracker();
|
||||
private const float delayBetweenBatches = 5.0f;
|
||||
#endif
|
||||
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
public struct RequestTiming
|
||||
{
|
||||
public DateTime StartTimeUtc;
|
||||
public string ApiEndpoint;
|
||||
public int WorkerRequestMs;
|
||||
public int MainThreadRequestMs;
|
||||
}
|
||||
|
||||
public delegate void ApiRequestTimingEvent(RequestTiming time);
|
||||
public static event ApiRequestTimingEvent ApiRequestTimingEventHandler;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Return the number of api calls that are waiting for results from the server
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static int GetPendingMessages()
|
||||
{
|
||||
var transport = PluginManager.GetPlugin<ITransportPlugin>(PluginContract.PlayFab_Transport);
|
||||
return transport.IsInitialized ? transport.GetPendingMessages() : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This initializes the GameObject and ensures it is in the scene.
|
||||
/// </summary>
|
||||
public static void InitializeHttp()
|
||||
{
|
||||
if (string.IsNullOrEmpty(PlayFabSettings.TitleId))
|
||||
throw new PlayFabException(PlayFabExceptionCode.TitleNotSet, "You must set PlayFabSettings.TitleId before making API Calls.");
|
||||
var transport = PluginManager.GetPlugin<ITransportPlugin>(PluginContract.PlayFab_Transport);
|
||||
if (transport.IsInitialized)
|
||||
return;
|
||||
|
||||
transport.Initialize();
|
||||
CreateInstance(); // Invoke the SingletonMonoBehaviour
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This initializes the GameObject and ensures it is in the scene.
|
||||
/// </summary>
|
||||
public static void InitializeLogger(IPlayFabLogger setLogger = null)
|
||||
{
|
||||
if (_logger != null)
|
||||
throw new InvalidOperationException("Once initialized, the logger cannot be reset.");
|
||||
if (setLogger == null)
|
||||
setLogger = new PlayFabLogger();
|
||||
_logger = setLogger;
|
||||
}
|
||||
|
||||
#if !DISABLE_PLAYFABENTITY_API && !DISABLE_PLAYFABCLIENT_API
|
||||
/// <summary>
|
||||
/// This initializes ScreenTimeTracker object and notifying it to start sending info.
|
||||
/// </summary>
|
||||
/// <param name="playFabUserId">Result of the user's login, represent user ID</param>
|
||||
public static void InitializeScreenTimeTracker(string entityId, string entityType, string playFabUserId)
|
||||
{
|
||||
screenTimeTracker.ClientSessionStart(entityId, entityType, playFabUserId);
|
||||
instance.StartCoroutine(SendScreenTimeEvents(delayBetweenBatches));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function will send Screen Time events on a periodic basis.
|
||||
/// </summary>
|
||||
/// <param name="secondsBetweenBatches">Delay between batches, in seconds</param>
|
||||
private static IEnumerator SendScreenTimeEvents(float secondsBetweenBatches)
|
||||
{
|
||||
WaitForSeconds delay = new WaitForSeconds(secondsBetweenBatches);
|
||||
|
||||
while (!PlayFabSettings.DisableFocusTimeCollection)
|
||||
{
|
||||
screenTimeTracker.Send();
|
||||
yield return delay;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void SimpleGetCall(string fullUrl, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
InitializeHttp();
|
||||
PluginManager.GetPlugin<ITransportPlugin>(PluginContract.PlayFab_Transport).SimpleGetCall(fullUrl, successCallback, errorCallback);
|
||||
}
|
||||
|
||||
|
||||
public static void SimplePutCall(string fullUrl, byte[] payload, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
InitializeHttp();
|
||||
PluginManager.GetPlugin<ITransportPlugin>(PluginContract.PlayFab_Transport).SimplePutCall(fullUrl, payload, successCallback, errorCallback);
|
||||
}
|
||||
|
||||
public static void SimplePostCall(string fullUrl, byte[] payload, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
InitializeHttp();
|
||||
PluginManager.GetPlugin<ITransportPlugin>(PluginContract.PlayFab_Transport).SimplePostCall(fullUrl, payload, successCallback, errorCallback);
|
||||
}
|
||||
|
||||
protected internal static void MakeApiCall<TResult>(string apiEndpoint,
|
||||
PlayFabRequestCommon request, AuthType authType, Action<TResult> resultCallback,
|
||||
Action<PlayFabError> errorCallback, object customData = null, Dictionary<string, string> extraHeaders = null, PlayFabAuthenticationContext authenticationContext = null, PlayFabApiSettings apiSettings = null, IPlayFabInstanceApi instanceApi = null)
|
||||
where TResult : PlayFabResultCommon
|
||||
{
|
||||
apiSettings = apiSettings ?? PlayFabSettings.staticSettings;
|
||||
var fullUrl = apiSettings.GetFullUrl(apiEndpoint, apiSettings.RequestGetParams);
|
||||
_MakeApiCall(apiEndpoint, fullUrl, request, authType, resultCallback, errorCallback, customData, extraHeaders, false, authenticationContext, apiSettings, instanceApi);
|
||||
}
|
||||
|
||||
protected internal static void MakeApiCallWithFullUri<TResult>(string fullUri,
|
||||
PlayFabRequestCommon request, AuthType authType, Action<TResult> resultCallback,
|
||||
Action<PlayFabError> errorCallback, object customData = null, Dictionary<string, string> extraHeaders = null, PlayFabAuthenticationContext authenticationContext = null, PlayFabApiSettings apiSettings = null, IPlayFabInstanceApi instanceApi = null)
|
||||
where TResult : PlayFabResultCommon
|
||||
{
|
||||
apiSettings = apiSettings ?? PlayFabSettings.staticSettings;
|
||||
// This will not be called if environment file does not exist or does not contain property the debugging URI
|
||||
_MakeApiCall(null, fullUri, request, authType, resultCallback, errorCallback, customData, extraHeaders, false, authenticationContext, apiSettings, instanceApi);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal method for Make API Calls
|
||||
/// </summary>
|
||||
private static void _MakeApiCall<TResult>(string apiEndpoint, string fullUrl,
|
||||
PlayFabRequestCommon request, AuthType authType, Action<TResult> resultCallback,
|
||||
Action<PlayFabError> errorCallback, object customData, Dictionary<string, string> extraHeaders, bool allowQueueing, PlayFabAuthenticationContext authenticationContext, PlayFabApiSettings apiSettings, IPlayFabInstanceApi instanceApi)
|
||||
where TResult : PlayFabResultCommon
|
||||
{
|
||||
InitializeHttp();
|
||||
SendEvent(apiEndpoint, request, null, ApiProcessingEventType.Pre);
|
||||
|
||||
var serializer = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer);
|
||||
var reqContainer = new CallRequestContainer
|
||||
{
|
||||
ApiEndpoint = apiEndpoint,
|
||||
FullUrl = fullUrl,
|
||||
settings = apiSettings,
|
||||
context = authenticationContext,
|
||||
CustomData = customData,
|
||||
Payload = Encoding.UTF8.GetBytes(serializer.SerializeObject(request)),
|
||||
ApiRequest = request,
|
||||
ErrorCallback = errorCallback,
|
||||
RequestHeaders = extraHeaders ?? new Dictionary<string, string>(), // Use any headers provided by the customer
|
||||
instanceApi = instanceApi
|
||||
};
|
||||
// Append any additional headers
|
||||
foreach (var pair in GlobalHeaderInjection)
|
||||
if (!reqContainer.RequestHeaders.ContainsKey(pair.Key))
|
||||
reqContainer.RequestHeaders[pair.Key] = pair.Value;
|
||||
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
reqContainer.Timing.StartTimeUtc = DateTime.UtcNow;
|
||||
reqContainer.Timing.ApiEndpoint = apiEndpoint;
|
||||
#endif
|
||||
|
||||
// Add PlayFab Headers
|
||||
var transport = PluginManager.GetPlugin<ITransportPlugin>(PluginContract.PlayFab_Transport);
|
||||
reqContainer.RequestHeaders["X-ReportErrorAsSuccess"] = "true"; // Makes processing PlayFab errors a little easier
|
||||
reqContainer.RequestHeaders["X-PlayFabSDK"] = PlayFabSettings.VersionString; // Tell PlayFab which SDK this is
|
||||
switch (authType)
|
||||
{
|
||||
#if ENABLE_PLAYFABSERVER_API || ENABLE_PLAYFABADMIN_API || UNITY_EDITOR || ENABLE_PLAYFAB_SECRETKEY
|
||||
case AuthType.DevSecretKey:
|
||||
if (apiSettings.DeveloperSecretKey == null) throw new PlayFabException(PlayFabExceptionCode.DeveloperKeyNotSet, "DeveloperSecretKey is not found in Request, Server Instance or PlayFabSettings");
|
||||
reqContainer.RequestHeaders["X-SecretKey"] = apiSettings.DeveloperSecretKey; break;
|
||||
#endif
|
||||
#if !DISABLE_PLAYFABCLIENT_API
|
||||
case AuthType.LoginSession:
|
||||
if (authenticationContext != null)
|
||||
reqContainer.RequestHeaders["X-Authorization"] = authenticationContext.ClientSessionTicket;
|
||||
break;
|
||||
#endif
|
||||
#if !DISABLE_PLAYFABENTITY_API
|
||||
case AuthType.EntityToken:
|
||||
if (authenticationContext != null)
|
||||
reqContainer.RequestHeaders["X-EntityToken"] = authenticationContext.EntityToken;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
// These closures preserve the TResult generic information in a way that's safe for all the devices
|
||||
reqContainer.DeserializeResultJson = () =>
|
||||
{
|
||||
reqContainer.ApiResult = serializer.DeserializeObject<TResult>(reqContainer.JsonResponse);
|
||||
};
|
||||
reqContainer.InvokeSuccessCallback = () =>
|
||||
{
|
||||
if (resultCallback != null)
|
||||
{
|
||||
resultCallback((TResult)reqContainer.ApiResult);
|
||||
}
|
||||
};
|
||||
|
||||
if (allowQueueing && _apiCallQueue != null)
|
||||
{
|
||||
for (var i = _apiCallQueue.Count - 1; i >= 0; i--)
|
||||
if (_apiCallQueue[i].ApiEndpoint == apiEndpoint)
|
||||
_apiCallQueue.RemoveAt(i);
|
||||
_apiCallQueue.Add(reqContainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
transport.MakeApiCall(reqContainer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal code shared by IPlayFabHTTP implementations
|
||||
/// </summary>
|
||||
internal void OnPlayFabApiResult(CallRequestContainer reqContainer)
|
||||
{
|
||||
var result = reqContainer.ApiResult;
|
||||
|
||||
#if !DISABLE_PLAYFABENTITY_API
|
||||
|
||||
var entRes = result as AuthenticationModels.GetEntityTokenResponse;
|
||||
if (entRes != null)
|
||||
{
|
||||
PlayFabSettings.staticPlayer.EntityToken = entRes.EntityToken;
|
||||
}
|
||||
|
||||
#endif
|
||||
#if !DISABLE_PLAYFABCLIENT_API
|
||||
var logRes = result as ClientModels.LoginResult;
|
||||
var regRes = result as ClientModels.RegisterPlayFabUserResult;
|
||||
if (logRes != null)
|
||||
{
|
||||
logRes.AuthenticationContext = new PlayFabAuthenticationContext(logRes.SessionTicket, logRes.EntityToken.EntityToken, logRes.PlayFabId, logRes.EntityToken.Entity.Id, logRes.EntityToken.Entity.Type);
|
||||
if (reqContainer.context != null)
|
||||
reqContainer.context.CopyFrom(logRes.AuthenticationContext);
|
||||
}
|
||||
else if (regRes != null)
|
||||
{
|
||||
regRes.AuthenticationContext = new PlayFabAuthenticationContext(regRes.SessionTicket, regRes.EntityToken.EntityToken, regRes.PlayFabId, regRes.EntityToken.Entity.Id, regRes.EntityToken.Entity.Type);
|
||||
if (reqContainer.context != null)
|
||||
reqContainer.context.CopyFrom(regRes.AuthenticationContext);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MonoBehaviour OnEnable Method
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
if (_logger != null)
|
||||
{
|
||||
_logger.OnEnable();
|
||||
}
|
||||
|
||||
#if !DISABLE_PLAYFABENTITY_API && !DISABLE_PLAYFABCLIENT_API
|
||||
if ((screenTimeTracker != null) && !PlayFabSettings.DisableFocusTimeCollection)
|
||||
{
|
||||
screenTimeTracker.OnEnable();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MonoBehaviour OnDisable
|
||||
/// </summary>
|
||||
private void OnDisable()
|
||||
{
|
||||
if (_logger != null)
|
||||
{
|
||||
_logger.OnDisable();
|
||||
}
|
||||
|
||||
#if !DISABLE_PLAYFABENTITY_API && !DISABLE_PLAYFABCLIENT_API
|
||||
if ((screenTimeTracker != null) && !PlayFabSettings.DisableFocusTimeCollection)
|
||||
{
|
||||
screenTimeTracker.OnDisable();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MonoBehaviour OnDestroy
|
||||
/// </summary>
|
||||
private void OnDestroy()
|
||||
{
|
||||
var transport = PluginManager.GetPlugin<ITransportPlugin>(PluginContract.PlayFab_Transport);
|
||||
if (transport.IsInitialized)
|
||||
{
|
||||
transport.OnDestroy();
|
||||
}
|
||||
|
||||
if (_logger != null)
|
||||
{
|
||||
_logger.OnDestroy();
|
||||
}
|
||||
|
||||
#if !DISABLE_PLAYFABENTITY_API && !DISABLE_PLAYFABCLIENT_API
|
||||
if ((screenTimeTracker != null) && !PlayFabSettings.DisableFocusTimeCollection)
|
||||
{
|
||||
screenTimeTracker.OnDestroy();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MonoBehaviour OnApplicationFocus
|
||||
/// </summary>
|
||||
public void OnApplicationFocus(bool isFocused)
|
||||
{
|
||||
#if !DISABLE_PLAYFABENTITY_API && !DISABLE_PLAYFABCLIENT_API
|
||||
if ((screenTimeTracker != null) && !PlayFabSettings.DisableFocusTimeCollection)
|
||||
{
|
||||
screenTimeTracker.OnApplicationFocus(isFocused);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MonoBehaviour OnApplicationQuit
|
||||
/// </summary>
|
||||
public void OnApplicationQuit()
|
||||
{
|
||||
#if !DISABLE_PLAYFABENTITY_API && !DISABLE_PLAYFABCLIENT_API
|
||||
if ((screenTimeTracker != null) && !PlayFabSettings.DisableFocusTimeCollection)
|
||||
{
|
||||
screenTimeTracker.OnApplicationQuit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MonoBehaviour Update
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
var transport = PluginManager.GetPlugin<ITransportPlugin>(PluginContract.PlayFab_Transport);
|
||||
if (transport.IsInitialized)
|
||||
{
|
||||
if (_apiCallQueue != null)
|
||||
{
|
||||
foreach (var eachRequest in _apiCallQueue)
|
||||
transport.MakeApiCall(eachRequest); // Flush the queue
|
||||
_apiCallQueue = null; // null this after it's flushed
|
||||
}
|
||||
transport.Update();
|
||||
}
|
||||
|
||||
while (_injectedCoroutines.Count > 0)
|
||||
StartCoroutine(_injectedCoroutines.Dequeue());
|
||||
|
||||
while (_injectedAction.Count > 0)
|
||||
{
|
||||
var action = _injectedAction.Dequeue();
|
||||
if (action != null)
|
||||
{
|
||||
action.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
protected internal static PlayFabError GeneratePlayFabError(string apiEndpoint, string json, object customData)
|
||||
{
|
||||
Dictionary<string, object> errorDict = null;
|
||||
Dictionary<string, List<string>> errorDetails = null;
|
||||
var serializer = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer);
|
||||
try
|
||||
{
|
||||
// Deserialize the error
|
||||
errorDict = serializer.DeserializeObject<Dictionary<string, object>>(json);
|
||||
}
|
||||
catch (Exception) { /* Unusual, but shouldn't actually matter */ }
|
||||
try
|
||||
{
|
||||
object errorDetailsString;
|
||||
if (errorDict != null && errorDict.TryGetValue("errorDetails", out errorDetailsString))
|
||||
errorDetails = serializer.DeserializeObject<Dictionary<string, List<string>>>(errorDetailsString.ToString());
|
||||
}
|
||||
catch (Exception) { /* Unusual, but shouldn't actually matter */ }
|
||||
|
||||
return new PlayFabError
|
||||
{
|
||||
ApiEndpoint = apiEndpoint,
|
||||
HttpCode = errorDict != null && errorDict.ContainsKey("code") ? Convert.ToInt32(errorDict["code"]) : 400,
|
||||
HttpStatus = errorDict != null && errorDict.ContainsKey("status") ? (string)errorDict["status"] : "BadRequest",
|
||||
Error = errorDict != null && errorDict.ContainsKey("errorCode") ? (PlayFabErrorCode)Convert.ToInt32(errorDict["errorCode"]) : PlayFabErrorCode.ServiceUnavailable,
|
||||
ErrorMessage = errorDict != null && errorDict.ContainsKey("errorMessage") ? (string)errorDict["errorMessage"] : json,
|
||||
ErrorDetails = errorDetails,
|
||||
CustomData = customData,
|
||||
RetryAfterSeconds = errorDict != null && errorDict.ContainsKey("retryAfterSeconds") ? Convert.ToUInt32(errorDict["retryAfterSeconds"]) : (uint?)null,
|
||||
};
|
||||
}
|
||||
|
||||
protected internal static void SendErrorEvent(PlayFabRequestCommon request, PlayFabError error)
|
||||
{
|
||||
if (ApiProcessingErrorEventHandler == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
ApiProcessingErrorEventHandler(request, error);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected internal static void SendEvent(string apiEndpoint, PlayFabRequestCommon request, PlayFabResultCommon result, ApiProcessingEventType eventType)
|
||||
{
|
||||
if (ApiProcessingEventHandler == null)
|
||||
return;
|
||||
try
|
||||
{
|
||||
ApiProcessingEventHandler(new ApiProcessingEventArgs
|
||||
{
|
||||
ApiEndpoint = apiEndpoint,
|
||||
EventType = eventType,
|
||||
Request = request,
|
||||
Result = result
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearAllEvents()
|
||||
{
|
||||
ApiProcessingEventHandler = null;
|
||||
ApiProcessingErrorEventHandler = null;
|
||||
}
|
||||
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
protected internal static void SendRequestTiming(RequestTiming rt)
|
||||
{
|
||||
if (ApiRequestTimingEventHandler != null)
|
||||
{
|
||||
ApiRequestTimingEventHandler(rt);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
private readonly Queue<IEnumerator> _injectedCoroutines = new Queue<IEnumerator>();
|
||||
private readonly Queue<Action> _injectedAction = new Queue<Action>();
|
||||
|
||||
public void InjectInUnityThread(IEnumerator x)
|
||||
{
|
||||
_injectedCoroutines.Enqueue(x);
|
||||
}
|
||||
|
||||
public void InjectInUnityThread(Action action)
|
||||
{
|
||||
_injectedAction.Enqueue(action);
|
||||
}
|
||||
}
|
||||
|
||||
#region Event Classes
|
||||
public enum ApiProcessingEventType
|
||||
{
|
||||
Pre,
|
||||
Post
|
||||
}
|
||||
|
||||
public class ApiProcessingEventArgs
|
||||
{
|
||||
public string ApiEndpoint;
|
||||
public ApiProcessingEventType EventType;
|
||||
public PlayFabRequestCommon Request;
|
||||
public PlayFabResultCommon Result;
|
||||
|
||||
public TRequest GetRequest<TRequest>() where TRequest : PlayFabRequestCommon
|
||||
{
|
||||
return Request as TRequest;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97a8a3caac8b73541aa8a9a1e330f479
|
||||
timeCreated: 1462575707
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,244 @@
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
|
||||
using PlayFab.SharedModels;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace PlayFab.Internal
|
||||
{
|
||||
public class PlayFabUnityHttp : ITransportPlugin
|
||||
{
|
||||
private bool _isInitialized = false;
|
||||
private readonly int _pendingWwwMessages = 0;
|
||||
|
||||
public bool IsInitialized { get { return _isInitialized; } }
|
||||
|
||||
public void Initialize() { _isInitialized = true; }
|
||||
|
||||
public void Update() { }
|
||||
|
||||
public void OnDestroy() { }
|
||||
|
||||
public void SimpleGetCall(string fullUrl, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
PlayFabHttp.instance.StartCoroutine(SimpleCallCoroutine("get", fullUrl, null, successCallback, errorCallback));
|
||||
}
|
||||
|
||||
public void SimplePutCall(string fullUrl, byte[] payload, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
PlayFabHttp.instance.StartCoroutine(SimpleCallCoroutine("put", fullUrl, payload, successCallback, errorCallback));
|
||||
}
|
||||
|
||||
public void SimplePostCall(string fullUrl, byte[] payload, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
PlayFabHttp.instance.StartCoroutine(SimpleCallCoroutine("post", fullUrl, payload, successCallback, errorCallback));
|
||||
}
|
||||
|
||||
private static IEnumerator SimpleCallCoroutine(string method, string fullUrl, byte[] payload, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
if (payload == null)
|
||||
{
|
||||
using (UnityWebRequest www = UnityWebRequest.Get(fullUrl))
|
||||
{
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
www.timeout = PlayFabSettings.RequestTimeout / 1000;
|
||||
yield return www.SendWebRequest();
|
||||
#else
|
||||
yield return www.Send();
|
||||
#endif
|
||||
|
||||
if (!string.IsNullOrEmpty(www.error))
|
||||
errorCallback(www.error);
|
||||
else
|
||||
successCallback(www.downloadHandler.data);
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
UnityWebRequest request;
|
||||
if (method == "put")
|
||||
{
|
||||
request = UnityWebRequest.Put(fullUrl, payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
request = new UnityWebRequest(fullUrl, "POST");
|
||||
request.uploadHandler = (UploadHandler)new UploadHandlerRaw(payload);
|
||||
request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
|
||||
request.SetRequestHeader("Content-Type", "application/json");
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
#if !UNITY_2019_1_OR_NEWER
|
||||
request.chunkedTransfer = false; // can be removed after Unity's PUT will be more stable
|
||||
#endif
|
||||
yield return request.SendWebRequest();
|
||||
#else
|
||||
yield return request.Send();
|
||||
#endif
|
||||
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
|
||||
#else
|
||||
if (request.isNetworkError || request.isHttpError)
|
||||
#endif
|
||||
{
|
||||
errorCallback(request.error);
|
||||
}
|
||||
else
|
||||
{
|
||||
successCallback(request.downloadHandler.data);
|
||||
}
|
||||
|
||||
request.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void MakeApiCall(object reqContainerObj)
|
||||
{
|
||||
CallRequestContainer reqContainer = (CallRequestContainer)reqContainerObj;
|
||||
reqContainer.RequestHeaders["Content-Type"] = "application/json";
|
||||
|
||||
// Start the www corouting to Post, and get a response or error which is then passed to the callbacks.
|
||||
PlayFabHttp.instance.StartCoroutine(Post(reqContainer));
|
||||
}
|
||||
|
||||
private IEnumerator Post(CallRequestContainer reqContainer)
|
||||
{
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
var startTime = DateTime.UtcNow;
|
||||
#endif
|
||||
|
||||
using var www = new UnityWebRequest(reqContainer.FullUrl)
|
||||
{
|
||||
uploadHandler = new UploadHandlerRaw(reqContainer.Payload),
|
||||
downloadHandler = new DownloadHandlerBuffer(),
|
||||
method = "POST"
|
||||
};
|
||||
|
||||
foreach (var headerPair in reqContainer.RequestHeaders)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(headerPair.Key) && !string.IsNullOrEmpty(headerPair.Value))
|
||||
www.SetRequestHeader(headerPair.Key, headerPair.Value);
|
||||
else
|
||||
Debug.LogWarning("Null header: " + headerPair.Key + " = " + headerPair.Value);
|
||||
}
|
||||
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
yield return www.SendWebRequest();
|
||||
#else
|
||||
yield return www.Send();
|
||||
#endif
|
||||
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
stopwatch.Stop();
|
||||
var timing = new PlayFabHttp.RequestTiming {
|
||||
StartTimeUtc = startTime,
|
||||
ApiEndpoint = reqContainer.ApiEndpoint,
|
||||
WorkerRequestMs = (int)stopwatch.ElapsedMilliseconds,
|
||||
MainThreadRequestMs = (int)stopwatch.ElapsedMilliseconds
|
||||
};
|
||||
PlayFabHttp.SendRequestTiming(timing);
|
||||
#endif
|
||||
|
||||
if (!string.IsNullOrEmpty(www.error))
|
||||
{
|
||||
OnError(www.error, reqContainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] responseBytes = www.downloadHandler.data;
|
||||
string responseText = System.Text.Encoding.UTF8.GetString(responseBytes, 0, responseBytes.Length);
|
||||
OnResponse(responseText, reqContainer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
OnError("Unhandled error in PlayFabUnityHttp: " + e, reqContainer);
|
||||
}
|
||||
}
|
||||
www.Dispose();
|
||||
}
|
||||
|
||||
public int GetPendingMessages()
|
||||
{
|
||||
return _pendingWwwMessages;
|
||||
}
|
||||
|
||||
public void OnResponse(string response, CallRequestContainer reqContainer)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
var startTime = DateTime.UtcNow;
|
||||
#endif
|
||||
var serializer = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer);
|
||||
var httpResult = serializer.DeserializeObject<HttpResponseObject>(response);
|
||||
|
||||
if (httpResult.code == 200)
|
||||
{
|
||||
// We have a good response from the server
|
||||
reqContainer.JsonResponse = serializer.SerializeObject(httpResult.data);
|
||||
reqContainer.DeserializeResultJson();
|
||||
reqContainer.ApiResult.Request = reqContainer.ApiRequest;
|
||||
reqContainer.ApiResult.CustomData = reqContainer.CustomData;
|
||||
|
||||
PlayFabHttp.instance.OnPlayFabApiResult(reqContainer);
|
||||
#if !DISABLE_PLAYFABCLIENT_API
|
||||
PlayFabDeviceUtil.OnPlayFabLogin(reqContainer.ApiResult, reqContainer.settings, reqContainer.instanceApi);
|
||||
#endif
|
||||
try
|
||||
{
|
||||
PlayFabHttp.SendEvent(reqContainer.ApiEndpoint, reqContainer.ApiRequest, reqContainer.ApiResult, ApiProcessingEventType.Post);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
reqContainer.InvokeSuccessCallback();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reqContainer.ErrorCallback != null)
|
||||
{
|
||||
reqContainer.Error = PlayFabHttp.GeneratePlayFabError(reqContainer.ApiEndpoint, response, reqContainer.CustomData);
|
||||
PlayFabHttp.SendErrorEvent(reqContainer.ApiRequest, reqContainer.Error);
|
||||
reqContainer.ErrorCallback(reqContainer.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnError(string error, CallRequestContainer reqContainer)
|
||||
{
|
||||
reqContainer.JsonResponse = error;
|
||||
if (reqContainer.ErrorCallback != null)
|
||||
{
|
||||
reqContainer.Error = PlayFabHttp.GeneratePlayFabError(reqContainer.ApiEndpoint, reqContainer.JsonResponse, reqContainer.CustomData);
|
||||
PlayFabHttp.SendErrorEvent(reqContainer.ApiRequest, reqContainer.Error);
|
||||
reqContainer.ErrorCallback(reqContainer.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdda21a9c6bb5c74d85422afab113b0f
|
||||
timeCreated: 1512617003
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,219 @@
|
||||
#if !UNITY_2018_2_OR_NEWER // Unity has deprecated Www
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using PlayFab.Json;
|
||||
using PlayFab.SharedModels;
|
||||
using UnityEngine;
|
||||
#if UNITY_5_4_OR_NEWER
|
||||
using UnityEngine.Networking;
|
||||
#else
|
||||
using UnityEngine.Experimental.Networking;
|
||||
#endif
|
||||
|
||||
namespace PlayFab.Internal
|
||||
{
|
||||
public class PlayFabWww : ITransportPlugin
|
||||
{
|
||||
private bool _isInitialized = false;
|
||||
private int _pendingWwwMessages = 0;
|
||||
|
||||
public bool IsInitialized { get { return _isInitialized; } }
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
public void Update() { }
|
||||
public void OnDestroy() { }
|
||||
|
||||
public void SimpleGetCall(string fullUrl, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
PlayFabHttp.instance.StartCoroutine(SimpleCallCoroutine("get", fullUrl, null, successCallback, errorCallback));
|
||||
}
|
||||
|
||||
public void SimplePutCall(string fullUrl, byte[] payload, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
PlayFabHttp.instance.StartCoroutine(SimpleCallCoroutine("put", fullUrl, payload, successCallback, errorCallback));
|
||||
}
|
||||
|
||||
public void SimplePostCall(string fullUrl, byte[] payload, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
PlayFabHttp.instance.StartCoroutine(SimpleCallCoroutine("post", fullUrl, payload, successCallback, errorCallback));
|
||||
}
|
||||
|
||||
private static IEnumerator SimpleCallCoroutine(string method, string fullUrl, byte[] payload, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
if (payload == null)
|
||||
{
|
||||
var www = new WWW(fullUrl);
|
||||
yield return www;
|
||||
if (!string.IsNullOrEmpty(www.error))
|
||||
errorCallback(www.error);
|
||||
else
|
||||
successCallback(www.bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityWebRequest request;
|
||||
if (method == "put")
|
||||
{
|
||||
request = UnityWebRequest.Put(fullUrl, payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
var strPayload = System.Text.Encoding.UTF8.GetString(payload, 0, payload.Length);
|
||||
request = UnityWebRequest.Post(fullUrl, strPayload);
|
||||
}
|
||||
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
request.chunkedTransfer = false; // can be removed after Unity's PUT will be more stable
|
||||
request.SendWebRequest();
|
||||
#else
|
||||
request.Send();
|
||||
#endif
|
||||
|
||||
#if !UNITY_WEBGL
|
||||
while (request.uploadProgress < 1 || request.downloadProgress < 1)
|
||||
{
|
||||
yield return 1;
|
||||
}
|
||||
#else
|
||||
while (!request.isDone)
|
||||
{
|
||||
yield return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!string.IsNullOrEmpty(request.error))
|
||||
errorCallback(request.error);
|
||||
else
|
||||
successCallback(request.downloadHandler.data);
|
||||
}
|
||||
}
|
||||
|
||||
public void MakeApiCall(object reqContainerObj)
|
||||
{
|
||||
CallRequestContainer reqContainer = (CallRequestContainer)reqContainerObj;
|
||||
reqContainer.RequestHeaders["Content-Type"] = "application/json";
|
||||
|
||||
//Debug.LogFormat("Posting {0} to Url: {1}", req.Trim(), url);
|
||||
var www = new WWW(reqContainer.FullUrl, reqContainer.Payload, reqContainer.RequestHeaders);
|
||||
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
#endif
|
||||
|
||||
// Start the www corouting to Post, and get a response or error which is then passed to the callbacks.
|
||||
Action<string> wwwSuccessCallback = (response) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
var startTime = DateTime.UtcNow;
|
||||
#endif
|
||||
var serializer = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer);
|
||||
var httpResult = serializer.DeserializeObject<HttpResponseObject>(response);
|
||||
|
||||
if (httpResult.code == 200)
|
||||
{
|
||||
// We have a good response from the server
|
||||
reqContainer.JsonResponse = serializer.SerializeObject(httpResult.data);
|
||||
reqContainer.DeserializeResultJson();
|
||||
reqContainer.ApiResult.Request = reqContainer.ApiRequest;
|
||||
reqContainer.ApiResult.CustomData = reqContainer.CustomData;
|
||||
|
||||
PlayFabHttp.instance.OnPlayFabApiResult(reqContainer);
|
||||
#if !DISABLE_PLAYFABCLIENT_API
|
||||
PlayFabDeviceUtil.OnPlayFabLogin(reqContainer.ApiResult, reqContainer.settings, reqContainer.instanceApi);
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
PlayFabHttp.SendEvent(reqContainer.ApiEndpoint, reqContainer.ApiRequest, reqContainer.ApiResult, ApiProcessingEventType.Post);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
stopwatch.Stop();
|
||||
var timing = new PlayFabHttp.RequestTiming {
|
||||
StartTimeUtc = startTime,
|
||||
ApiEndpoint = reqContainer.ApiEndpoint,
|
||||
WorkerRequestMs = (int)stopwatch.ElapsedMilliseconds,
|
||||
MainThreadRequestMs = (int)stopwatch.ElapsedMilliseconds
|
||||
};
|
||||
PlayFabHttp.SendRequestTiming(timing);
|
||||
#endif
|
||||
try
|
||||
{
|
||||
reqContainer.InvokeSuccessCallback();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reqContainer.ErrorCallback != null)
|
||||
{
|
||||
reqContainer.Error = PlayFabHttp.GeneratePlayFabError(reqContainer.ApiEndpoint, response, reqContainer.CustomData);
|
||||
PlayFabHttp.SendErrorEvent(reqContainer.ApiRequest, reqContainer.Error);
|
||||
reqContainer.ErrorCallback(reqContainer.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
};
|
||||
|
||||
Action<string> wwwErrorCallback = (errorCb) =>
|
||||
{
|
||||
reqContainer.JsonResponse = errorCb;
|
||||
if (reqContainer.ErrorCallback != null)
|
||||
{
|
||||
reqContainer.Error = PlayFabHttp.GeneratePlayFabError(reqContainer.ApiEndpoint, reqContainer.JsonResponse, reqContainer.CustomData);
|
||||
PlayFabHttp.SendErrorEvent(reqContainer.ApiRequest, reqContainer.Error);
|
||||
reqContainer.ErrorCallback(reqContainer.Error);
|
||||
}
|
||||
};
|
||||
|
||||
PlayFabHttp.instance.StartCoroutine(PostPlayFabApiCall(www, wwwSuccessCallback, wwwErrorCallback));
|
||||
}
|
||||
|
||||
private IEnumerator PostPlayFabApiCall(WWW www, Action<string> wwwSuccessCallback, Action<string> wwwErrorCallback)
|
||||
{
|
||||
yield return www;
|
||||
if (!string.IsNullOrEmpty(www.error))
|
||||
{
|
||||
wwwErrorCallback(www.error);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] responseBytes = www.bytes;
|
||||
string responseText = System.Text.Encoding.UTF8.GetString(responseBytes, 0, responseBytes.Length);
|
||||
wwwSuccessCallback(responseText);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
wwwErrorCallback("Unhandled error in PlayFabWWW: " + e);
|
||||
}
|
||||
}
|
||||
www.Dispose();
|
||||
}
|
||||
|
||||
public int GetPendingMessages()
|
||||
{
|
||||
return _pendingWwwMessages;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71ae810a641b9644187c8824db5ff1fe
|
||||
timeCreated: 1462745593
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,544 @@
|
||||
#if !UNITY_WSA && !UNITY_WP8
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using PlayFab.SharedModels;
|
||||
#if !DISABLE_PLAYFABCLIENT_API
|
||||
using PlayFab.ClientModels;
|
||||
#endif
|
||||
|
||||
namespace PlayFab.Internal
|
||||
{
|
||||
public class PlayFabWebRequest : ITransportPlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Disable encryption certificate validation within PlayFabWebRequest using this request.
|
||||
/// This is not generally recommended.
|
||||
/// As of early 2018:
|
||||
/// None of the built-in Unity mechanisms validate the certificate, using .Net 3.5 equivalent runtime
|
||||
/// It is also not currently feasible to provide a single cross platform solution that will correctly validate a certificate.
|
||||
/// The Risk:
|
||||
/// All Unity HTTPS mechanisms are vulnerable to Man-In-The-Middle attacks.
|
||||
/// The only more-secure option is to define a custom CustomCertValidationHook, specifically tailored to the platforms you support,
|
||||
/// which validate the cert based on a list of trusted certificate providers. This list of providers must be able to update itself, as the
|
||||
/// base certificates for those providers will also expire and need updating on a regular basis.
|
||||
/// </summary>
|
||||
public static void SkipCertificateValidation()
|
||||
{
|
||||
var rcvc = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications); //(sender, cert, chain, ssl) => true
|
||||
ServicePointManager.ServerCertificateValidationCallback = rcvc;
|
||||
certValidationSet = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provide PlayFabWebRequest with a custom ServerCertificateValidationCallback which can be used to validate the PlayFab encryption certificate.
|
||||
/// Please do not:
|
||||
/// - Hard code the current PlayFab certificate information - The PlayFab certificate updates itself on a regular schedule, and your game will fail and require a republish to fix
|
||||
/// - Hard code a list of static certificate authorities - Any single exported list of certificate authorities will become out of date, and have the same problem when the CA cert expires
|
||||
/// Real solution:
|
||||
/// - A mechanism where a valid certificate authority list can be securely downloaded and updated without republishing the client when existing certificates expire.
|
||||
/// </summary>
|
||||
public static System.Net.Security.RemoteCertificateValidationCallback CustomCertValidationHook
|
||||
{
|
||||
set
|
||||
{
|
||||
ServicePointManager.ServerCertificateValidationCallback = value;
|
||||
certValidationSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Queue<Action> ResultQueueTransferThread = new Queue<Action>();
|
||||
private static readonly Queue<Action> ResultQueueMainThread = new Queue<Action>();
|
||||
private static readonly List<CallRequestContainer> ActiveRequests = new List<CallRequestContainer>();
|
||||
|
||||
private static bool certValidationSet = false;
|
||||
private static Thread _requestQueueThread;
|
||||
private static readonly object _ThreadLock = new object();
|
||||
private static readonly TimeSpan ThreadKillTimeout = TimeSpan.FromSeconds(60);
|
||||
private static DateTime _threadKillTime = DateTime.UtcNow + ThreadKillTimeout; // Kill the thread after 1 minute of inactivity
|
||||
private static bool _isApplicationPlaying;
|
||||
private static int _activeCallCount;
|
||||
|
||||
private static string _unityVersion;
|
||||
|
||||
private bool _isInitialized = false;
|
||||
|
||||
public bool IsInitialized { get { return _isInitialized; } }
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
SetupCertificates();
|
||||
_isApplicationPlaying = true;
|
||||
_unityVersion = Application.unityVersion;
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
public void OnDestroy()
|
||||
{
|
||||
_isApplicationPlaying = false;
|
||||
lock (ResultQueueTransferThread)
|
||||
{
|
||||
ResultQueueTransferThread.Clear();
|
||||
}
|
||||
lock (ActiveRequests)
|
||||
{
|
||||
ActiveRequests.Clear();
|
||||
}
|
||||
lock (_ThreadLock)
|
||||
{
|
||||
_requestQueueThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupCertificates()
|
||||
{
|
||||
// These are performance Optimizations for HttpWebRequests.
|
||||
ServicePointManager.DefaultConnectionLimit = 10;
|
||||
ServicePointManager.Expect100Continue = false;
|
||||
|
||||
if (!certValidationSet)
|
||||
{
|
||||
Debug.LogWarning("PlayFab API calls will likely fail because you have not set up a HttpWebRequest certificate validation mechanism");
|
||||
Debug.LogWarning("Please set a validation callback into PlayFab.Internal.PlayFabWebRequest.CustomCertValidationHook, or set PlayFab.Internal.PlayFabWebRequest.SkipCertificateValidation()");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This disables certificate validation, if it's been activated by a customer via SkipCertificateValidation()
|
||||
/// </summary>
|
||||
private static bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SimpleGetCall(string fullUrl, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
// This needs to be improved to use a decent thread-pool, but it can be improved invisibly later
|
||||
var newThread = new Thread(() => SimpleHttpsWorker("GET", fullUrl, null, successCallback, errorCallback));
|
||||
newThread.Start();
|
||||
}
|
||||
|
||||
public void SimplePutCall(string fullUrl, byte[] payload, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
// This needs to be improved to use a decent thread-pool, but it can be improved invisibly later
|
||||
var newThread = new Thread(() => SimpleHttpsWorker("PUT", fullUrl, payload, successCallback, errorCallback));
|
||||
newThread.Start();
|
||||
}
|
||||
|
||||
public void SimplePostCall(string fullUrl, byte[] payload, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
// This needs to be improved to use a decent thread-pool, but it can be improved invisibly later
|
||||
var newThread = new Thread(() => SimpleHttpsWorker("POST", fullUrl, payload, successCallback, errorCallback));
|
||||
newThread.Start();
|
||||
}
|
||||
|
||||
|
||||
private void SimpleHttpsWorker(string httpMethod, string fullUrl, byte[] payload, Action<byte[]> successCallback, Action<string> errorCallback)
|
||||
{
|
||||
// This should also use a pooled HttpWebRequest object, but that too can be improved invisibly later
|
||||
var httpRequest = (HttpWebRequest)WebRequest.Create(fullUrl);
|
||||
httpRequest.UserAgent = "UnityEngine-Unity; Version: " + _unityVersion;
|
||||
httpRequest.Method = httpMethod;
|
||||
httpRequest.KeepAlive = PlayFabSettings.RequestKeepAlive;
|
||||
httpRequest.Timeout = PlayFabSettings.RequestTimeout;
|
||||
httpRequest.AllowWriteStreamBuffering = false;
|
||||
httpRequest.ReadWriteTimeout = PlayFabSettings.RequestTimeout;
|
||||
|
||||
if (payload != null)
|
||||
{
|
||||
httpRequest.ContentLength = payload.LongLength;
|
||||
using (var stream = httpRequest.GetRequestStream())
|
||||
{
|
||||
stream.Write(payload, 0, payload.Length);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var response = httpRequest.GetResponse();
|
||||
byte[] output = null;
|
||||
using (var responseStream = response.GetResponseStream())
|
||||
{
|
||||
if (responseStream != null)
|
||||
{
|
||||
output = new byte[response.ContentLength];
|
||||
responseStream.Read(output, 0, output.Length);
|
||||
}
|
||||
}
|
||||
successCallback(output);
|
||||
}
|
||||
catch (WebException webException)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var responseStream = webException.Response.GetResponseStream())
|
||||
{
|
||||
if (responseStream != null)
|
||||
using (var stream = new StreamReader(responseStream))
|
||||
errorCallback(stream.ReadToEnd());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void MakeApiCall(object reqContainerObj)
|
||||
{
|
||||
CallRequestContainer reqContainer = (CallRequestContainer)reqContainerObj;
|
||||
reqContainer.HttpState = HttpRequestState.Idle;
|
||||
|
||||
lock (ActiveRequests)
|
||||
{
|
||||
ActiveRequests.Insert(0, reqContainer);
|
||||
}
|
||||
|
||||
ActivateThreadWorker();
|
||||
}
|
||||
|
||||
private static void ActivateThreadWorker()
|
||||
{
|
||||
lock (_ThreadLock)
|
||||
{
|
||||
if (_requestQueueThread != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_requestQueueThread = new Thread(WorkerThreadMainLoop);
|
||||
_requestQueueThread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private static void WorkerThreadMainLoop()
|
||||
{
|
||||
try
|
||||
{
|
||||
bool active;
|
||||
lock (_ThreadLock)
|
||||
{
|
||||
// Kill the thread after 1 minute of inactivity
|
||||
_threadKillTime = DateTime.UtcNow + ThreadKillTimeout;
|
||||
}
|
||||
|
||||
List<CallRequestContainer> localActiveRequests = new List<CallRequestContainer>();
|
||||
do
|
||||
{
|
||||
//process active requests
|
||||
lock (ActiveRequests)
|
||||
{
|
||||
localActiveRequests.AddRange(ActiveRequests);
|
||||
ActiveRequests.Clear();
|
||||
_activeCallCount = localActiveRequests.Count;
|
||||
}
|
||||
|
||||
var activeCalls = localActiveRequests.Count;
|
||||
for (var i = activeCalls - 1; i >= 0; i--) // We must iterate backwards, because we remove at index i in some cases
|
||||
{
|
||||
switch (localActiveRequests[i].HttpState)
|
||||
{
|
||||
case HttpRequestState.Error:
|
||||
localActiveRequests.RemoveAt(i); break;
|
||||
case HttpRequestState.Idle:
|
||||
Post(localActiveRequests[i]); break;
|
||||
case HttpRequestState.Sent:
|
||||
if (!localActiveRequests[i].CalledGetResponse) { // Else we'll GetResponse try again next tick
|
||||
localActiveRequests[i].HttpRequest.GetResponseAsync();
|
||||
localActiveRequests[i].CalledGetResponse = true;
|
||||
}
|
||||
else if (localActiveRequests[i].HttpRequest.HaveResponse)
|
||||
ProcessHttpResponse(localActiveRequests[i]);
|
||||
break;
|
||||
case HttpRequestState.Received:
|
||||
ProcessJsonResponse(localActiveRequests[i]);
|
||||
localActiveRequests.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#region Expire Thread.
|
||||
// Check if we've been inactive
|
||||
lock (_ThreadLock)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
if (activeCalls > 0 && _isApplicationPlaying)
|
||||
{
|
||||
// Still active, reset the _threadKillTime
|
||||
_threadKillTime = now + ThreadKillTimeout;
|
||||
}
|
||||
// Kill the thread after 1 minute of inactivity
|
||||
active = now <= _threadKillTime;
|
||||
if (!active)
|
||||
{
|
||||
_requestQueueThread = null;
|
||||
}
|
||||
// This thread will be stopped, so null this now, inside lock (_threadLock)
|
||||
}
|
||||
#endregion
|
||||
|
||||
Thread.Sleep(1);
|
||||
} while (active);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
_requestQueueThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Post(CallRequestContainer reqContainer)
|
||||
{
|
||||
try
|
||||
{
|
||||
reqContainer.HttpRequest = (HttpWebRequest)WebRequest.Create(reqContainer.FullUrl);
|
||||
reqContainer.HttpRequest.UserAgent = "UnityEngine-Unity; Version: " + _unityVersion;
|
||||
reqContainer.HttpRequest.SendChunked = false;
|
||||
// Prevents hitting a proxy if no proxy is available. TODO: Add support for proxy's.
|
||||
reqContainer.HttpRequest.Proxy = null;
|
||||
|
||||
foreach (var pair in reqContainer.RequestHeaders)
|
||||
reqContainer.HttpRequest.Headers.Add(pair.Key, pair.Value);
|
||||
|
||||
reqContainer.HttpRequest.ContentType = "application/json";
|
||||
reqContainer.HttpRequest.Method = "POST";
|
||||
reqContainer.HttpRequest.KeepAlive = PlayFabSettings.RequestKeepAlive;
|
||||
reqContainer.HttpRequest.Timeout = PlayFabSettings.RequestTimeout;
|
||||
reqContainer.HttpRequest.AllowWriteStreamBuffering = false;
|
||||
reqContainer.HttpRequest.Proxy = null;
|
||||
reqContainer.HttpRequest.ContentLength = reqContainer.Payload.LongLength;
|
||||
reqContainer.HttpRequest.ReadWriteTimeout = PlayFabSettings.RequestTimeout;
|
||||
|
||||
//Debug.Log("Get Stream");
|
||||
// Get Request Stream and send data in the body.
|
||||
using (var stream = reqContainer.HttpRequest.GetRequestStream())
|
||||
{
|
||||
//Debug.Log("Post Stream");
|
||||
stream.Write(reqContainer.Payload, 0, reqContainer.Payload.Length);
|
||||
//Debug.Log("After Post stream");
|
||||
}
|
||||
|
||||
reqContainer.HttpState = HttpRequestState.Sent;
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
reqContainer.JsonResponse = ResponseToString(e.Response) ?? e.Status + ": WebException making http request to: " + reqContainer.FullUrl;
|
||||
var enhancedError = new WebException(reqContainer.JsonResponse, e);
|
||||
Debug.LogException(enhancedError);
|
||||
QueueRequestError(reqContainer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
reqContainer.JsonResponse = "Unhandled exception in Post : " + reqContainer.FullUrl;
|
||||
var enhancedError = new Exception(reqContainer.JsonResponse, e);
|
||||
Debug.LogException(enhancedError);
|
||||
QueueRequestError(reqContainer);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessHttpResponse(CallRequestContainer reqContainer)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
reqContainer.Timing.WorkerRequestMs = (int)reqContainer.Stopwatch.ElapsedMilliseconds;
|
||||
#endif
|
||||
// Get and check the response
|
||||
var httpResponse = (HttpWebResponse)reqContainer.HttpRequest.GetResponse();
|
||||
if (httpResponse.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
reqContainer.JsonResponse = ResponseToString(httpResponse);
|
||||
}
|
||||
|
||||
if (httpResponse.StatusCode != HttpStatusCode.OK || string.IsNullOrEmpty(reqContainer.JsonResponse))
|
||||
{
|
||||
reqContainer.JsonResponse = reqContainer.JsonResponse ?? "No response from server";
|
||||
QueueRequestError(reqContainer);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Response Recieved Successfully, now process.
|
||||
}
|
||||
|
||||
reqContainer.HttpState = HttpRequestState.Received;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var msg = "Unhandled exception in ProcessHttpResponse : " + reqContainer.FullUrl;
|
||||
reqContainer.JsonResponse = reqContainer.JsonResponse ?? msg;
|
||||
var enhancedError = new Exception(msg, e);
|
||||
Debug.LogException(enhancedError);
|
||||
QueueRequestError(reqContainer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the reqContainer into an error state, and queue it to invoke the ErrorCallback for that request
|
||||
/// </summary>
|
||||
private static void QueueRequestError(CallRequestContainer reqContainer)
|
||||
{
|
||||
reqContainer.Error = PlayFabHttp.GeneratePlayFabError(reqContainer.ApiEndpoint, reqContainer.JsonResponse, reqContainer.CustomData); // Decode the server-json error
|
||||
reqContainer.HttpState = HttpRequestState.Error;
|
||||
lock (ResultQueueTransferThread)
|
||||
{
|
||||
//Queue The result callbacks to run on the main thread.
|
||||
ResultQueueTransferThread.Enqueue(() =>
|
||||
{
|
||||
PlayFabHttp.SendErrorEvent(reqContainer.ApiRequest, reqContainer.Error);
|
||||
if (reqContainer.ErrorCallback != null)
|
||||
reqContainer.ErrorCallback(reqContainer.Error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessJsonResponse(CallRequestContainer reqContainer)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serializer = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer);
|
||||
var httpResult = serializer.DeserializeObject<HttpResponseObject>(reqContainer.JsonResponse);
|
||||
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
reqContainer.Timing.WorkerRequestMs = (int)reqContainer.Stopwatch.ElapsedMilliseconds;
|
||||
#endif
|
||||
|
||||
//This would happen if playfab returned a 500 internal server error or a bad json response.
|
||||
if (httpResult == null || httpResult.code != 200)
|
||||
{
|
||||
QueueRequestError(reqContainer);
|
||||
return;
|
||||
}
|
||||
|
||||
reqContainer.JsonResponse = serializer.SerializeObject(httpResult.data);
|
||||
reqContainer.DeserializeResultJson(); // Assigns Result with a properly typed object
|
||||
reqContainer.ApiResult.Request = reqContainer.ApiRequest;
|
||||
reqContainer.ApiResult.CustomData = reqContainer.CustomData;
|
||||
|
||||
if(_isApplicationPlaying)
|
||||
{
|
||||
PlayFabHttp.instance.OnPlayFabApiResult(reqContainer);
|
||||
}
|
||||
|
||||
#if !DISABLE_PLAYFABCLIENT_API
|
||||
lock (ResultQueueTransferThread)
|
||||
{
|
||||
ResultQueueTransferThread.Enqueue(() => { PlayFabDeviceUtil.OnPlayFabLogin(reqContainer.ApiResult, reqContainer.settings, reqContainer.instanceApi); });
|
||||
}
|
||||
#endif
|
||||
lock (ResultQueueTransferThread)
|
||||
{
|
||||
//Queue The result callbacks to run on the main thread.
|
||||
ResultQueueTransferThread.Enqueue(() =>
|
||||
{
|
||||
#if PLAYFAB_REQUEST_TIMING
|
||||
reqContainer.Stopwatch.Stop();
|
||||
reqContainer.Timing.MainThreadRequestMs = (int)reqContainer.Stopwatch.ElapsedMilliseconds;
|
||||
PlayFabHttp.SendRequestTiming(reqContainer.Timing);
|
||||
#endif
|
||||
try
|
||||
{
|
||||
PlayFabHttp.SendEvent(reqContainer.ApiEndpoint, reqContainer.ApiRequest, reqContainer.ApiResult, ApiProcessingEventType.Post);
|
||||
reqContainer.InvokeSuccessCallback();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e); // Log the user's callback exception back to them without halting PlayFabHttp
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var msg = "Unhandled exception in ProcessJsonResponse : " + reqContainer.FullUrl;
|
||||
reqContainer.JsonResponse = reqContainer.JsonResponse ?? msg;
|
||||
var enhancedError = new Exception(msg, e);
|
||||
Debug.LogException(enhancedError);
|
||||
QueueRequestError(reqContainer);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
lock (ResultQueueTransferThread)
|
||||
{
|
||||
while (ResultQueueTransferThread.Count > 0)
|
||||
{
|
||||
var actionToQueue = ResultQueueTransferThread.Dequeue();
|
||||
ResultQueueMainThread.Enqueue(actionToQueue);
|
||||
}
|
||||
}
|
||||
|
||||
while (ResultQueueMainThread.Count > 0)
|
||||
{
|
||||
var finishedRequest = ResultQueueMainThread.Dequeue();
|
||||
finishedRequest();
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResponseToString(WebResponse webResponse)
|
||||
{
|
||||
if (webResponse == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
using (var responseStream = webResponse.GetResponseStream())
|
||||
{
|
||||
if (responseStream == null)
|
||||
return null;
|
||||
using (var stream = new StreamReader(responseStream))
|
||||
{
|
||||
return stream.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (WebException webException)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var responseStream = webException.Response.GetResponseStream())
|
||||
{
|
||||
if (responseStream == null)
|
||||
return null;
|
||||
using (var stream = new StreamReader(responseStream))
|
||||
{
|
||||
return stream.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetPendingMessages()
|
||||
{
|
||||
var count = 0;
|
||||
lock (ActiveRequests)
|
||||
count += ActiveRequests.Count + _activeCallCount;
|
||||
lock (ResultQueueTransferThread)
|
||||
count += ResultQueueTransferThread.Count;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18fd1a0daadd68d45aebf8c19cac2bda
|
||||
timeCreated: 1466016486
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bce6184794650f24fa8ac244b25edc17
|
||||
timeCreated: 1462682372
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace PlayFab.Internal
|
||||
{
|
||||
//public to be accessible by Unity engine
|
||||
public class SingletonMonoBehaviour<T> : MonoBehaviour where T : SingletonMonoBehaviour<T>
|
||||
{
|
||||
private static T _instance;
|
||||
|
||||
public static T instance
|
||||
{
|
||||
get
|
||||
{
|
||||
CreateInstance();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static void CreateInstance()
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
//find existing instance
|
||||
_instance = FindObjectOfType<T>();
|
||||
if (_instance == null)
|
||||
{
|
||||
//create new instance
|
||||
var go = new GameObject(typeof(T).Name);
|
||||
_instance = go.AddComponent<T>();
|
||||
}
|
||||
//initialize instance if necessary
|
||||
if (!_instance.initialized)
|
||||
{
|
||||
_instance.Initialize();
|
||||
_instance.initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Awake ()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
DontDestroyOnLoad(this);
|
||||
}
|
||||
|
||||
//check if instance already exists when reloading original scene
|
||||
if (_instance != null)
|
||||
{
|
||||
DestroyImmediate (gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
protected bool initialized;
|
||||
|
||||
protected virtual void Initialize() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6a51fa1ed684497db153f40961979c4
|
||||
timeCreated: 1462682373
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,157 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
#if NETFX_CORE
|
||||
using System.Reflection;
|
||||
#endif
|
||||
|
||||
namespace PlayFab.Internal
|
||||
{
|
||||
public static class PlayFabUtil
|
||||
{
|
||||
static PlayFabUtil() { }
|
||||
|
||||
private static string _localSettingsFileName = "playfab.local.settings.json";
|
||||
public static readonly string[] _defaultDateTimeFormats = new string[]{ // All parseable ISO 8601 formats for DateTime.[Try]ParseExact - Lets us deserialize any legacy timestamps in one of these formats
|
||||
// These are the standard format with ISO 8601 UTC markers (T/Z)
|
||||
"yyyy-MM-ddTHH:mm:ss.FFFFFFZ",
|
||||
"yyyy-MM-ddTHH:mm:ss.FFFFZ",
|
||||
"yyyy-MM-ddTHH:mm:ss.FFFZ", // DEFAULT_UTC_OUTPUT_INDEX
|
||||
"yyyy-MM-ddTHH:mm:ss.FFZ",
|
||||
"yyyy-MM-ddTHH:mm:ssZ",
|
||||
"yyyy-MM-dd HH:mm:ssZ", // Added for Android Push Plugin
|
||||
|
||||
// These are the standard format without ISO 8601 UTC markers (T/Z)
|
||||
"yyyy-MM-dd HH:mm:ss.FFFFFF",
|
||||
"yyyy-MM-dd HH:mm:ss.FFFF",
|
||||
"yyyy-MM-dd HH:mm:ss.FFF",
|
||||
"yyyy-MM-dd HH:mm:ss.FF", // DEFAULT_LOCAL_OUTPUT_INDEX
|
||||
"yyyy-MM-dd HH:mm:ss",
|
||||
|
||||
// These are the result of an input bug, which we now have to support as long as the db has entries formatted like this
|
||||
"yyyy-MM-dd HH:mm.ss.FFFF",
|
||||
"yyyy-MM-dd HH:mm.ss.FFF",
|
||||
"yyyy-MM-dd HH:mm.ss.FF",
|
||||
"yyyy-MM-dd HH:mm.ss",
|
||||
};
|
||||
public const int DEFAULT_UTC_OUTPUT_INDEX = 2; // The default format everybody should use
|
||||
public const int DEFAULT_LOCAL_OUTPUT_INDEX = 9; // The default format if you want to use local time (This doesn't have universal support in all PlayFab code)
|
||||
public static DateTimeStyles DateTimeStyles = DateTimeStyles.RoundtripKind;
|
||||
|
||||
public static string timeStamp
|
||||
{
|
||||
get { return DateTime.Now.ToString(_defaultDateTimeFormats[DEFAULT_LOCAL_OUTPUT_INDEX]); }
|
||||
}
|
||||
|
||||
public static string utcTimeStamp
|
||||
{
|
||||
get { return DateTime.UtcNow.ToString(_defaultDateTimeFormats[DEFAULT_UTC_OUTPUT_INDEX]); }
|
||||
}
|
||||
|
||||
public static string Format(string text, params object[] args)
|
||||
{
|
||||
return args.Length > 0 ? string.Format(text, args) : text;
|
||||
}
|
||||
|
||||
[ThreadStatic]
|
||||
private static StringBuilder _sb;
|
||||
/// <summary>
|
||||
/// A threadsafe way to block and load a text file
|
||||
///
|
||||
/// Load a text file, and return the file as text.
|
||||
/// Used for small (usually json) files.
|
||||
/// </summary>
|
||||
public static string ReadAllFileText(string filename)
|
||||
{
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (_sb == null)
|
||||
{
|
||||
_sb = new StringBuilder();
|
||||
}
|
||||
_sb.Length = 0;
|
||||
|
||||
using (var fs = new FileStream(filename, FileMode.Open))
|
||||
{
|
||||
using (var br = new BinaryReader(fs))
|
||||
{
|
||||
while (br.BaseStream.Position != br.BaseStream.Length)
|
||||
{
|
||||
_sb.Append(br.ReadChar());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _sb.ToString();
|
||||
}
|
||||
|
||||
public static T TryEnumParse<T>(string value, T defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (T)Enum.Parse(typeof(T), value);
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UnityEngine.Debug.LogError("Enum cast failed with unknown error: " + e.Message);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
internal static string GetLocalSettingsFileProperty(string propertyKey)
|
||||
{
|
||||
string envFileContent = null;
|
||||
|
||||
string currDir = Directory.GetCurrentDirectory();
|
||||
string currDirEnvFile = Path.Combine(currDir, _localSettingsFileName);
|
||||
|
||||
if (File.Exists(currDirEnvFile))
|
||||
{
|
||||
envFileContent = ReadAllFileText(currDirEnvFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
string tempDir = Path.GetTempPath();
|
||||
string tempDirEnvFile = Path.Combine(tempDir, _localSettingsFileName);
|
||||
|
||||
if (File.Exists(tempDirEnvFile))
|
||||
{
|
||||
envFileContent = ReadAllFileText(tempDirEnvFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(envFileContent))
|
||||
{
|
||||
var serializer = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer);
|
||||
var envJson = serializer.DeserializeObject<Dictionary<string, object>>(envFileContent);
|
||||
try
|
||||
{
|
||||
object result;
|
||||
if (envJson.TryGetValue(propertyKey, out result))
|
||||
{
|
||||
return result == null ? null : result.ToString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3bfc0fbdbe1a36429699dfc30c9e488
|
||||
timeCreated: 1462682372
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
#if UNITY_WSA && UNITY_WP8
|
||||
#define NETFX_CORE
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace PlayFab
|
||||
{
|
||||
public static class WsaReflectionExtensions
|
||||
{
|
||||
#if !NETFX_CORE
|
||||
public static Delegate CreateDelegate(this MethodInfo methodInfo, Type delegateType, object instance)
|
||||
{
|
||||
return Delegate.CreateDelegate(delegateType, instance, methodInfo);
|
||||
}
|
||||
public static Type GetTypeInfo(this Type type)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
public static Type AsType(this Type type)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
public static string GetDelegateName(this Delegate delegateInstance)
|
||||
{
|
||||
return delegateInstance.Method.Name;
|
||||
}
|
||||
#else
|
||||
public static bool IsInstanceOfType(this Type type, object obj)
|
||||
{
|
||||
return obj != null && type.GetTypeInfo().IsAssignableFrom(obj.GetType().GetTypeInfo());
|
||||
}
|
||||
public static string GetDelegateName(this Delegate delegateInstance)
|
||||
{
|
||||
return delegateInstance.ToString();
|
||||
}
|
||||
public static MethodInfo GetMethod(this Type type, string methodName)
|
||||
{
|
||||
return type.GetTypeInfo().GetDeclaredMethod(methodName);
|
||||
}
|
||||
public static IEnumerable<FieldInfo> GetFields(this TypeInfo typeInfo)
|
||||
{
|
||||
return typeInfo.DeclaredFields;
|
||||
}
|
||||
public static TypeInfo GetTypeInfo(this TypeInfo typeInfo)
|
||||
{
|
||||
return typeInfo;
|
||||
}
|
||||
public static IEnumerable<ConstructorInfo> GetConstructors(this TypeInfo typeInfo)
|
||||
{
|
||||
return typeInfo.DeclaredConstructors;
|
||||
}
|
||||
public static IEnumerable<MethodInfo> GetMethods(this TypeInfo typeInfo, BindingFlags ignored)
|
||||
{
|
||||
return typeInfo.DeclaredMethods;
|
||||
}
|
||||
public static IEnumerable<TypeInfo> GetTypes(this Assembly assembly)
|
||||
{
|
||||
return assembly.DefinedTypes;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b20d57e2279b3a408268b20c2be2208
|
||||
timeCreated: 1468890373
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user