init commit
						commit
						a0532a5ced
					
				|  | @ -0,0 +1,2 @@ | |||
| # Mac auto-generated system files | ||||
| *.DS_Store* | ||||
|  | @ -0,0 +1,65 @@ | |||
| # Guru Template Change Log | ||||
| 
 | ||||
| ## 2.0.3 | ||||
| 
 | ||||
| - Firebase | ||||
|   - 整体升级到 10.1.1. 作为Unity组统一标准 | ||||
| - Max 广告聚合 | ||||
|   - 升级Max聚合的所有渠道, 对齐[中台需求](https://docs.google.com/spreadsheets/d/161UnDimGerqetIYNiMCfUBmJ7qozht8z1baxnxRdCnI/edit#gid=311231520)   | ||||
| - GuruBuildTools | ||||
|   - 新增 Deps Reporter, 用于在Jenkins环境, 上报打包依赖 (Android/iOS). 理论上报告工具不影响本地打包, 不影响打包机打包. 出问题的话也不会中断打包流程. | ||||
|   - 修复 IOS 打包成功后, 上传TF时报Info.plist内没有设置版本号的报错 | ||||
| - GuruAds | ||||
|   - 根据中台的需求, 新增广告属性打点:  `bads_imp`, `bads_loaded` | ||||
|   - 去掉使用三方广告SDK, 需要预先设置 AD_AMAZON 和 AD_PUBMATIC 的流程. 目前默认全部接入  | ||||
| - GuruAnalytics | ||||
|   - 更新和添加 Worker 支持, 预期可让用户在线时长更加精准 | ||||
| - DeviceUtil | ||||
|   - 更新Android端获取系统版本号的的接口, 方便程序判断 Android API 33 以及后继的响应  | ||||
| 
 | ||||
| 
 | ||||
| ## 2.0.2 | ||||
| 
 | ||||
| 各模块对应的内容更新 | ||||
| 
 | ||||
| - FBService  | ||||
|   - 添加IOS平台打点开启语句 `FB.Mobile.SetAdvertiserTrackingEnabled(true);` | ||||
| - AdjustService  | ||||
|   - 自动创建生命周期对象, 优化部分逻辑 | ||||
| - Firebase | ||||
|   - 修复 Firebase(8.1.0) 无法生成 google-service.json 的问题. 替换了Firebase.Editor.dll | ||||
| - Guru L10n 更新 | ||||
|   - 更新GuruL10N -> 0.4.0 新增单独翻译google sheet的设置 | ||||
|   - 更新插件 backup.csv 缓存路径, 请各个项目将 **`backup.csv`** 提交到代码内进行跟踪! | ||||
|   - 更新了语言编码去重识别, 根据Alpha表重排的功能 | ||||
| - Guru Analytics | ||||
|   - 广告打点中加入了 Waterfall 信息上报 | ||||
|   - 添加了用户属性缓存表 | ||||
| - Guru Build Tools | ||||
|   - 新增 DebugView 联调参数注入, 需要项目安装验证 | ||||
|   - 更新打包管线相关逻辑, IOS Target Version 升级为 13.0 | ||||
| - RemoteConfig | ||||
|   - 修复了AROConfig的初始化逻辑, 避免初始化时报空引发报错 | ||||
| - IAPService | ||||
|   - 添加了本地的订单数据缓存, 防止特殊操作的时候, iOS的订单重复上报的问题. | ||||
| 
 | ||||
| 
 | ||||
| ## 2.0.1 | ||||
| - 更新自打点库原生依赖  | ||||
|   - Android 原生库版本 (0.2.10) | ||||
|   - IOS 原生库版本 (0.2.16)  | ||||
| - 更新 L10n 版本 (3.2.0) | ||||
|   - 更新了导入表格会把code行也导入进来的BUG | ||||
|   - 更新配置多语言时 nb-NO 语言的识别功能 | ||||
| 
 | ||||
| 
 | ||||
| ## 1.6.0 | ||||
| - 添加了 Amazon (1.0.0) 广告扩展,使用说明详见: [GuruAds 扩展 Amazon安装说明](GuruAds/README.md) | ||||
| - 添加了 GuruAnalytics (1.0.3) 广告自打点插件,使用说明详见: [Guru Unity Analytics 自打点插件](GuruAnalytics/README.md) | ||||
| - 添加了 StandardProperties 标准属性点类, 用于记录游戏内的标准事件和属性 | ||||
| - 添加了 GuruBuildTool 模块, 收集和整理了目前为止所有 BuildTool 相关的逻辑 | ||||
| - 扩展了GuruSettings的配置格式(Amazon广告配置相关) | ||||
| - 在 AdjustService 内添加获取 AdjustId 以及 FirebaseID 的逻辑 | ||||
| - 在 AdjustService 内添加上报 DeviceID 的逻辑 | ||||
| - 修复了若干插件显示层以及构建管线的BUG | ||||
| - 调整了框架整体的文件结构 | ||||
|  | @ -0,0 +1,7 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 6acd89dd2c454676834609a8981c136a | ||||
| TextScriptImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: e3ff74f6837b4366b71c8bfe322a4562 | ||||
| timeCreated: 1671010724 | ||||
|  | @ -0,0 +1,8 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: c2bda7db652148e7a73fd2179e22be09 | ||||
| folderAsset: yes | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 347116c7f46946f5945ca097a6e964db | ||||
| timeCreated: 1687241187 | ||||
|  | @ -0,0 +1,83 @@ | |||
| #if UNITY_ANDROID | ||||
| namespace Guru | ||||
| { | ||||
|     using System.Collections.Generic; | ||||
|     using System.IO; | ||||
|     using System.Linq; | ||||
|     using UnityEditor; | ||||
|     using UnityEditor.Build; | ||||
|     using UnityEditor.Build.Reporting; | ||||
|     using UnityEngine; | ||||
|      | ||||
|     /// <summary> | ||||
|     /// Android混淆器内容填充 | ||||
|     /// 于应用构建前执行 | ||||
|     /// </summary> | ||||
|     public class UserProguardHelper: IPreprocessBuildWithReport | ||||
|     { | ||||
|         public int callbackOrder { get; } = 0; | ||||
|         public void OnPreprocessBuild(BuildReport report) | ||||
|         { | ||||
|             // 修复ProguardFile | ||||
|             OnApplyProguardFiles(); | ||||
|         } | ||||
|          | ||||
|         private static void OnApplyProguardFiles() | ||||
|         { | ||||
|             string proguardPath = $"{Application.dataPath}/Plugins/Android/proguard-user.txt"; | ||||
|             if (File.Exists(proguardPath)) | ||||
|             { | ||||
|                 List<string> keeps = new List<string>(); | ||||
|                 DirectoryInfo dir = new DirectoryInfo(Application.dataPath); | ||||
|                 string raw = File.ReadAllText(proguardPath); | ||||
|                  | ||||
|                 if (dir.Exists) | ||||
|                 { | ||||
|                     var editors = dir.GetDirectories("Editor", SearchOption.AllDirectories); | ||||
|                     List<FileInfo> files = new List<FileInfo>(); | ||||
|                     foreach (var e in editors) | ||||
|                     { | ||||
|                         files.AddRange(e.GetFiles("*Proguards.txt", SearchOption.AllDirectories)); | ||||
|                     } | ||||
|                      | ||||
|                     // Debug.Log($"--- Proguard Files: {files.Length}"); | ||||
| 
 | ||||
|                     string[] lens = null; | ||||
|                     string l = ""; | ||||
|                     for (int i = 0; i < files.Count; i++) | ||||
|                     { | ||||
|                         lens = File.ReadAllLines(files[i].FullName); | ||||
|                         foreach (var s in lens) | ||||
|                         { | ||||
|                             l = s.TrimStart(); | ||||
|                             if(string.IsNullOrEmpty(l)) continue; | ||||
|                             if(raw.Contains(l)) continue; | ||||
|                             keeps.Add(l); | ||||
|                             Debug.Log($"--- ✏️ Apply: [ {l} ]"); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|                 if (keeps.Count == 0) return; // 无注入文件则退出 | ||||
|                  | ||||
|                 List<string> lines = File.ReadAllLines(proguardPath).ToList(); | ||||
|                 lines.Add(""); | ||||
|                 lines.AddRange(keeps); | ||||
|                  | ||||
|                 File.WriteAllLines(proguardPath, lines.ToArray()); | ||||
|                 Debug.Log($"--- Update proguard-user.txt done! ☀️ ---"); | ||||
|                  | ||||
|             } | ||||
|         } | ||||
|          | ||||
|          | ||||
|         [MenuItem("Tools/Android/Add proguard-user")] | ||||
|         private static void EditorAddProguardUser() | ||||
|         { | ||||
|             OnApplyProguardFiles(); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 548800163ca249de8edcfa039836449d | ||||
| timeCreated: 1687241187 | ||||
|  | @ -0,0 +1,8 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: c4d05b56a8b854c2c93c1db55c5bc13b | ||||
| folderAsset: yes | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,22 @@ | |||
| %YAML 1.1 | ||||
| %TAG !u! tag:unity3d.com,2011: | ||||
| --- !u!114 &11400000 | ||||
| MonoBehaviour: | ||||
|   m_ObjectHideFlags: 0 | ||||
|   m_CorrespondingSourceObject: {fileID: 0} | ||||
|   m_PrefabInstance: {fileID: 0} | ||||
|   m_PrefabAsset: {fileID: 0} | ||||
|   m_GameObject: {fileID: 0} | ||||
|   m_Enabled: 1 | ||||
|   m_EditorHideFlags: 0 | ||||
|   m_Script: {fileID: 11500000, guid: a403a09e241a0480a957591ea60fb785, type: 3} | ||||
|   m_Name: settings | ||||
|   m_EditorClassIdentifier:  | ||||
|   usesCleartextTraffic: 0 | ||||
|   writeExternalStorage: 0 | ||||
|   accessFineLocation: 0 | ||||
|   addsKotlin: 0 | ||||
|   addsAndroidBrowser: 0 | ||||
|   enableJetifier: 1 | ||||
|   authCallbackUrls: [] | ||||
|   supportLINELogin: 0 | ||||
|  | @ -0,0 +1,8 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 0e00e1700888048628304b0c69a1c61e | ||||
| NativeFormatImporter: | ||||
|   externalObjects: {} | ||||
|   mainObjectFileID: 0 | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,8 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: a99ba0cf57ee14adbb2be18231643025 | ||||
| folderAsset: yes | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1,7 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: a2b9d9fa87e634e99b4932bcaaec2f40 | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 0c5075eff6f44aad872f5c8160b94132 | ||||
| timeCreated: 1703228621 | ||||
|  | @ -0,0 +1,14 @@ | |||
| { | ||||
|     "name": "Guru.LitJson", | ||||
|     "rootNamespace": "Guru.LitJson", | ||||
|     "references": [], | ||||
|     "includePlatforms": [], | ||||
|     "excludePlatforms": [], | ||||
|     "allowUnsafeCode": false, | ||||
|     "overrideReferences": false, | ||||
|     "precompiledReferences": [], | ||||
|     "autoReferenced": true, | ||||
|     "defineConstraints": [], | ||||
|     "versionDefines": [], | ||||
|     "noEngineReferences": false | ||||
| } | ||||
|  | @ -0,0 +1,7 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 2bd307385b74f48c2bdf31bd24d78056 | ||||
| AssemblyDefinitionImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,8 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 63a6db46b50de451a9008227af468125 | ||||
| folderAsset: yes | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,18 @@ | |||
| using System; | ||||
| using System.Reflection; | ||||
| using System.Runtime.CompilerServices; | ||||
| 
 | ||||
| 
 | ||||
| [assembly: CLSCompliant (true)] | ||||
| 
 | ||||
| [assembly: AssemblyTitle ("LitJson")] | ||||
| [assembly: AssemblyDescription ("LitJSON library")] | ||||
| [assembly: AssemblyConfiguration ("")] | ||||
| [assembly: AssemblyCompany ("")] | ||||
| [assembly: AssemblyProduct ("LitJSON")] | ||||
| [assembly: AssemblyCopyright ( | ||||
|     "The authors disclaim copyright to this source code")] | ||||
| [assembly: AssemblyTrademark ("")] | ||||
| [assembly: AssemblyCulture ("")] | ||||
| 
 | ||||
| [assembly: AssemblyVersion ("@ASSEMBLY_VERSION@")] | ||||
|  | @ -0,0 +1,7 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: b7cf5dc50b2d64dca9830e9144c06b2c | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,60 @@ | |||
| #region Header | ||||
| /** | ||||
|  * IJsonWrapper.cs | ||||
|  *   Interface that represents a type capable of handling all kinds of JSON | ||||
|  *   data. This is mainly used when mapping objects through JsonMapper, and | ||||
|  *   it's implemented by JsonData. | ||||
|  * | ||||
|  * The authors disclaim copyright to this source code. For more details, see | ||||
|  * the COPYING file included with this distribution. | ||||
|  **/ | ||||
| #endregion | ||||
| 
 | ||||
| 
 | ||||
| using System.Collections; | ||||
| using System.Collections.Specialized; | ||||
| 
 | ||||
| 
 | ||||
| namespace Guru.LitJson | ||||
| { | ||||
|     public enum JsonType | ||||
|     { | ||||
|         None, | ||||
| 
 | ||||
|         Object, | ||||
|         Array, | ||||
|         String, | ||||
|         Int, | ||||
|         Long, | ||||
|         Double, | ||||
|         Boolean | ||||
|     } | ||||
| 
 | ||||
|     public interface IJsonWrapper : IList, IOrderedDictionary | ||||
|     { | ||||
|         bool IsArray   { get; } | ||||
|         bool IsBoolean { get; } | ||||
|         bool IsDouble  { get; } | ||||
|         bool IsInt     { get; } | ||||
|         bool IsLong    { get; } | ||||
|         bool IsObject  { get; } | ||||
|         bool IsString  { get; } | ||||
| 
 | ||||
|         bool     GetBoolean (); | ||||
|         double   GetDouble (); | ||||
|         int      GetInt (); | ||||
|         JsonType GetJsonType (); | ||||
|         long     GetLong (); | ||||
|         string   GetString (); | ||||
| 
 | ||||
|         void SetBoolean  (bool val); | ||||
|         void SetDouble   (double val); | ||||
|         void SetInt      (int val); | ||||
|         void SetJsonType (JsonType type); | ||||
|         void SetLong     (long val); | ||||
|         void SetString   (string val); | ||||
| 
 | ||||
|         string ToJson (); | ||||
|         void   ToJson (JsonWriter writer); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 394f32e20d93e474487e7f8a07415298 | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 5559251be0dd54c669a5b225ad53126e | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,65 @@ | |||
| #region Header | ||||
| /** | ||||
|  * JsonException.cs | ||||
|  *   Base class throwed by LitJSON when a parsing error occurs. | ||||
|  * | ||||
|  * The authors disclaim copyright to this source code. For more details, see | ||||
|  * the COPYING file included with this distribution. | ||||
|  **/ | ||||
| #endregion | ||||
| 
 | ||||
| 
 | ||||
| using System; | ||||
| 
 | ||||
| 
 | ||||
| namespace Guru.LitJson | ||||
| { | ||||
|     public class JsonException : | ||||
| #if NETSTANDARD1_5 | ||||
|         Exception | ||||
| #else | ||||
|         ApplicationException | ||||
| #endif | ||||
|     { | ||||
|         public JsonException () : base () | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         internal JsonException (ParserToken token) : | ||||
|             base (String.Format ( | ||||
|                     "Invalid token '{0}' in input string", token)) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         internal JsonException (ParserToken token, | ||||
|                                 Exception inner_exception) : | ||||
|             base (String.Format ( | ||||
|                     "Invalid token '{0}' in input string", token), | ||||
|                 inner_exception) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         internal JsonException (int c) : | ||||
|             base (String.Format ( | ||||
|                     "Invalid character '{0}' in input string", (char) c)) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         internal JsonException (int c, Exception inner_exception) : | ||||
|             base (String.Format ( | ||||
|                     "Invalid character '{0}' in input string", (char) c), | ||||
|                 inner_exception) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         public JsonException (string message) : base (message) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public JsonException (string message, Exception inner_exception) : | ||||
|             base (message, inner_exception) | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 35e97fa5a8f99447a90bffb890cfd55d | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,995 @@ | |||
| #region Header | ||||
| /** | ||||
|  * JsonMapper.cs | ||||
|  *   JSON to .Net object and object to JSON conversions. | ||||
|  * | ||||
|  * The authors disclaim copyright to this source code. For more details, see | ||||
|  * the COPYING file included with this distribution. | ||||
|  **/ | ||||
| #endregion | ||||
| 
 | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.Globalization; | ||||
| using System.IO; | ||||
| using System.Reflection; | ||||
| 
 | ||||
| 
 | ||||
| namespace Guru.LitJson | ||||
| { | ||||
|     internal struct PropertyMetadata | ||||
|     { | ||||
|         public MemberInfo Info; | ||||
|         public bool       IsField; | ||||
|         public Type       Type; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     internal struct ArrayMetadata | ||||
|     { | ||||
|         private Type element_type; | ||||
|         private bool is_array; | ||||
|         private bool is_list; | ||||
| 
 | ||||
| 
 | ||||
|         public Type ElementType { | ||||
|             get { | ||||
|                 if (element_type == null) | ||||
|                     return typeof (JsonData); | ||||
| 
 | ||||
|                 return element_type; | ||||
|             } | ||||
| 
 | ||||
|             set { element_type = value; } | ||||
|         } | ||||
| 
 | ||||
|         public bool IsArray { | ||||
|             get { return is_array; } | ||||
|             set { is_array = value; } | ||||
|         } | ||||
| 
 | ||||
|         public bool IsList { | ||||
|             get { return is_list; } | ||||
|             set { is_list = value; } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     internal struct ObjectMetadata | ||||
|     { | ||||
|         private Type element_type; | ||||
|         private bool is_dictionary; | ||||
| 
 | ||||
|         private IDictionary<string, PropertyMetadata> properties; | ||||
| 
 | ||||
| 
 | ||||
|         public Type ElementType { | ||||
|             get { | ||||
|                 if (element_type == null) | ||||
|                     return typeof (JsonData); | ||||
| 
 | ||||
|                 return element_type; | ||||
|             } | ||||
| 
 | ||||
|             set { element_type = value; } | ||||
|         } | ||||
| 
 | ||||
|         public bool IsDictionary { | ||||
|             get { return is_dictionary; } | ||||
|             set { is_dictionary = value; } | ||||
|         } | ||||
| 
 | ||||
|         public IDictionary<string, PropertyMetadata> Properties { | ||||
|             get { return properties; } | ||||
|             set { properties = value; } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     internal delegate void ExporterFunc    (object obj, JsonWriter writer); | ||||
|     public   delegate void ExporterFunc<T> (T obj, JsonWriter writer); | ||||
| 
 | ||||
|     internal delegate object ImporterFunc                (object input); | ||||
|     public   delegate TValue ImporterFunc<TJson, TValue> (TJson input); | ||||
| 
 | ||||
|     public delegate IJsonWrapper WrapperFactory (); | ||||
| 
 | ||||
| 
 | ||||
|     public class JsonMapper | ||||
|     { | ||||
|         #region Fields | ||||
|         private static readonly int max_nesting_depth; | ||||
| 
 | ||||
|         private static readonly IFormatProvider datetime_format; | ||||
| 
 | ||||
|         private static readonly IDictionary<Type, ExporterFunc> base_exporters_table; | ||||
|         private static readonly IDictionary<Type, ExporterFunc> custom_exporters_table; | ||||
|         private static readonly object custom_exporters_table_lock = new Object(); | ||||
| 
 | ||||
|         private static readonly IDictionary<Type, | ||||
|                 IDictionary<Type, ImporterFunc>> base_importers_table; | ||||
|         private static readonly IDictionary<Type, | ||||
|                 IDictionary<Type, ImporterFunc>> custom_importers_table; | ||||
|         private static readonly object custom_importers_table_lock = new Object(); | ||||
| 
 | ||||
|         private static readonly IDictionary<Type, ArrayMetadata> array_metadata; | ||||
|         private static readonly object array_metadata_lock = new Object (); | ||||
| 
 | ||||
|         private static readonly IDictionary<Type, | ||||
|                 IDictionary<Type, MethodInfo>> conv_ops; | ||||
|         private static readonly object conv_ops_lock = new Object (); | ||||
| 
 | ||||
|         private static readonly IDictionary<Type, ObjectMetadata> object_metadata; | ||||
|         private static readonly object object_metadata_lock = new Object (); | ||||
| 
 | ||||
|         private static readonly IDictionary<Type, | ||||
|                 IList<PropertyMetadata>> type_properties; | ||||
|         private static readonly object type_properties_lock = new Object (); | ||||
| 
 | ||||
|         private static readonly JsonWriter      static_writer; | ||||
|         private static readonly object static_writer_lock = new Object (); | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Constructors | ||||
|         static JsonMapper () | ||||
|         { | ||||
|             max_nesting_depth = 100; | ||||
| 
 | ||||
|             array_metadata = new Dictionary<Type, ArrayMetadata> (); | ||||
|             conv_ops = new Dictionary<Type, IDictionary<Type, MethodInfo>> (); | ||||
|             object_metadata = new Dictionary<Type, ObjectMetadata> (); | ||||
|             type_properties = new Dictionary<Type, | ||||
|                             IList<PropertyMetadata>> (); | ||||
| 
 | ||||
|             static_writer = new JsonWriter (); | ||||
| 
 | ||||
|             datetime_format = DateTimeFormatInfo.InvariantInfo; | ||||
| 
 | ||||
|             base_exporters_table   = new Dictionary<Type, ExporterFunc> (); | ||||
|             custom_exporters_table = new Dictionary<Type, ExporterFunc> (); | ||||
| 
 | ||||
|             base_importers_table = new Dictionary<Type, | ||||
|                                  IDictionary<Type, ImporterFunc>> (); | ||||
|             custom_importers_table = new Dictionary<Type, | ||||
|                                    IDictionary<Type, ImporterFunc>> (); | ||||
| 
 | ||||
|             RegisterBaseExporters (); | ||||
|             RegisterBaseImporters (); | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Private Methods | ||||
|         private static void AddArrayMetadata (Type type) | ||||
|         { | ||||
|             if (array_metadata.ContainsKey (type)) | ||||
|                 return; | ||||
| 
 | ||||
|             ArrayMetadata data = new ArrayMetadata (); | ||||
| 
 | ||||
|             data.IsArray = type.IsArray; | ||||
| 
 | ||||
|             if (type.GetInterface ("System.Collections.IList") != null) | ||||
|                 data.IsList = true; | ||||
| 
 | ||||
|             foreach (PropertyInfo p_info in type.GetProperties ()) { | ||||
|                 if (p_info.Name != "Item") | ||||
|                     continue; | ||||
| 
 | ||||
|                 ParameterInfo[] parameters = p_info.GetIndexParameters (); | ||||
| 
 | ||||
|                 if (parameters.Length != 1) | ||||
|                     continue; | ||||
| 
 | ||||
|                 if (parameters[0].ParameterType == typeof (int)) | ||||
|                     data.ElementType = p_info.PropertyType; | ||||
|             } | ||||
| 
 | ||||
|             lock (array_metadata_lock) { | ||||
|                 try { | ||||
|                     array_metadata.Add (type, data); | ||||
|                 } catch (ArgumentException) { | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void AddObjectMetadata (Type type) | ||||
|         { | ||||
|             if (object_metadata.ContainsKey (type)) | ||||
|                 return; | ||||
| 
 | ||||
|             ObjectMetadata data = new ObjectMetadata (); | ||||
| 
 | ||||
|             if (type.GetInterface ("System.Collections.IDictionary") != null) | ||||
|                 data.IsDictionary = true; | ||||
| 
 | ||||
|             data.Properties = new Dictionary<string, PropertyMetadata> (); | ||||
| 
 | ||||
|             foreach (PropertyInfo p_info in type.GetProperties ()) { | ||||
|                 if (p_info.Name == "Item") { | ||||
|                     ParameterInfo[] parameters = p_info.GetIndexParameters (); | ||||
| 
 | ||||
|                     if (parameters.Length != 1) | ||||
|                         continue; | ||||
| 
 | ||||
|                     if (parameters[0].ParameterType == typeof (string)) | ||||
|                         data.ElementType = p_info.PropertyType; | ||||
| 
 | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 PropertyMetadata p_data = new PropertyMetadata (); | ||||
|                 p_data.Info = p_info; | ||||
|                 p_data.Type = p_info.PropertyType; | ||||
| 
 | ||||
|                 data.Properties.Add (p_info.Name, p_data); | ||||
|             } | ||||
| 
 | ||||
|             foreach (FieldInfo f_info in type.GetFields ()) { | ||||
|                 PropertyMetadata p_data = new PropertyMetadata (); | ||||
|                 p_data.Info = f_info; | ||||
|                 p_data.IsField = true; | ||||
|                 p_data.Type = f_info.FieldType; | ||||
| 
 | ||||
|                 data.Properties.Add (f_info.Name, p_data); | ||||
|             } | ||||
| 
 | ||||
|             lock (object_metadata_lock) { | ||||
|                 try { | ||||
|                     object_metadata.Add (type, data); | ||||
|                 } catch (ArgumentException) { | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void AddTypeProperties (Type type) | ||||
|         { | ||||
|             if (type_properties.ContainsKey (type)) | ||||
|                 return; | ||||
| 
 | ||||
|             IList<PropertyMetadata> props = new List<PropertyMetadata> (); | ||||
| 
 | ||||
|             foreach (PropertyInfo p_info in type.GetProperties ()) { | ||||
|                 if (p_info.Name == "Item") | ||||
|                     continue; | ||||
| 
 | ||||
|                 PropertyMetadata p_data = new PropertyMetadata (); | ||||
|                 p_data.Info = p_info; | ||||
|                 p_data.IsField = false; | ||||
|                 props.Add (p_data); | ||||
|             } | ||||
| 
 | ||||
|             foreach (FieldInfo f_info in type.GetFields ()) { | ||||
|                 PropertyMetadata p_data = new PropertyMetadata (); | ||||
|                 p_data.Info = f_info; | ||||
|                 p_data.IsField = true; | ||||
| 
 | ||||
|                 props.Add (p_data); | ||||
|             } | ||||
| 
 | ||||
|             lock (type_properties_lock) { | ||||
|                 try { | ||||
|                     type_properties.Add (type, props); | ||||
|                 } catch (ArgumentException) { | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static MethodInfo GetConvOp (Type t1, Type t2) | ||||
|         { | ||||
|             lock (conv_ops_lock) { | ||||
|                 if (! conv_ops.ContainsKey (t1)) | ||||
|                     conv_ops.Add (t1, new Dictionary<Type, MethodInfo> ()); | ||||
|             } | ||||
| 
 | ||||
|             if (conv_ops[t1].ContainsKey (t2)) | ||||
|                 return conv_ops[t1][t2]; | ||||
| 
 | ||||
|             MethodInfo op = t1.GetMethod ( | ||||
|                 "op_Implicit", new Type[] { t2 }); | ||||
| 
 | ||||
|             lock (conv_ops_lock) { | ||||
|                 try { | ||||
|                     conv_ops[t1].Add (t2, op); | ||||
|                 } catch (ArgumentException) { | ||||
|                     return conv_ops[t1][t2]; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return op; | ||||
|         } | ||||
| 
 | ||||
|         private static object ReadValue (Type inst_type, JsonReader reader) | ||||
|         { | ||||
|             reader.Read (); | ||||
| 
 | ||||
|             if (reader.Token == JsonToken.ArrayEnd) | ||||
|                 return null; | ||||
| 
 | ||||
|             Type underlying_type = Nullable.GetUnderlyingType(inst_type); | ||||
|             Type value_type = underlying_type ?? inst_type; | ||||
| 
 | ||||
|             if (reader.Token == JsonToken.Null) { | ||||
|                 #if NETSTANDARD1_5 | ||||
|                 if (inst_type.IsClass() || underlying_type != null) { | ||||
|                     return null; | ||||
|                 } | ||||
|                 #else | ||||
|                 if (inst_type.IsClass || underlying_type != null) { | ||||
|                     return null; | ||||
|                 } | ||||
|                 #endif | ||||
| 
 | ||||
|                 throw new JsonException (String.Format ( | ||||
|                             "Can't assign null to an instance of type {0}", | ||||
|                             inst_type)); | ||||
|             } | ||||
| 
 | ||||
|             if (reader.Token == JsonToken.Double || | ||||
|                 reader.Token == JsonToken.Int || | ||||
|                 reader.Token == JsonToken.Long || | ||||
|                 reader.Token == JsonToken.String || | ||||
|                 reader.Token == JsonToken.Boolean) { | ||||
| 
 | ||||
|                 Type json_type = reader.Value.GetType (); | ||||
| 
 | ||||
|                 if (value_type.IsAssignableFrom (json_type)) | ||||
|                     return reader.Value; | ||||
| 
 | ||||
|                 // If there's a custom importer that fits, use it | ||||
|                 lock (custom_importers_table_lock) { | ||||
|                     if (custom_importers_table.TryGetValue(json_type, out IDictionary<Type, ImporterFunc> customImporterTablesValue) && | ||||
|                         customImporterTablesValue.TryGetValue(value_type, out ImporterFunc customImporter)) { | ||||
| 
 | ||||
|                         return customImporter(reader.Value); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 // Maybe there's a base importer that works | ||||
|                 if (base_importers_table.TryGetValue(json_type, out IDictionary<Type, ImporterFunc> baseImporterTablesValue) && | ||||
|                     baseImporterTablesValue.TryGetValue(value_type, out ImporterFunc baseImporter)) { | ||||
| 
 | ||||
|                     return baseImporter(reader.Value); | ||||
|                 } | ||||
| 
 | ||||
|                 // Maybe it's an enum | ||||
|                 #if NETSTANDARD1_5 | ||||
|                 if (value_type.IsEnum()) | ||||
|                     return Enum.ToObject (value_type, reader.Value); | ||||
|                 #else | ||||
|                 if (value_type.IsEnum) | ||||
|                     return Enum.ToObject (value_type, reader.Value); | ||||
|                 #endif | ||||
|                 // Try using an implicit conversion operator | ||||
|                 MethodInfo conv_op = GetConvOp (value_type, json_type); | ||||
| 
 | ||||
|                 if (conv_op != null) | ||||
|                     return conv_op.Invoke (null, | ||||
|                                            new object[] { reader.Value }); | ||||
| 
 | ||||
|                 // No luck | ||||
|                 throw new JsonException (String.Format ( | ||||
|                         "Can't assign value '{0}' (type {1}) to type {2}", | ||||
|                         reader.Value, json_type, inst_type)); | ||||
|             } | ||||
| 
 | ||||
|             object instance = null; | ||||
| 
 | ||||
|             if (reader.Token == JsonToken.ArrayStart) { | ||||
| 
 | ||||
|                 AddArrayMetadata (inst_type); | ||||
|                 ArrayMetadata t_data = array_metadata[inst_type]; | ||||
| 
 | ||||
|                 if (! t_data.IsArray && ! t_data.IsList) | ||||
|                     throw new JsonException (String.Format ( | ||||
|                             "Type {0} can't act as an array", | ||||
|                             inst_type)); | ||||
| 
 | ||||
|                 IList list; | ||||
|                 Type elem_type; | ||||
| 
 | ||||
|                 if (! t_data.IsArray) { | ||||
|                     list = (IList) Activator.CreateInstance (inst_type); | ||||
|                     elem_type = t_data.ElementType; | ||||
|                 } else { | ||||
|                     list = new ArrayList (); | ||||
|                     elem_type = inst_type.GetElementType (); | ||||
|                 } | ||||
| 
 | ||||
|                 list.Clear(); | ||||
| 
 | ||||
|                 while (true) { | ||||
|                     object item = ReadValue (elem_type, reader); | ||||
|                     if (item == null && reader.Token == JsonToken.ArrayEnd) | ||||
|                         break; | ||||
| 
 | ||||
|                     list.Add (item); | ||||
|                 } | ||||
| 
 | ||||
|                 if (t_data.IsArray) { | ||||
|                     int n = list.Count; | ||||
|                     instance = Array.CreateInstance (elem_type, n); | ||||
| 
 | ||||
|                     for (int i = 0; i < n; i++) | ||||
|                         ((Array) instance).SetValue (list[i], i); | ||||
|                 } else | ||||
|                     instance = list; | ||||
| 
 | ||||
|             } else if (reader.Token == JsonToken.ObjectStart) { | ||||
|                 AddObjectMetadata (value_type); | ||||
|                 ObjectMetadata t_data = object_metadata[value_type]; | ||||
| 
 | ||||
|                 instance = Activator.CreateInstance (value_type); | ||||
| 
 | ||||
|                 while (true) { | ||||
|                     reader.Read (); | ||||
| 
 | ||||
|                     if (reader.Token == JsonToken.ObjectEnd) | ||||
|                         break; | ||||
| 
 | ||||
|                     string property = (string) reader.Value; | ||||
| 
 | ||||
|                     if (t_data.Properties.ContainsKey (property)) { | ||||
|                         PropertyMetadata prop_data = | ||||
|                             t_data.Properties[property]; | ||||
| 
 | ||||
|                         if (prop_data.IsField) { | ||||
|                             ((FieldInfo) prop_data.Info).SetValue ( | ||||
|                                 instance, ReadValue (prop_data.Type, reader)); | ||||
|                         } else { | ||||
|                             PropertyInfo p_info = | ||||
|                                 (PropertyInfo) prop_data.Info; | ||||
| 
 | ||||
|                             if (p_info.CanWrite) | ||||
|                                 p_info.SetValue ( | ||||
|                                     instance, | ||||
|                                     ReadValue (prop_data.Type, reader), | ||||
|                                     null); | ||||
|                             else | ||||
|                                 ReadValue (prop_data.Type, reader); | ||||
|                         } | ||||
| 
 | ||||
|                     } else { | ||||
|                         if (! t_data.IsDictionary) { | ||||
| 
 | ||||
|                             if (! reader.SkipNonMembers) { | ||||
|                                 throw new JsonException (String.Format ( | ||||
|                                         "The type {0} doesn't have the " + | ||||
|                                         "property '{1}'", | ||||
|                                         inst_type, property)); | ||||
|                             } else { | ||||
|                                 ReadSkip (reader); | ||||
|                                 continue; | ||||
|                             } | ||||
|                         } | ||||
| 
 | ||||
|                         ((IDictionary) instance).Add ( | ||||
|                             property, ReadValue ( | ||||
|                                 t_data.ElementType, reader)); | ||||
|                     } | ||||
| 
 | ||||
|                 } | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             return instance; | ||||
|         } | ||||
| 
 | ||||
|         private static IJsonWrapper ReadValue (WrapperFactory factory, | ||||
|                                                JsonReader reader) | ||||
|         { | ||||
|             reader.Read (); | ||||
| 
 | ||||
|             if (reader.Token == JsonToken.ArrayEnd || | ||||
|                 reader.Token == JsonToken.Null) | ||||
|                 return null; | ||||
| 
 | ||||
|             IJsonWrapper instance = factory (); | ||||
| 
 | ||||
|             if (reader.Token == JsonToken.String) { | ||||
|                 instance.SetString ((string) reader.Value); | ||||
|                 return instance; | ||||
|             } | ||||
| 
 | ||||
|             if (reader.Token == JsonToken.Double) { | ||||
|                 instance.SetDouble ((double) reader.Value); | ||||
|                 return instance; | ||||
|             } | ||||
| 
 | ||||
|             if (reader.Token == JsonToken.Int) { | ||||
|                 instance.SetInt ((int) reader.Value); | ||||
|                 return instance; | ||||
|             } | ||||
| 
 | ||||
|             if (reader.Token == JsonToken.Long) { | ||||
|                 instance.SetLong ((long) reader.Value); | ||||
|                 return instance; | ||||
|             } | ||||
| 
 | ||||
|             if (reader.Token == JsonToken.Boolean) { | ||||
|                 instance.SetBoolean ((bool) reader.Value); | ||||
|                 return instance; | ||||
|             } | ||||
| 
 | ||||
|             if (reader.Token == JsonToken.ArrayStart) { | ||||
|                 instance.SetJsonType (JsonType.Array); | ||||
| 
 | ||||
|                 while (true) { | ||||
|                     IJsonWrapper item = ReadValue (factory, reader); | ||||
|                     if (item == null && reader.Token == JsonToken.ArrayEnd) | ||||
|                         break; | ||||
| 
 | ||||
|                     ((IList) instance).Add (item); | ||||
|                 } | ||||
|             } | ||||
|             else if (reader.Token == JsonToken.ObjectStart) { | ||||
|                 instance.SetJsonType (JsonType.Object); | ||||
| 
 | ||||
|                 while (true) { | ||||
|                     reader.Read (); | ||||
| 
 | ||||
|                     if (reader.Token == JsonToken.ObjectEnd) | ||||
|                         break; | ||||
| 
 | ||||
|                     string property = (string) reader.Value; | ||||
| 
 | ||||
|                     ((IDictionary) instance)[property] = ReadValue ( | ||||
|                         factory, reader); | ||||
|                 } | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             return instance; | ||||
|         } | ||||
| 
 | ||||
|         private static void ReadSkip (JsonReader reader) | ||||
|         { | ||||
|             ToWrapper ( | ||||
|                 delegate { return new JsonMockWrapper (); }, reader); | ||||
|         } | ||||
| 
 | ||||
|         private static void RegisterBaseExporters () | ||||
|         { | ||||
|             // This method is only called from the static initializer, | ||||
|             // so there is no need to explicitly lock any static members here | ||||
|             base_exporters_table[typeof (byte)] = | ||||
|                 delegate (object obj, JsonWriter writer) { | ||||
|                     writer.Write (Convert.ToInt32 ((byte) obj)); | ||||
|                 }; | ||||
| 
 | ||||
|             base_exporters_table[typeof (char)] = | ||||
|                 delegate (object obj, JsonWriter writer) { | ||||
|                     writer.Write (Convert.ToString ((char) obj)); | ||||
|                 }; | ||||
| 
 | ||||
|             base_exporters_table[typeof (DateTime)] = | ||||
|                 delegate (object obj, JsonWriter writer) { | ||||
|                     writer.Write (Convert.ToString ((DateTime) obj, | ||||
|                                                     datetime_format)); | ||||
|                 }; | ||||
| 
 | ||||
|             base_exporters_table[typeof (decimal)] = | ||||
|                 delegate (object obj, JsonWriter writer) { | ||||
|                     writer.Write ((decimal) obj); | ||||
|                 }; | ||||
| 
 | ||||
|             base_exporters_table[typeof (sbyte)] = | ||||
|                 delegate (object obj, JsonWriter writer) { | ||||
|                     writer.Write (Convert.ToInt32 ((sbyte) obj)); | ||||
|                 }; | ||||
| 
 | ||||
|             base_exporters_table[typeof (short)] = | ||||
|                 delegate (object obj, JsonWriter writer) { | ||||
|                     writer.Write (Convert.ToInt32 ((short) obj)); | ||||
|                 }; | ||||
| 
 | ||||
|             base_exporters_table[typeof (ushort)] = | ||||
|                 delegate (object obj, JsonWriter writer) { | ||||
|                     writer.Write (Convert.ToInt32 ((ushort) obj)); | ||||
|                 }; | ||||
| 
 | ||||
|             base_exporters_table[typeof (uint)] = | ||||
|                 delegate (object obj, JsonWriter writer) { | ||||
|                     writer.Write (Convert.ToUInt64 ((uint) obj)); | ||||
|                 }; | ||||
| 
 | ||||
|             base_exporters_table[typeof (ulong)] = | ||||
|                 delegate (object obj, JsonWriter writer) { | ||||
|                     writer.Write ((ulong) obj); | ||||
|                 }; | ||||
| 
 | ||||
|             base_exporters_table[typeof(DateTimeOffset)] = | ||||
|                 delegate (object obj, JsonWriter writer) { | ||||
|                     writer.Write(((DateTimeOffset)obj).ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", datetime_format)); | ||||
|                 }; | ||||
|         } | ||||
| 
 | ||||
|         private static void RegisterBaseImporters () | ||||
|         { | ||||
|             // This method is only called from the static initializer, | ||||
|             // so there is no need to explicitly lock any static members here | ||||
|             ImporterFunc importer; | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToByte ((int) input); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (int), | ||||
|                               typeof (byte), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToUInt64 ((int) input); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (int), | ||||
|                               typeof (ulong), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToInt64((int)input); | ||||
|             }; | ||||
|             RegisterImporter(base_importers_table, typeof(int), | ||||
|                               typeof(long), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToSByte ((int) input); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (int), | ||||
|                               typeof (sbyte), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToInt16 ((int) input); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (int), | ||||
|                               typeof (short), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToUInt16 ((int) input); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (int), | ||||
|                               typeof (ushort), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToUInt32 ((int) input); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (int), | ||||
|                               typeof (uint), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToSingle ((int) input); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (int), | ||||
|                               typeof (float), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToDouble ((int) input); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (int), | ||||
|                               typeof (double), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToDecimal ((double) input); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (double), | ||||
|                               typeof (decimal), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToSingle((double)input); | ||||
|             }; | ||||
|             RegisterImporter(base_importers_table, typeof(double), | ||||
|                 typeof(float), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToUInt32 ((long) input); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (long), | ||||
|                               typeof (uint), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToChar ((string) input); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (string), | ||||
|                               typeof (char), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return Convert.ToDateTime ((string) input, datetime_format); | ||||
|             }; | ||||
|             RegisterImporter (base_importers_table, typeof (string), | ||||
|                               typeof (DateTime), importer); | ||||
| 
 | ||||
|             importer = delegate (object input) { | ||||
|                 return DateTimeOffset.Parse((string)input, datetime_format); | ||||
|             }; | ||||
|             RegisterImporter(base_importers_table, typeof(string), | ||||
|                 typeof(DateTimeOffset), importer); | ||||
|         } | ||||
| 
 | ||||
|         private static void RegisterImporter ( | ||||
|             IDictionary<Type, IDictionary<Type, ImporterFunc>> table, | ||||
|             Type json_type, Type value_type, ImporterFunc importer) | ||||
|         { | ||||
|             if (! table.ContainsKey (json_type)) | ||||
|                 table.Add (json_type, new Dictionary<Type, ImporterFunc> ()); | ||||
| 
 | ||||
|             table[json_type][value_type] = importer; | ||||
|         } | ||||
| 
 | ||||
|         private static void WriteValue (object obj, JsonWriter writer, | ||||
|                                         bool writer_is_private, | ||||
|                                         int depth) | ||||
|         { | ||||
|             if (depth > max_nesting_depth) | ||||
|                 throw new JsonException ( | ||||
|                     String.Format ("Max allowed object depth reached while " + | ||||
|                                    "trying to export from type {0}", | ||||
|                                    obj.GetType ())); | ||||
| 
 | ||||
|             if (obj == null) { | ||||
|                 writer.Write (null); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (obj is IJsonWrapper) { | ||||
|                 if (writer_is_private) | ||||
|                     writer.TextWriter.Write (((IJsonWrapper) obj).ToJson ()); | ||||
|                 else | ||||
|                     ((IJsonWrapper) obj).ToJson (writer); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (obj is String) { | ||||
|                 writer.Write ((string) obj); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (obj is Double) { | ||||
|                 writer.Write ((double) obj); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (obj is Single) | ||||
|             { | ||||
|                 writer.Write((float)obj); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (obj is Int32) { | ||||
|                 writer.Write ((int) obj); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (obj is Boolean) { | ||||
|                 writer.Write ((bool) obj); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (obj is Int64) { | ||||
|                 writer.Write ((long) obj); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (obj is Array) { | ||||
|                 writer.WriteArrayStart (); | ||||
| 
 | ||||
|                 foreach (object elem in (Array) obj) | ||||
|                     WriteValue (elem, writer, writer_is_private, depth + 1); | ||||
| 
 | ||||
|                 writer.WriteArrayEnd (); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (obj is IList) { | ||||
|                 writer.WriteArrayStart (); | ||||
|                 foreach (object elem in (IList) obj) | ||||
|                     WriteValue (elem, writer, writer_is_private, depth + 1); | ||||
|                 writer.WriteArrayEnd (); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (obj is IDictionary dictionary) { | ||||
|                 writer.WriteObjectStart (); | ||||
|                 foreach (DictionaryEntry entry in dictionary) { | ||||
|                     var propertyName = entry.Key is string key ? | ||||
|                         key | ||||
|                         : Convert.ToString(entry.Key, CultureInfo.InvariantCulture); | ||||
|                     writer.WritePropertyName (propertyName); | ||||
|                     WriteValue (entry.Value, writer, writer_is_private, | ||||
|                                 depth + 1); | ||||
|                 } | ||||
|                 writer.WriteObjectEnd (); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             Type obj_type = obj.GetType (); | ||||
| 
 | ||||
|             // See if there's a custom exporter for the object | ||||
|             lock (custom_exporters_table_lock) { | ||||
|                 if (custom_exporters_table.TryGetValue(obj_type, out ExporterFunc customExporter)) { | ||||
|                     customExporter(obj, writer); | ||||
| 
 | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // If not, maybe there's a base exporter | ||||
|             if (base_exporters_table.TryGetValue(obj_type, out ExporterFunc baseExporter)) { | ||||
|                 baseExporter(obj, writer); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             // Last option, let's see if it's an enum | ||||
|             if (obj is Enum) { | ||||
|                 Type e_type = Enum.GetUnderlyingType (obj_type); | ||||
| 
 | ||||
|                 if (e_type == typeof (long)) | ||||
|                     writer.Write ((long) obj); | ||||
|                 else if (e_type == typeof (uint)) | ||||
|                     writer.Write ((uint) obj); | ||||
|                 else if (e_type == typeof (ulong)) | ||||
|                     writer.Write ((ulong) obj); | ||||
|                 else if (e_type == typeof(ushort)) | ||||
|                     writer.Write ((ushort)obj); | ||||
|                 else if (e_type == typeof(short)) | ||||
|                     writer.Write ((short)obj); | ||||
|                 else if (e_type == typeof(byte)) | ||||
|                     writer.Write ((byte)obj); | ||||
|                 else if (e_type == typeof(sbyte)) | ||||
|                     writer.Write ((sbyte)obj); | ||||
|                 else | ||||
|                     writer.Write ((int) obj); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             // Okay, so it looks like the input should be exported as an | ||||
|             // object | ||||
|             AddTypeProperties (obj_type); | ||||
|             IList<PropertyMetadata> props = type_properties[obj_type]; | ||||
| 
 | ||||
|             writer.WriteObjectStart (); | ||||
|             foreach (PropertyMetadata p_data in props) { | ||||
|                 if (p_data.IsField) { | ||||
|                     writer.WritePropertyName (p_data.Info.Name); | ||||
|                     WriteValue (((FieldInfo) p_data.Info).GetValue (obj), | ||||
|                                 writer, writer_is_private, depth + 1); | ||||
|                 } | ||||
|                 else { | ||||
|                     PropertyInfo p_info = (PropertyInfo) p_data.Info; | ||||
| 
 | ||||
|                     if (p_info.CanRead) { | ||||
|                         writer.WritePropertyName (p_data.Info.Name); | ||||
|                         WriteValue (p_info.GetValue (obj, null), | ||||
|                                     writer, writer_is_private, depth + 1); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             writer.WriteObjectEnd (); | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         public static string ToJson (object obj) | ||||
|         { | ||||
|             lock (static_writer_lock) { | ||||
|                 static_writer.Reset (); | ||||
| 
 | ||||
|                 WriteValue (obj, static_writer, true, 0); | ||||
| 
 | ||||
|                 return static_writer.ToString (); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static void ToJson (object obj, JsonWriter writer) | ||||
|         { | ||||
|             WriteValue (obj, writer, false, 0); | ||||
|         } | ||||
| 
 | ||||
|         public static JsonData ToObject (JsonReader reader) | ||||
|         { | ||||
|             return (JsonData) ToWrapper ( | ||||
|                 delegate { return new JsonData (); }, reader); | ||||
|         } | ||||
| 
 | ||||
|         public static JsonData ToObject (TextReader reader) | ||||
|         { | ||||
|             JsonReader json_reader = new JsonReader (reader); | ||||
| 
 | ||||
|             return (JsonData) ToWrapper ( | ||||
|                 delegate { return new JsonData (); }, json_reader); | ||||
|         } | ||||
| 
 | ||||
|         public static JsonData ToObject (string json) | ||||
|         { | ||||
|             return (JsonData) ToWrapper ( | ||||
|                 delegate { return new JsonData (); }, json); | ||||
|         } | ||||
| 
 | ||||
|         public static T ToObject<T> (JsonReader reader) | ||||
|         { | ||||
|             return (T) ReadValue (typeof (T), reader); | ||||
|         } | ||||
| 
 | ||||
|         public static T ToObject<T> (TextReader reader) | ||||
|         { | ||||
|             JsonReader json_reader = new JsonReader (reader); | ||||
| 
 | ||||
|             return (T) ReadValue (typeof (T), json_reader); | ||||
|         } | ||||
| 
 | ||||
|         public static T ToObject<T> (string json) | ||||
|         { | ||||
|             JsonReader reader = new JsonReader (json); | ||||
| 
 | ||||
|             return (T) ReadValue (typeof (T), reader); | ||||
|         } | ||||
| 
 | ||||
|         public static object ToObject(string json, Type ConvertType ) | ||||
|         { | ||||
|             JsonReader reader = new JsonReader(json); | ||||
| 
 | ||||
|             return ReadValue(ConvertType, reader); | ||||
|         } | ||||
| 
 | ||||
|         public static IJsonWrapper ToWrapper (WrapperFactory factory, | ||||
|                                               JsonReader reader) | ||||
|         { | ||||
|             return ReadValue (factory, reader); | ||||
|         } | ||||
| 
 | ||||
|         public static IJsonWrapper ToWrapper (WrapperFactory factory, | ||||
|                                               string json) | ||||
|         { | ||||
|             JsonReader reader = new JsonReader (json); | ||||
| 
 | ||||
|             return ReadValue (factory, reader); | ||||
|         } | ||||
| 
 | ||||
|         public static void RegisterExporter<T> (ExporterFunc<T> exporter) | ||||
|         { | ||||
|             ExporterFunc exporter_wrapper = | ||||
|                 delegate (object obj, JsonWriter writer) { | ||||
|                     exporter ((T) obj, writer); | ||||
|                 }; | ||||
| 
 | ||||
|             lock (custom_exporters_table_lock) {  | ||||
|                 custom_exporters_table[typeof (T)] = exporter_wrapper; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static void RegisterImporter<TJson, TValue> ( | ||||
|             ImporterFunc<TJson, TValue> importer) | ||||
|         { | ||||
|             ImporterFunc importer_wrapper = | ||||
|                 delegate (object input) { | ||||
|                     return importer ((TJson) input); | ||||
|                 }; | ||||
| 
 | ||||
|             lock (custom_importers_table_lock) { | ||||
|                 RegisterImporter (custom_importers_table, typeof (TJson), | ||||
|                                  typeof (TValue), importer_wrapper); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static void UnregisterExporters () | ||||
|         { | ||||
|             lock (custom_exporters_table_lock) { | ||||
|                 custom_exporters_table.Clear(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static void UnregisterImporters () | ||||
|         { | ||||
|             lock (custom_importers_table_lock) { | ||||
|                 custom_importers_table.Clear(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 3e14ed6947460448ea1c1512947ced5d | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,105 @@ | |||
| #region Header | ||||
| /** | ||||
|  * JsonMockWrapper.cs | ||||
|  *   Mock object implementing IJsonWrapper, to facilitate actions like | ||||
|  *   skipping data more efficiently. | ||||
|  * | ||||
|  * The authors disclaim copyright to this source code. For more details, see | ||||
|  * the COPYING file included with this distribution. | ||||
|  **/ | ||||
| #endregion | ||||
| 
 | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Specialized; | ||||
| 
 | ||||
| 
 | ||||
| namespace Guru.LitJson | ||||
| { | ||||
|     public class JsonMockWrapper : IJsonWrapper | ||||
|     { | ||||
|         public bool IsArray   { get { return false; } } | ||||
|         public bool IsBoolean { get { return false; } } | ||||
|         public bool IsDouble  { get { return false; } } | ||||
|         public bool IsInt     { get { return false; } } | ||||
|         public bool IsLong    { get { return false; } } | ||||
|         public bool IsObject  { get { return false; } } | ||||
|         public bool IsString  { get { return false; } } | ||||
| 
 | ||||
|         public bool     GetBoolean ()  { return false; } | ||||
|         public double   GetDouble ()   { return 0.0; } | ||||
|         public int      GetInt ()      { return 0; } | ||||
|         public JsonType GetJsonType () { return JsonType.None; } | ||||
|         public long     GetLong ()     { return 0L; } | ||||
|         public string   GetString ()   { return ""; } | ||||
| 
 | ||||
|         public void SetBoolean  (bool val)      {} | ||||
|         public void SetDouble   (double val)    {} | ||||
|         public void SetInt      (int val)       {} | ||||
|         public void SetJsonType (JsonType type) {} | ||||
|         public void SetLong     (long val)      {} | ||||
|         public void SetString   (string val)    {} | ||||
| 
 | ||||
|         public string ToJson ()                  { return ""; } | ||||
|         public void   ToJson (JsonWriter writer) {} | ||||
| 
 | ||||
| 
 | ||||
|         bool IList.IsFixedSize { get { return true; } } | ||||
|         bool IList.IsReadOnly  { get { return true; } } | ||||
| 
 | ||||
|         object IList.this[int index] { | ||||
|             get { return null; } | ||||
|             set {} | ||||
|         } | ||||
| 
 | ||||
|         int  IList.Add (object value)       { return 0; } | ||||
|         void IList.Clear ()                 {} | ||||
|         bool IList.Contains (object value)  { return false; } | ||||
|         int  IList.IndexOf (object value)   { return -1; } | ||||
|         void IList.Insert (int i, object v) {} | ||||
|         void IList.Remove (object value)    {} | ||||
|         void IList.RemoveAt (int index)     {} | ||||
| 
 | ||||
| 
 | ||||
|         int    ICollection.Count          { get { return 0; } } | ||||
|         bool   ICollection.IsSynchronized { get { return false; } } | ||||
|         object ICollection.SyncRoot       { get { return null; } } | ||||
| 
 | ||||
|         void ICollection.CopyTo (Array array, int index) {} | ||||
| 
 | ||||
| 
 | ||||
|         IEnumerator IEnumerable.GetEnumerator () { return null; } | ||||
| 
 | ||||
| 
 | ||||
|         bool IDictionary.IsFixedSize { get { return true; } } | ||||
|         bool IDictionary.IsReadOnly  { get { return true; } } | ||||
| 
 | ||||
|         ICollection IDictionary.Keys   { get { return null; } } | ||||
|         ICollection IDictionary.Values { get { return null; } } | ||||
| 
 | ||||
|         object IDictionary.this[object key] { | ||||
|             get { return null; } | ||||
|             set {} | ||||
|         } | ||||
| 
 | ||||
|         void IDictionary.Add (object k, object v) {} | ||||
|         void IDictionary.Clear ()                 {} | ||||
|         bool IDictionary.Contains (object key)    { return false; } | ||||
|         void IDictionary.Remove (object key)      {} | ||||
| 
 | ||||
|         IDictionaryEnumerator IDictionary.GetEnumerator () { return null; } | ||||
| 
 | ||||
| 
 | ||||
|         object IOrderedDictionary.this[int idx] { | ||||
|             get { return null; } | ||||
|             set {} | ||||
|         } | ||||
| 
 | ||||
|         IDictionaryEnumerator IOrderedDictionary.GetEnumerator () { | ||||
|             return null; | ||||
|         } | ||||
|         void IOrderedDictionary.Insert   (int i, object k, object v) {} | ||||
|         void IOrderedDictionary.RemoveAt (int i) {} | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: b54da0524de4e4164893c964b0b7b443 | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,478 @@ | |||
| #region Header | ||||
| /** | ||||
|  * JsonReader.cs | ||||
|  *   Stream-like access to JSON text. | ||||
|  * | ||||
|  * The authors disclaim copyright to this source code. For more details, see | ||||
|  * the COPYING file included with this distribution. | ||||
|  **/ | ||||
| #endregion | ||||
| 
 | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Globalization; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| 
 | ||||
| 
 | ||||
| namespace Guru.LitJson | ||||
| { | ||||
|     public enum JsonToken | ||||
|     { | ||||
|         None, | ||||
| 
 | ||||
|         ObjectStart, | ||||
|         PropertyName, | ||||
|         ObjectEnd, | ||||
| 
 | ||||
|         ArrayStart, | ||||
|         ArrayEnd, | ||||
| 
 | ||||
|         Int, | ||||
|         Long, | ||||
|         Double, | ||||
| 
 | ||||
|         String, | ||||
| 
 | ||||
|         Boolean, | ||||
|         Null | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public class JsonReader | ||||
|     { | ||||
|         #region Fields | ||||
|         private static readonly IDictionary<int, IDictionary<int, int[]>> parse_table; | ||||
| 
 | ||||
|         private Stack<int>    automaton_stack; | ||||
|         private int           current_input; | ||||
|         private int           current_symbol; | ||||
|         private bool          end_of_json; | ||||
|         private bool          end_of_input; | ||||
|         private Lexer         lexer; | ||||
|         private bool          parser_in_string; | ||||
|         private bool          parser_return; | ||||
|         private bool          read_started; | ||||
|         private TextReader    reader; | ||||
|         private bool          reader_is_owned; | ||||
|         private bool          skip_non_members; | ||||
|         private object        token_value; | ||||
|         private JsonToken     token; | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Public Properties | ||||
|         public bool AllowComments { | ||||
|             get { return lexer.AllowComments; } | ||||
|             set { lexer.AllowComments = value; } | ||||
|         } | ||||
| 
 | ||||
|         public bool AllowSingleQuotedStrings { | ||||
|             get { return lexer.AllowSingleQuotedStrings; } | ||||
|             set { lexer.AllowSingleQuotedStrings = value; } | ||||
|         } | ||||
| 
 | ||||
|         public bool SkipNonMembers { | ||||
|             get { return skip_non_members; } | ||||
|             set { skip_non_members = value; } | ||||
|         } | ||||
| 
 | ||||
|         public bool EndOfInput { | ||||
|             get { return end_of_input; } | ||||
|         } | ||||
| 
 | ||||
|         public bool EndOfJson { | ||||
|             get { return end_of_json; } | ||||
|         } | ||||
| 
 | ||||
|         public JsonToken Token { | ||||
|             get { return token; } | ||||
|         } | ||||
| 
 | ||||
|         public object Value { | ||||
|             get { return token_value; } | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Constructors | ||||
|         static JsonReader () | ||||
|         { | ||||
|             parse_table = PopulateParseTable (); | ||||
|         } | ||||
| 
 | ||||
|         public JsonReader (string json_text) : | ||||
|             this (new StringReader (json_text), true) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public JsonReader (TextReader reader) : | ||||
|             this (reader, false) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         private JsonReader (TextReader reader, bool owned) | ||||
|         { | ||||
|             if (reader == null) | ||||
|                 throw new ArgumentNullException ("reader"); | ||||
| 
 | ||||
|             parser_in_string = false; | ||||
|             parser_return    = false; | ||||
| 
 | ||||
|             read_started = false; | ||||
|             automaton_stack = new Stack<int> (); | ||||
|             automaton_stack.Push ((int) ParserToken.End); | ||||
|             automaton_stack.Push ((int) ParserToken.Text); | ||||
| 
 | ||||
|             lexer = new Lexer (reader); | ||||
| 
 | ||||
|             end_of_input = false; | ||||
|             end_of_json  = false; | ||||
| 
 | ||||
|             skip_non_members = true; | ||||
| 
 | ||||
|             this.reader = reader; | ||||
|             reader_is_owned = owned; | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Static Methods | ||||
|         private static IDictionary<int, IDictionary<int, int[]>> PopulateParseTable () | ||||
|         { | ||||
|             // See section A.2. of the manual for details | ||||
|             IDictionary<int, IDictionary<int, int[]>> parse_table = new Dictionary<int, IDictionary<int, int[]>> (); | ||||
| 
 | ||||
|             TableAddRow (parse_table, ParserToken.Array); | ||||
|             TableAddCol (parse_table, ParserToken.Array, '[', | ||||
|                             '[', | ||||
|                             (int) ParserToken.ArrayPrime); | ||||
| 
 | ||||
|             TableAddRow (parse_table, ParserToken.ArrayPrime); | ||||
|             TableAddCol (parse_table, ParserToken.ArrayPrime, '"', | ||||
|                             (int) ParserToken.Value, | ||||
| 
 | ||||
|                             (int) ParserToken.ValueRest, | ||||
|                             ']'); | ||||
|             TableAddCol (parse_table, ParserToken.ArrayPrime, '[', | ||||
|                             (int) ParserToken.Value, | ||||
|                             (int) ParserToken.ValueRest, | ||||
|                             ']'); | ||||
|             TableAddCol (parse_table, ParserToken.ArrayPrime, ']', | ||||
|                             ']'); | ||||
|             TableAddCol (parse_table, ParserToken.ArrayPrime, '{', | ||||
|                             (int) ParserToken.Value, | ||||
|                             (int) ParserToken.ValueRest, | ||||
|                             ']'); | ||||
|             TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.Number, | ||||
|                             (int) ParserToken.Value, | ||||
|                             (int) ParserToken.ValueRest, | ||||
|                             ']'); | ||||
|             TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.True, | ||||
|                             (int) ParserToken.Value, | ||||
|                             (int) ParserToken.ValueRest, | ||||
|                             ']'); | ||||
|             TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.False, | ||||
|                             (int) ParserToken.Value, | ||||
|                             (int) ParserToken.ValueRest, | ||||
|                             ']'); | ||||
|             TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.Null, | ||||
|                             (int) ParserToken.Value, | ||||
|                             (int) ParserToken.ValueRest, | ||||
|                             ']'); | ||||
| 
 | ||||
|             TableAddRow (parse_table, ParserToken.Object); | ||||
|             TableAddCol (parse_table, ParserToken.Object, '{', | ||||
|                             '{', | ||||
|                             (int) ParserToken.ObjectPrime); | ||||
| 
 | ||||
|             TableAddRow (parse_table, ParserToken.ObjectPrime); | ||||
|             TableAddCol (parse_table, ParserToken.ObjectPrime, '"', | ||||
|                             (int) ParserToken.Pair, | ||||
|                             (int) ParserToken.PairRest, | ||||
|                             '}'); | ||||
|             TableAddCol (parse_table, ParserToken.ObjectPrime, '}', | ||||
|                             '}'); | ||||
| 
 | ||||
|             TableAddRow (parse_table, ParserToken.Pair); | ||||
|             TableAddCol (parse_table, ParserToken.Pair, '"', | ||||
|                             (int) ParserToken.String, | ||||
|                             ':', | ||||
|                             (int) ParserToken.Value); | ||||
| 
 | ||||
|             TableAddRow (parse_table, ParserToken.PairRest); | ||||
|             TableAddCol (parse_table, ParserToken.PairRest, ',', | ||||
|                             ',', | ||||
|                             (int) ParserToken.Pair, | ||||
|                             (int) ParserToken.PairRest); | ||||
|             TableAddCol (parse_table, ParserToken.PairRest, '}', | ||||
|                             (int) ParserToken.Epsilon); | ||||
| 
 | ||||
|             TableAddRow (parse_table, ParserToken.String); | ||||
|             TableAddCol (parse_table, ParserToken.String, '"', | ||||
|                             '"', | ||||
|                             (int) ParserToken.CharSeq, | ||||
|                             '"'); | ||||
| 
 | ||||
|             TableAddRow (parse_table, ParserToken.Text); | ||||
|             TableAddCol (parse_table, ParserToken.Text, '[', | ||||
|                             (int) ParserToken.Array); | ||||
|             TableAddCol (parse_table, ParserToken.Text, '{', | ||||
|                             (int) ParserToken.Object); | ||||
| 
 | ||||
|             TableAddRow (parse_table, ParserToken.Value); | ||||
|             TableAddCol (parse_table, ParserToken.Value, '"', | ||||
|                             (int) ParserToken.String); | ||||
|             TableAddCol (parse_table, ParserToken.Value, '[', | ||||
|                             (int) ParserToken.Array); | ||||
|             TableAddCol (parse_table, ParserToken.Value, '{', | ||||
|                             (int) ParserToken.Object); | ||||
|             TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.Number, | ||||
|                             (int) ParserToken.Number); | ||||
|             TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.True, | ||||
|                             (int) ParserToken.True); | ||||
|             TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.False, | ||||
|                             (int) ParserToken.False); | ||||
|             TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.Null, | ||||
|                             (int) ParserToken.Null); | ||||
| 
 | ||||
|             TableAddRow (parse_table, ParserToken.ValueRest); | ||||
|             TableAddCol (parse_table, ParserToken.ValueRest, ',', | ||||
|                             ',', | ||||
|                             (int) ParserToken.Value, | ||||
|                             (int) ParserToken.ValueRest); | ||||
|             TableAddCol (parse_table, ParserToken.ValueRest, ']', | ||||
|                             (int) ParserToken.Epsilon); | ||||
| 
 | ||||
|             return parse_table; | ||||
|         } | ||||
| 
 | ||||
|         private static void TableAddCol (IDictionary<int, IDictionary<int, int[]>> parse_table, ParserToken row, int col, | ||||
|                                          params int[] symbols) | ||||
|         { | ||||
|             parse_table[(int) row].Add (col, symbols); | ||||
|         } | ||||
| 
 | ||||
|         private static void TableAddRow (IDictionary<int, IDictionary<int, int[]>> parse_table, ParserToken rule) | ||||
|         { | ||||
|             parse_table.Add ((int) rule, new Dictionary<int, int[]> ()); | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Private Methods | ||||
|         private void ProcessNumber (string number) | ||||
|         { | ||||
|             if (number.IndexOf ('.') != -1 || | ||||
|                 number.IndexOf ('e') != -1 || | ||||
|                 number.IndexOf ('E') != -1) { | ||||
| 
 | ||||
|                 double n_double; | ||||
|                 if (double.TryParse (number, NumberStyles.Any, CultureInfo.InvariantCulture, out n_double)) { | ||||
|                     token = JsonToken.Double; | ||||
|                     token_value = n_double; | ||||
| 
 | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             int n_int32; | ||||
|             if (int.TryParse (number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int32)) { | ||||
|                 token = JsonToken.Int; | ||||
|                 token_value = n_int32; | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             long n_int64; | ||||
|             if (long.TryParse (number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int64)) { | ||||
|                 token = JsonToken.Long; | ||||
|                 token_value = n_int64; | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             ulong n_uint64; | ||||
|             if (ulong.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_uint64)) | ||||
|             { | ||||
|                 token = JsonToken.Long; | ||||
|                 token_value = n_uint64; | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             // Shouldn't happen, but just in case, return something | ||||
|             token = JsonToken.Int; | ||||
|             token_value = 0; | ||||
|         } | ||||
| 
 | ||||
|         private void ProcessSymbol () | ||||
|         { | ||||
|             if (current_symbol == '[')  { | ||||
|                 token = JsonToken.ArrayStart; | ||||
|                 parser_return = true; | ||||
| 
 | ||||
|             } else if (current_symbol == ']')  { | ||||
|                 token = JsonToken.ArrayEnd; | ||||
|                 parser_return = true; | ||||
| 
 | ||||
|             } else if (current_symbol == '{')  { | ||||
|                 token = JsonToken.ObjectStart; | ||||
|                 parser_return = true; | ||||
| 
 | ||||
|             } else if (current_symbol == '}')  { | ||||
|                 token = JsonToken.ObjectEnd; | ||||
|                 parser_return = true; | ||||
| 
 | ||||
|             } else if (current_symbol == '"')  { | ||||
|                 if (parser_in_string) { | ||||
|                     parser_in_string = false; | ||||
| 
 | ||||
|                     parser_return = true; | ||||
| 
 | ||||
|                 } else { | ||||
|                     if (token == JsonToken.None) | ||||
|                         token = JsonToken.String; | ||||
| 
 | ||||
|                     parser_in_string = true; | ||||
|                 } | ||||
| 
 | ||||
|             } else if (current_symbol == (int) ParserToken.CharSeq) { | ||||
|                 token_value = lexer.StringValue; | ||||
| 
 | ||||
|             } else if (current_symbol == (int) ParserToken.False)  { | ||||
|                 token = JsonToken.Boolean; | ||||
|                 token_value = false; | ||||
|                 parser_return = true; | ||||
| 
 | ||||
|             } else if (current_symbol == (int) ParserToken.Null)  { | ||||
|                 token = JsonToken.Null; | ||||
|                 parser_return = true; | ||||
| 
 | ||||
|             } else if (current_symbol == (int) ParserToken.Number)  { | ||||
|                 ProcessNumber (lexer.StringValue); | ||||
| 
 | ||||
|                 parser_return = true; | ||||
| 
 | ||||
|             } else if (current_symbol == (int) ParserToken.Pair)  { | ||||
|                 token = JsonToken.PropertyName; | ||||
| 
 | ||||
|             } else if (current_symbol == (int) ParserToken.True)  { | ||||
|                 token = JsonToken.Boolean; | ||||
|                 token_value = true; | ||||
|                 parser_return = true; | ||||
| 
 | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private bool ReadToken () | ||||
|         { | ||||
|             if (end_of_input) | ||||
|                 return false; | ||||
| 
 | ||||
|             lexer.NextToken (); | ||||
| 
 | ||||
|             if (lexer.EndOfInput) { | ||||
|                 Close (); | ||||
| 
 | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             current_input = lexer.Token; | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         public void Close () | ||||
|         { | ||||
|             if (end_of_input) | ||||
|                 return; | ||||
| 
 | ||||
|             end_of_input = true; | ||||
|             end_of_json  = true; | ||||
| 
 | ||||
|             if (reader_is_owned) | ||||
|             { | ||||
|                 using(reader){} | ||||
|             } | ||||
| 
 | ||||
|             reader = null; | ||||
|         } | ||||
| 
 | ||||
|         public bool Read () | ||||
|         { | ||||
|             if (end_of_input) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (end_of_json) { | ||||
|                 end_of_json = false; | ||||
|                 automaton_stack.Clear (); | ||||
|                 automaton_stack.Push ((int) ParserToken.End); | ||||
|                 automaton_stack.Push ((int) ParserToken.Text); | ||||
|             } | ||||
| 
 | ||||
|             parser_in_string = false; | ||||
|             parser_return    = false; | ||||
| 
 | ||||
|             token       = JsonToken.None; | ||||
|             token_value = null; | ||||
| 
 | ||||
|             if (! read_started) { | ||||
|                 read_started = true; | ||||
| 
 | ||||
|                 if (! ReadToken ()) | ||||
|                     return false; | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             int[] entry_symbols; | ||||
| 
 | ||||
|             while (true) { | ||||
|                 if (parser_return) { | ||||
|                     if (automaton_stack.Peek () == (int) ParserToken.End) | ||||
|                         end_of_json = true; | ||||
| 
 | ||||
|                     return true; | ||||
|                 } | ||||
| 
 | ||||
|                 current_symbol = automaton_stack.Pop (); | ||||
| 
 | ||||
|                 ProcessSymbol (); | ||||
| 
 | ||||
|                 if (current_symbol == current_input) { | ||||
|                     if (! ReadToken ()) { | ||||
|                         if (automaton_stack.Peek () != (int) ParserToken.End) | ||||
|                             throw new JsonException ( | ||||
|                                 "Input doesn't evaluate to proper JSON text"); | ||||
| 
 | ||||
|                         if (parser_return) | ||||
|                             return true; | ||||
| 
 | ||||
|                         return false; | ||||
|                     } | ||||
| 
 | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 try { | ||||
| 
 | ||||
|                     entry_symbols = | ||||
|                         parse_table[current_symbol][current_input]; | ||||
| 
 | ||||
|                 } catch (KeyNotFoundException e) { | ||||
|                     throw new JsonException ((ParserToken) current_input, e); | ||||
|                 } | ||||
| 
 | ||||
|                 if (entry_symbols[0] == (int) ParserToken.Epsilon) | ||||
|                     continue; | ||||
| 
 | ||||
|                 for (int i = entry_symbols.Length - 1; i >= 0; i--) | ||||
|                     automaton_stack.Push (entry_symbols[i]); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: a486d94a05da74fb4a2e1d9d1eb53455 | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,484 @@ | |||
| #region Header | ||||
| /** | ||||
|  * JsonWriter.cs | ||||
|  *   Stream-like facility to output JSON text. | ||||
|  * | ||||
|  * The authors disclaim copyright to this source code. For more details, see | ||||
|  * the COPYING file included with this distribution. | ||||
|  **/ | ||||
| #endregion | ||||
| 
 | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Globalization; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| 
 | ||||
| 
 | ||||
| namespace Guru.LitJson | ||||
| { | ||||
|     internal enum Condition | ||||
|     { | ||||
|         InArray, | ||||
|         InObject, | ||||
|         NotAProperty, | ||||
|         Property, | ||||
|         Value | ||||
|     } | ||||
| 
 | ||||
|     internal class WriterContext | ||||
|     { | ||||
|         public int  Count; | ||||
|         public bool InArray; | ||||
|         public bool InObject; | ||||
|         public bool ExpectingValue; | ||||
|         public int  Padding; | ||||
|     } | ||||
| 
 | ||||
|     public class JsonWriter | ||||
|     { | ||||
|         #region Fields | ||||
|         private static readonly NumberFormatInfo number_format; | ||||
| 
 | ||||
|         private WriterContext        context; | ||||
|         private Stack<WriterContext> ctx_stack; | ||||
|         private bool                 has_reached_end; | ||||
|         private char[]               hex_seq; | ||||
|         private int                  indentation; | ||||
|         private int                  indent_value; | ||||
|         private StringBuilder        inst_string_builder; | ||||
|         private bool                 pretty_print; | ||||
|         private bool                 validate; | ||||
|         private bool                 lower_case_properties; | ||||
|         private TextWriter           writer; | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Properties | ||||
|         public int IndentValue { | ||||
|             get { return indent_value; } | ||||
|             set { | ||||
|                 indentation = (indentation / indent_value) * value; | ||||
|                 indent_value = value; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public bool PrettyPrint { | ||||
|             get { return pretty_print; } | ||||
|             set { pretty_print = value; } | ||||
|         } | ||||
| 
 | ||||
|         public TextWriter TextWriter { | ||||
|             get { return writer; } | ||||
|         } | ||||
| 
 | ||||
|         public bool Validate { | ||||
|             get { return validate; } | ||||
|             set { validate = value; } | ||||
|         } | ||||
| 
 | ||||
|         public bool LowerCaseProperties { | ||||
|             get { return lower_case_properties; } | ||||
|             set { lower_case_properties = value; } | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Constructors | ||||
|         static JsonWriter () | ||||
|         { | ||||
|             number_format = NumberFormatInfo.InvariantInfo; | ||||
|         } | ||||
| 
 | ||||
|         public JsonWriter () | ||||
|         { | ||||
|             inst_string_builder = new StringBuilder (); | ||||
|             writer = new StringWriter (inst_string_builder); | ||||
| 
 | ||||
|             Init (); | ||||
|         } | ||||
| 
 | ||||
|         public JsonWriter (StringBuilder sb) : | ||||
|             this (new StringWriter (sb)) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public JsonWriter (TextWriter writer) | ||||
|         { | ||||
|             if (writer == null) | ||||
|                 throw new ArgumentNullException ("writer"); | ||||
| 
 | ||||
|             this.writer = writer; | ||||
| 
 | ||||
|             Init (); | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Private Methods | ||||
|         private void DoValidation (Condition cond) | ||||
|         { | ||||
|             if (! context.ExpectingValue) | ||||
|                 context.Count++; | ||||
| 
 | ||||
|             if (! validate) | ||||
|                 return; | ||||
| 
 | ||||
|             if (has_reached_end) | ||||
|                 throw new JsonException ( | ||||
|                     "A complete JSON symbol has already been written"); | ||||
| 
 | ||||
|             switch (cond) { | ||||
|             case Condition.InArray: | ||||
|                 if (! context.InArray) | ||||
|                     throw new JsonException ( | ||||
|                         "Can't close an array here"); | ||||
|                 break; | ||||
| 
 | ||||
|             case Condition.InObject: | ||||
|                 if (! context.InObject || context.ExpectingValue) | ||||
|                     throw new JsonException ( | ||||
|                         "Can't close an object here"); | ||||
|                 break; | ||||
| 
 | ||||
|             case Condition.NotAProperty: | ||||
|                 if (context.InObject && ! context.ExpectingValue) | ||||
|                     throw new JsonException ( | ||||
|                         "Expected a property"); | ||||
|                 break; | ||||
| 
 | ||||
|             case Condition.Property: | ||||
|                 if (! context.InObject || context.ExpectingValue) | ||||
|                     throw new JsonException ( | ||||
|                         "Can't add a property here"); | ||||
|                 break; | ||||
| 
 | ||||
|             case Condition.Value: | ||||
|                 if (! context.InArray && | ||||
|                     (! context.InObject || ! context.ExpectingValue)) | ||||
|                     throw new JsonException ( | ||||
|                         "Can't add a value here"); | ||||
| 
 | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void Init () | ||||
|         { | ||||
|             has_reached_end = false; | ||||
|             hex_seq = new char[4]; | ||||
|             indentation = 0; | ||||
|             indent_value = 4; | ||||
|             pretty_print = false; | ||||
|             validate = true; | ||||
|             lower_case_properties = false; | ||||
| 
 | ||||
|             ctx_stack = new Stack<WriterContext> (); | ||||
|             context = new WriterContext (); | ||||
|             ctx_stack.Push (context); | ||||
|         } | ||||
| 
 | ||||
|         private static void IntToHex (int n, char[] hex) | ||||
|         { | ||||
|             int num; | ||||
| 
 | ||||
|             for (int i = 0; i < 4; i++) { | ||||
|                 num = n % 16; | ||||
| 
 | ||||
|                 if (num < 10) | ||||
|                     hex[3 - i] = (char) ('0' + num); | ||||
|                 else | ||||
|                     hex[3 - i] = (char) ('A' + (num - 10)); | ||||
| 
 | ||||
|                 n >>= 4; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void Indent () | ||||
|         { | ||||
|             if (pretty_print) | ||||
|                 indentation += indent_value; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         private void Put (string str) | ||||
|         { | ||||
|             if (pretty_print && ! context.ExpectingValue) | ||||
|                 for (int i = 0; i < indentation; i++) | ||||
|                     writer.Write (' '); | ||||
| 
 | ||||
|             writer.Write (str); | ||||
|         } | ||||
| 
 | ||||
|         private void PutNewline () | ||||
|         { | ||||
|             PutNewline (true); | ||||
|         } | ||||
| 
 | ||||
|         private void PutNewline (bool add_comma) | ||||
|         { | ||||
|             if (add_comma && ! context.ExpectingValue && | ||||
|                 context.Count > 1) | ||||
|                 writer.Write (','); | ||||
| 
 | ||||
|             if (pretty_print && ! context.ExpectingValue) | ||||
|                 writer.Write (Environment.NewLine); | ||||
|         } | ||||
| 
 | ||||
|         private void PutString (string str) | ||||
|         { | ||||
|             Put (String.Empty); | ||||
| 
 | ||||
|             writer.Write ('"'); | ||||
| 
 | ||||
|             int n = str.Length; | ||||
|             for (int i = 0; i < n; i++) { | ||||
|                 switch (str[i]) { | ||||
|                 case '\n': | ||||
|                     writer.Write ("\\n"); | ||||
|                     continue; | ||||
| 
 | ||||
|                 case '\r': | ||||
|                     writer.Write ("\\r"); | ||||
|                     continue; | ||||
| 
 | ||||
|                 case '\t': | ||||
|                     writer.Write ("\\t"); | ||||
|                     continue; | ||||
| 
 | ||||
|                 case '"': | ||||
|                 case '\\': | ||||
|                     writer.Write ('\\'); | ||||
|                     writer.Write (str[i]); | ||||
|                     continue; | ||||
| 
 | ||||
|                 case '\f': | ||||
|                     writer.Write ("\\f"); | ||||
|                     continue; | ||||
| 
 | ||||
|                 case '\b': | ||||
|                     writer.Write ("\\b"); | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 if ((int) str[i] >= 32 && (int) str[i] <= 126) { | ||||
|                     writer.Write (str[i]); | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 // Default, turn into a \uXXXX sequence | ||||
|                 IntToHex ((int) str[i], hex_seq); | ||||
|                 writer.Write ("\\u"); | ||||
|                 writer.Write (hex_seq); | ||||
|             } | ||||
| 
 | ||||
|             writer.Write ('"'); | ||||
|         } | ||||
| 
 | ||||
|         private void Unindent () | ||||
|         { | ||||
|             if (pretty_print) | ||||
|                 indentation -= indent_value; | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         public override string ToString () | ||||
|         { | ||||
|             if (inst_string_builder == null) | ||||
|                 return String.Empty; | ||||
| 
 | ||||
|             return inst_string_builder.ToString (); | ||||
|         } | ||||
| 
 | ||||
|         public void Reset () | ||||
|         { | ||||
|             has_reached_end = false; | ||||
| 
 | ||||
|             ctx_stack.Clear (); | ||||
|             context = new WriterContext (); | ||||
|             ctx_stack.Push (context); | ||||
| 
 | ||||
|             if (inst_string_builder != null) | ||||
|                 inst_string_builder.Remove (0, inst_string_builder.Length); | ||||
|         } | ||||
| 
 | ||||
|         public void Write (bool boolean) | ||||
|         { | ||||
|             DoValidation (Condition.Value); | ||||
|             PutNewline (); | ||||
| 
 | ||||
|             Put (boolean ? "true" : "false"); | ||||
| 
 | ||||
|             context.ExpectingValue = false; | ||||
|         } | ||||
| 
 | ||||
|         public void Write (decimal number) | ||||
|         { | ||||
|             DoValidation (Condition.Value); | ||||
|             PutNewline (); | ||||
| 
 | ||||
|             Put (Convert.ToString (number, number_format)); | ||||
| 
 | ||||
|             context.ExpectingValue = false; | ||||
|         } | ||||
| 
 | ||||
|         public void Write (double number) | ||||
|         { | ||||
|             DoValidation (Condition.Value); | ||||
|             PutNewline (); | ||||
| 
 | ||||
|             string str = Convert.ToString (number, number_format); | ||||
|             Put (str); | ||||
| 
 | ||||
|             if (str.IndexOf ('.') == -1 && | ||||
|                 str.IndexOf ('E') == -1) | ||||
|                 writer.Write (".0"); | ||||
| 
 | ||||
|             context.ExpectingValue = false; | ||||
|         } | ||||
| 
 | ||||
|         public void Write(float number) | ||||
|         { | ||||
|             DoValidation(Condition.Value); | ||||
|             PutNewline(); | ||||
| 
 | ||||
|             string str = Convert.ToString(number, number_format); | ||||
|             Put(str); | ||||
| 
 | ||||
|             context.ExpectingValue = false; | ||||
|         } | ||||
| 
 | ||||
|         public void Write (int number) | ||||
|         { | ||||
|             DoValidation (Condition.Value); | ||||
|             PutNewline (); | ||||
| 
 | ||||
|             Put (Convert.ToString (number, number_format)); | ||||
| 
 | ||||
|             context.ExpectingValue = false; | ||||
|         } | ||||
| 
 | ||||
|         public void Write (long number) | ||||
|         { | ||||
|             DoValidation (Condition.Value); | ||||
|             PutNewline (); | ||||
| 
 | ||||
|             Put (Convert.ToString (number, number_format)); | ||||
| 
 | ||||
|             context.ExpectingValue = false; | ||||
|         } | ||||
| 
 | ||||
|         public void Write (string str) | ||||
|         { | ||||
|             DoValidation (Condition.Value); | ||||
|             PutNewline (); | ||||
| 
 | ||||
|             if (str == null) | ||||
|                 Put ("null"); | ||||
|             else | ||||
|                 PutString (str); | ||||
| 
 | ||||
|             context.ExpectingValue = false; | ||||
|         } | ||||
| 
 | ||||
|         [CLSCompliant(false)] | ||||
|         public void Write (ulong number) | ||||
|         { | ||||
|             DoValidation (Condition.Value); | ||||
|             PutNewline (); | ||||
| 
 | ||||
|             Put (Convert.ToString (number, number_format)); | ||||
| 
 | ||||
|             context.ExpectingValue = false; | ||||
|         } | ||||
| 
 | ||||
|         public void WriteArrayEnd () | ||||
|         { | ||||
|             DoValidation (Condition.InArray); | ||||
|             PutNewline (false); | ||||
| 
 | ||||
|             ctx_stack.Pop (); | ||||
|             if (ctx_stack.Count == 1) | ||||
|                 has_reached_end = true; | ||||
|             else { | ||||
|                 context = ctx_stack.Peek (); | ||||
|                 context.ExpectingValue = false; | ||||
|             } | ||||
| 
 | ||||
|             Unindent (); | ||||
|             Put ("]"); | ||||
|         } | ||||
| 
 | ||||
|         public void WriteArrayStart () | ||||
|         { | ||||
|             DoValidation (Condition.NotAProperty); | ||||
|             PutNewline (); | ||||
| 
 | ||||
|             Put ("["); | ||||
| 
 | ||||
|             context = new WriterContext (); | ||||
|             context.InArray = true; | ||||
|             ctx_stack.Push (context); | ||||
| 
 | ||||
|             Indent (); | ||||
|         } | ||||
| 
 | ||||
|         public void WriteObjectEnd () | ||||
|         { | ||||
|             DoValidation (Condition.InObject); | ||||
|             PutNewline (false); | ||||
| 
 | ||||
|             ctx_stack.Pop (); | ||||
|             if (ctx_stack.Count == 1) | ||||
|                 has_reached_end = true; | ||||
|             else { | ||||
|                 context = ctx_stack.Peek (); | ||||
|                 context.ExpectingValue = false; | ||||
|             } | ||||
| 
 | ||||
|             Unindent (); | ||||
|             Put ("}"); | ||||
|         } | ||||
| 
 | ||||
|         public void WriteObjectStart () | ||||
|         { | ||||
|             DoValidation (Condition.NotAProperty); | ||||
|             PutNewline (); | ||||
| 
 | ||||
|             Put ("{"); | ||||
| 
 | ||||
|             context = new WriterContext (); | ||||
|             context.InObject = true; | ||||
|             ctx_stack.Push (context); | ||||
| 
 | ||||
|             Indent (); | ||||
|         } | ||||
| 
 | ||||
|         public void WritePropertyName (string property_name) | ||||
|         { | ||||
|             DoValidation (Condition.Property); | ||||
|             PutNewline (); | ||||
|             string propertyName = (property_name == null || !lower_case_properties) | ||||
|                 ? property_name | ||||
|                 : property_name.ToLowerInvariant(); | ||||
| 
 | ||||
|             PutString (propertyName); | ||||
| 
 | ||||
|             if (pretty_print) { | ||||
|                 if (propertyName.Length > context.Padding) | ||||
|                     context.Padding = propertyName.Length; | ||||
| 
 | ||||
|                 for (int i = context.Padding - propertyName.Length; | ||||
|                      i >= 0; i--) | ||||
|                     writer.Write (' '); | ||||
| 
 | ||||
|                 writer.Write (": "); | ||||
|             } else | ||||
|                 writer.Write (':'); | ||||
| 
 | ||||
|             context.ExpectingValue = true; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: b5c3c60bc9e974025813d454b53835e1 | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,912 @@ | |||
| #region Header | ||||
| /** | ||||
|  * Lexer.cs | ||||
|  *   JSON lexer implementation based on a finite state machine. | ||||
|  * | ||||
|  * The authors disclaim copyright to this source code. For more details, see | ||||
|  * the COPYING file included with this distribution. | ||||
|  **/ | ||||
| #endregion | ||||
| 
 | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| 
 | ||||
| 
 | ||||
| namespace Guru.LitJson | ||||
| { | ||||
|     internal class FsmContext | ||||
|     { | ||||
|         public bool  Return; | ||||
|         public int   NextState; | ||||
|         public Lexer L; | ||||
|         public int   StateStack; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     internal class Lexer | ||||
|     { | ||||
|         #region Fields | ||||
|         private delegate bool StateHandler (FsmContext ctx); | ||||
| 
 | ||||
|         private static readonly int[]          fsm_return_table; | ||||
|         private static readonly StateHandler[] fsm_handler_table; | ||||
| 
 | ||||
|         private bool          allow_comments; | ||||
|         private bool          allow_single_quoted_strings; | ||||
|         private bool          end_of_input; | ||||
|         private FsmContext    fsm_context; | ||||
|         private int           input_buffer; | ||||
|         private int           input_char; | ||||
|         private TextReader    reader; | ||||
|         private int           state; | ||||
|         private StringBuilder string_buffer; | ||||
|         private string        string_value; | ||||
|         private int           token; | ||||
|         private int           unichar; | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Properties | ||||
|         public bool AllowComments { | ||||
|             get { return allow_comments; } | ||||
|             set { allow_comments = value; } | ||||
|         } | ||||
| 
 | ||||
|         public bool AllowSingleQuotedStrings { | ||||
|             get { return allow_single_quoted_strings; } | ||||
|             set { allow_single_quoted_strings = value; } | ||||
|         } | ||||
| 
 | ||||
|         public bool EndOfInput { | ||||
|             get { return end_of_input; } | ||||
|         } | ||||
| 
 | ||||
|         public int Token { | ||||
|             get { return token; } | ||||
|         } | ||||
| 
 | ||||
|         public string StringValue { | ||||
|             get { return string_value; } | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Constructors | ||||
|         static Lexer () | ||||
|         { | ||||
|             PopulateFsmTables (out fsm_handler_table, out fsm_return_table); | ||||
|         } | ||||
| 
 | ||||
|         public Lexer (TextReader reader) | ||||
|         { | ||||
|             allow_comments = true; | ||||
|             allow_single_quoted_strings = true; | ||||
| 
 | ||||
|             input_buffer = 0; | ||||
|             string_buffer = new StringBuilder (128); | ||||
|             state = 1; | ||||
|             end_of_input = false; | ||||
|             this.reader = reader; | ||||
| 
 | ||||
|             fsm_context = new FsmContext (); | ||||
|             fsm_context.L = this; | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Static Methods | ||||
|         private static int HexValue (int digit) | ||||
|         { | ||||
|             switch (digit) { | ||||
|             case 'a': | ||||
|             case 'A': | ||||
|                 return 10; | ||||
| 
 | ||||
|             case 'b': | ||||
|             case 'B': | ||||
|                 return 11; | ||||
| 
 | ||||
|             case 'c': | ||||
|             case 'C': | ||||
|                 return 12; | ||||
| 
 | ||||
|             case 'd': | ||||
|             case 'D': | ||||
|                 return 13; | ||||
| 
 | ||||
|             case 'e': | ||||
|             case 'E': | ||||
|                 return 14; | ||||
| 
 | ||||
|             case 'f': | ||||
|             case 'F': | ||||
|                 return 15; | ||||
| 
 | ||||
|             default: | ||||
|                 return digit - '0'; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void PopulateFsmTables (out StateHandler[] fsm_handler_table, out int[] fsm_return_table) | ||||
|         { | ||||
|             // See section A.1. of the manual for details of the finite | ||||
|             // state machine. | ||||
|             fsm_handler_table = new StateHandler[28] { | ||||
|                 State1, | ||||
|                 State2, | ||||
|                 State3, | ||||
|                 State4, | ||||
|                 State5, | ||||
|                 State6, | ||||
|                 State7, | ||||
|                 State8, | ||||
|                 State9, | ||||
|                 State10, | ||||
|                 State11, | ||||
|                 State12, | ||||
|                 State13, | ||||
|                 State14, | ||||
|                 State15, | ||||
|                 State16, | ||||
|                 State17, | ||||
|                 State18, | ||||
|                 State19, | ||||
|                 State20, | ||||
|                 State21, | ||||
|                 State22, | ||||
|                 State23, | ||||
|                 State24, | ||||
|                 State25, | ||||
|                 State26, | ||||
|                 State27, | ||||
|                 State28 | ||||
|             }; | ||||
| 
 | ||||
|             fsm_return_table = new int[28] { | ||||
|                 (int) ParserToken.Char, | ||||
|                 0, | ||||
|                 (int) ParserToken.Number, | ||||
|                 (int) ParserToken.Number, | ||||
|                 0, | ||||
|                 (int) ParserToken.Number, | ||||
|                 0, | ||||
|                 (int) ParserToken.Number, | ||||
|                 0, | ||||
|                 0, | ||||
|                 (int) ParserToken.True, | ||||
|                 0, | ||||
|                 0, | ||||
|                 0, | ||||
|                 (int) ParserToken.False, | ||||
|                 0, | ||||
|                 0, | ||||
|                 (int) ParserToken.Null, | ||||
|                 (int) ParserToken.CharSeq, | ||||
|                 (int) ParserToken.Char, | ||||
|                 0, | ||||
|                 0, | ||||
|                 (int) ParserToken.CharSeq, | ||||
|                 (int) ParserToken.Char, | ||||
|                 0, | ||||
|                 0, | ||||
|                 0, | ||||
|                 0 | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
|         private static char ProcessEscChar (int esc_char) | ||||
|         { | ||||
|             switch (esc_char) { | ||||
|             case '"': | ||||
|             case '\'': | ||||
|             case '\\': | ||||
|             case '/': | ||||
|                 return Convert.ToChar (esc_char); | ||||
| 
 | ||||
|             case 'n': | ||||
|                 return '\n'; | ||||
| 
 | ||||
|             case 't': | ||||
|                 return '\t'; | ||||
| 
 | ||||
|             case 'r': | ||||
|                 return '\r'; | ||||
| 
 | ||||
|             case 'b': | ||||
|                 return '\b'; | ||||
| 
 | ||||
|             case 'f': | ||||
|                 return '\f'; | ||||
| 
 | ||||
|             default: | ||||
|                 // Unreachable | ||||
|                 return '?'; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State1 (FsmContext ctx) | ||||
|         { | ||||
|             while (ctx.L.GetChar ()) { | ||||
|                 if (ctx.L.input_char == ' ' || | ||||
|                     ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') | ||||
|                     continue; | ||||
| 
 | ||||
|                 if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9') { | ||||
|                     ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                     ctx.NextState = 3; | ||||
|                     return true; | ||||
|                 } | ||||
| 
 | ||||
|                 switch (ctx.L.input_char) { | ||||
|                 case '"': | ||||
|                     ctx.NextState = 19; | ||||
|                     ctx.Return = true; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case ',': | ||||
|                 case ':': | ||||
|                 case '[': | ||||
|                 case ']': | ||||
|                 case '{': | ||||
|                 case '}': | ||||
|                     ctx.NextState = 1; | ||||
|                     ctx.Return = true; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case '-': | ||||
|                     ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                     ctx.NextState = 2; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case '0': | ||||
|                     ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                     ctx.NextState = 4; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case 'f': | ||||
|                     ctx.NextState = 12; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case 'n': | ||||
|                     ctx.NextState = 16; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case 't': | ||||
|                     ctx.NextState = 9; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case '\'': | ||||
|                     if (! ctx.L.allow_single_quoted_strings) | ||||
|                         return false; | ||||
| 
 | ||||
|                     ctx.L.input_char = '"'; | ||||
|                     ctx.NextState = 23; | ||||
|                     ctx.Return = true; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case '/': | ||||
|                     if (! ctx.L.allow_comments) | ||||
|                         return false; | ||||
| 
 | ||||
|                     ctx.NextState = 25; | ||||
|                     return true; | ||||
| 
 | ||||
|                 default: | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private static bool State2 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             if (ctx.L.input_char >= '1' && ctx.L.input_char<= '9') { | ||||
|                 ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                 ctx.NextState = 3; | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case '0': | ||||
|                 ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                 ctx.NextState = 4; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State3 (FsmContext ctx) | ||||
|         { | ||||
|             while (ctx.L.GetChar ()) { | ||||
|                 if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') { | ||||
|                     ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 if (ctx.L.input_char == ' ' || | ||||
|                     ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') { | ||||
|                     ctx.Return = true; | ||||
|                     ctx.NextState = 1; | ||||
|                     return true; | ||||
|                 } | ||||
| 
 | ||||
|                 switch (ctx.L.input_char) { | ||||
|                 case ',': | ||||
|                 case ']': | ||||
|                 case '}': | ||||
|                     ctx.L.UngetChar (); | ||||
|                     ctx.Return = true; | ||||
|                     ctx.NextState = 1; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case '.': | ||||
|                     ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                     ctx.NextState = 5; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case 'e': | ||||
|                 case 'E': | ||||
|                     ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                     ctx.NextState = 7; | ||||
|                     return true; | ||||
| 
 | ||||
|                 default: | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private static bool State4 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             if (ctx.L.input_char == ' ' || | ||||
|                 ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') { | ||||
|                 ctx.Return = true; | ||||
|                 ctx.NextState = 1; | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case ',': | ||||
|             case ']': | ||||
|             case '}': | ||||
|                 ctx.L.UngetChar (); | ||||
|                 ctx.Return = true; | ||||
|                 ctx.NextState = 1; | ||||
|                 return true; | ||||
| 
 | ||||
|             case '.': | ||||
|                 ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                 ctx.NextState = 5; | ||||
|                 return true; | ||||
| 
 | ||||
|             case 'e': | ||||
|             case 'E': | ||||
|                 ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                 ctx.NextState = 7; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State5 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') { | ||||
|                 ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                 ctx.NextState = 6; | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         private static bool State6 (FsmContext ctx) | ||||
|         { | ||||
|             while (ctx.L.GetChar ()) { | ||||
|                 if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') { | ||||
|                     ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 if (ctx.L.input_char == ' ' || | ||||
|                     ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') { | ||||
|                     ctx.Return = true; | ||||
|                     ctx.NextState = 1; | ||||
|                     return true; | ||||
|                 } | ||||
| 
 | ||||
|                 switch (ctx.L.input_char) { | ||||
|                 case ',': | ||||
|                 case ']': | ||||
|                 case '}': | ||||
|                     ctx.L.UngetChar (); | ||||
|                     ctx.Return = true; | ||||
|                     ctx.NextState = 1; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case 'e': | ||||
|                 case 'E': | ||||
|                     ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                     ctx.NextState = 7; | ||||
|                     return true; | ||||
| 
 | ||||
|                 default: | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private static bool State7 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') { | ||||
|                 ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                 ctx.NextState = 8; | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case '+': | ||||
|             case '-': | ||||
|                 ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                 ctx.NextState = 8; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State8 (FsmContext ctx) | ||||
|         { | ||||
|             while (ctx.L.GetChar ()) { | ||||
|                 if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') { | ||||
|                     ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 if (ctx.L.input_char == ' ' || | ||||
|                     ctx.L.input_char >= '\t' && ctx.L.input_char<= '\r') { | ||||
|                     ctx.Return = true; | ||||
|                     ctx.NextState = 1; | ||||
|                     return true; | ||||
|                 } | ||||
| 
 | ||||
|                 switch (ctx.L.input_char) { | ||||
|                 case ',': | ||||
|                 case ']': | ||||
|                 case '}': | ||||
|                     ctx.L.UngetChar (); | ||||
|                     ctx.Return = true; | ||||
|                     ctx.NextState = 1; | ||||
|                     return true; | ||||
| 
 | ||||
|                 default: | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private static bool State9 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case 'r': | ||||
|                 ctx.NextState = 10; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State10 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case 'u': | ||||
|                 ctx.NextState = 11; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State11 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case 'e': | ||||
|                 ctx.Return = true; | ||||
|                 ctx.NextState = 1; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State12 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case 'a': | ||||
|                 ctx.NextState = 13; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State13 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case 'l': | ||||
|                 ctx.NextState = 14; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State14 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case 's': | ||||
|                 ctx.NextState = 15; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State15 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case 'e': | ||||
|                 ctx.Return = true; | ||||
|                 ctx.NextState = 1; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State16 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case 'u': | ||||
|                 ctx.NextState = 17; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State17 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case 'l': | ||||
|                 ctx.NextState = 18; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State18 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case 'l': | ||||
|                 ctx.Return = true; | ||||
|                 ctx.NextState = 1; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State19 (FsmContext ctx) | ||||
|         { | ||||
|             while (ctx.L.GetChar ()) { | ||||
|                 switch (ctx.L.input_char) { | ||||
|                 case '"': | ||||
|                     ctx.L.UngetChar (); | ||||
|                     ctx.Return = true; | ||||
|                     ctx.NextState = 20; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case '\\': | ||||
|                     ctx.StateStack = 19; | ||||
|                     ctx.NextState = 21; | ||||
|                     return true; | ||||
| 
 | ||||
|                 default: | ||||
|                     ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private static bool State20 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case '"': | ||||
|                 ctx.Return = true; | ||||
|                 ctx.NextState = 1; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State21 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case 'u': | ||||
|                 ctx.NextState = 22; | ||||
|                 return true; | ||||
| 
 | ||||
|             case '"': | ||||
|             case '\'': | ||||
|             case '/': | ||||
|             case '\\': | ||||
|             case 'b': | ||||
|             case 'f': | ||||
|             case 'n': | ||||
|             case 'r': | ||||
|             case 't': | ||||
|                 ctx.L.string_buffer.Append ( | ||||
|                     ProcessEscChar (ctx.L.input_char)); | ||||
|                 ctx.NextState = ctx.StateStack; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State22 (FsmContext ctx) | ||||
|         { | ||||
|             int counter = 0; | ||||
|             int mult    = 4096; | ||||
| 
 | ||||
|             ctx.L.unichar = 0; | ||||
| 
 | ||||
|             while (ctx.L.GetChar ()) { | ||||
| 
 | ||||
|                 if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9' || | ||||
|                     ctx.L.input_char >= 'A' && ctx.L.input_char <= 'F' || | ||||
|                     ctx.L.input_char >= 'a' && ctx.L.input_char <= 'f') { | ||||
| 
 | ||||
|                     ctx.L.unichar += HexValue (ctx.L.input_char) * mult; | ||||
| 
 | ||||
|                     counter++; | ||||
|                     mult /= 16; | ||||
| 
 | ||||
|                     if (counter == 4) { | ||||
|                         ctx.L.string_buffer.Append ( | ||||
|                             Convert.ToChar (ctx.L.unichar)); | ||||
|                         ctx.NextState = ctx.StateStack; | ||||
|                         return true; | ||||
|                     } | ||||
| 
 | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private static bool State23 (FsmContext ctx) | ||||
|         { | ||||
|             while (ctx.L.GetChar ()) { | ||||
|                 switch (ctx.L.input_char) { | ||||
|                 case '\'': | ||||
|                     ctx.L.UngetChar (); | ||||
|                     ctx.Return = true; | ||||
|                     ctx.NextState = 24; | ||||
|                     return true; | ||||
| 
 | ||||
|                 case '\\': | ||||
|                     ctx.StateStack = 23; | ||||
|                     ctx.NextState = 21; | ||||
|                     return true; | ||||
| 
 | ||||
|                 default: | ||||
|                     ctx.L.string_buffer.Append ((char) ctx.L.input_char); | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private static bool State24 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case '\'': | ||||
|                 ctx.L.input_char = '"'; | ||||
|                 ctx.Return = true; | ||||
|                 ctx.NextState = 1; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State25 (FsmContext ctx) | ||||
|         { | ||||
|             ctx.L.GetChar (); | ||||
| 
 | ||||
|             switch (ctx.L.input_char) { | ||||
|             case '*': | ||||
|                 ctx.NextState = 27; | ||||
|                 return true; | ||||
| 
 | ||||
|             case '/': | ||||
|                 ctx.NextState = 26; | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static bool State26 (FsmContext ctx) | ||||
|         { | ||||
|             while (ctx.L.GetChar ()) { | ||||
|                 if (ctx.L.input_char == '\n') { | ||||
|                     ctx.NextState = 1; | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private static bool State27 (FsmContext ctx) | ||||
|         { | ||||
|             while (ctx.L.GetChar ()) { | ||||
|                 if (ctx.L.input_char == '*') { | ||||
|                     ctx.NextState = 28; | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private static bool State28 (FsmContext ctx) | ||||
|         { | ||||
|             while (ctx.L.GetChar ()) { | ||||
|                 if (ctx.L.input_char == '*') | ||||
|                     continue; | ||||
| 
 | ||||
|                 if (ctx.L.input_char == '/') { | ||||
|                     ctx.NextState = 1; | ||||
|                     return true; | ||||
|                 } | ||||
| 
 | ||||
|                 ctx.NextState = 27; | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         private bool GetChar () | ||||
|         { | ||||
|             if ((input_char = NextChar ()) != -1) | ||||
|                 return true; | ||||
| 
 | ||||
|             end_of_input = true; | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         private int NextChar () | ||||
|         { | ||||
|             if (input_buffer != 0) { | ||||
|                 int tmp = input_buffer; | ||||
|                 input_buffer = 0; | ||||
| 
 | ||||
|                 return tmp; | ||||
|             } | ||||
| 
 | ||||
|             return reader.Read (); | ||||
|         } | ||||
| 
 | ||||
|         public bool NextToken () | ||||
|         { | ||||
|             StateHandler handler; | ||||
|             fsm_context.Return = false; | ||||
| 
 | ||||
|             while (true) { | ||||
|                 handler = fsm_handler_table[state - 1]; | ||||
| 
 | ||||
|                 if (! handler (fsm_context)) | ||||
|                     throw new JsonException (input_char); | ||||
| 
 | ||||
|                 if (end_of_input) | ||||
|                     return false; | ||||
| 
 | ||||
|                 if (fsm_context.Return) { | ||||
|                     string_value = string_buffer.ToString (); | ||||
|                     string_buffer.Remove (0, string_buffer.Length); | ||||
|                     token = fsm_return_table[state - 1]; | ||||
| 
 | ||||
|                     if (token == (int) ParserToken.Char) | ||||
|                         token = input_char; | ||||
| 
 | ||||
|                     state = fsm_context.NextState; | ||||
| 
 | ||||
|                     return true; | ||||
|                 } | ||||
| 
 | ||||
|                 state = fsm_context.NextState; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void UngetChar () | ||||
|         { | ||||
|             input_buffer = input_char; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 0e99ecf149fcd4361bafc43771b80d60 | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,87 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFrameworks>netstandard2.1;netstandard2.0;net45;net48;netstandard1.5;net40;net35;net20;net6.0;net8.0</TargetFrameworks> | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <DebugType>embedded</DebugType> | ||||
|     <EmbedUntrackedSources>true</EmbedUntrackedSources> | ||||
|     <PublishRepositoryUrl>true</PublishRepositoryUrl> | ||||
|     <SourceLinkCreate Condition="'$(OS)' == 'Windows_NT'">true</SourceLinkCreate> | ||||
|     <PackageReadmeFile>README.md</PackageReadmeFile> | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <ItemGroup Condition="'$(OS)' == 'Windows_NT'"> | ||||
|     <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="all" /> | ||||
|     <DotNetCliToolReference Include="dotnet-sourcelink-git" Version="2.8.3" /> | ||||
|     <DotNetCliToolReference Include="dotnet-sourcelink" Version="2.8.3" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <PackageId>LitJson</PackageId> | ||||
|     <Description>A .NET library to handle conversions from and to JSON (JavaScript Object Notation) strings. Written in C#, and it’s intended to be small, fast and easy to use. | ||||
| It's quick and lean, without external dependencies.</Description> | ||||
|     <Copyright>The authors disclaim copyright to this source code.</Copyright> | ||||
|     <Authors>Leonardo Boshell, Mattias Karlsson and contributors</Authors> | ||||
|     <Company>Leonardo Boshell, Mattias Karlsson and contributors</Company> | ||||
|     <PackageLicenseExpression>Unlicense</PackageLicenseExpression> | ||||
|     <PackageIcon>litjson.png</PackageIcon> | ||||
|     <RepositoryUrl>https://github.com/LitJSON/litjson</RepositoryUrl> | ||||
|     <RepositoryType>git</RepositoryType> | ||||
|     <PackageTags>JSON;Serializer</PackageTags> | ||||
|     <IncludeSource>true</IncludeSource> | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
|     <None Include="litjson.png" Pack="true" PackagePath="" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup Condition="'$(TargetFramework)' == 'net20' "> | ||||
|     <DefineConstants>$(DefineConstants);LEGACY</DefineConstants> | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <PropertyGroup Condition="'$(TargetFramework)' == 'net35' "> | ||||
|     <DefineConstants>$(DefineConstants);LEGACY</DefineConstants> | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <PropertyGroup Condition="'$(TargetFramework)' == 'net40' "> | ||||
|     <DefineConstants>$(DefineConstants);LEGACY</DefineConstants> | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.5' "> | ||||
|     <PackageReference Include="System.Collections.NonGeneric" Version="4.3.0" /> | ||||
|     <PackageReference Include="System.Collections.Specialized" Version="4.3.0" /> | ||||
|     <PackageReference Include="System.Reflection" Version="4.3.0" /> | ||||
|     <PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net20" Version="1.0.3" Condition="'$(TargetFramework)' == 'net20' "> | ||||
|       <PrivateAssets>all</PrivateAssets> | ||||
|       <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | ||||
|     </PackageReference> | ||||
|     <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net35" Version="1.0.3" Condition="'$(TargetFramework)' == 'net35' "> | ||||
|       <PrivateAssets>all</PrivateAssets> | ||||
|       <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | ||||
|     </PackageReference> | ||||
|     <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net40" Version="1.0.3" Condition="'$(TargetFramework)' == 'net40' "> | ||||
|       <PrivateAssets>all</PrivateAssets> | ||||
|       <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | ||||
|     </PackageReference> | ||||
|     <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net45" Version="1.0.3" Condition="'$(TargetFramework)' == 'net45' "> | ||||
|       <PrivateAssets>all</PrivateAssets> | ||||
|       <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | ||||
|     </PackageReference> | ||||
|     <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net48" Version="1.0.3" Condition="'$(TargetFramework)' == 'net48' "> | ||||
|       <PrivateAssets>all</PrivateAssets> | ||||
|       <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | ||||
|     </PackageReference> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
|     <None Include="../../README.md" Pack="true" PackagePath="\" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
| </Project> | ||||
|  | @ -0,0 +1,7 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: c5e8519174c484ae1903459114f61f98 | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,24 @@ | |||
| #if NETSTANDARD1_5 | ||||
| using System; | ||||
| using System.Reflection; | ||||
| namespace LitJson | ||||
| { | ||||
|     internal static class Netstandard15Polyfill | ||||
|     { | ||||
|         internal static Type GetInterface(this Type type, string name) | ||||
|         { | ||||
|             return type.GetTypeInfo().GetInterface(name);  | ||||
|         } | ||||
| 
 | ||||
|         internal static bool IsClass(this Type type) | ||||
|         { | ||||
|             return type.GetTypeInfo().IsClass; | ||||
|         } | ||||
| 
 | ||||
|         internal static bool IsEnum(this Type type) | ||||
|         { | ||||
|             return type.GetTypeInfo().IsEnum; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| #endif | ||||
|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: e212e5f514d9d4ec68eed1251080cce4 | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,44 @@ | |||
| #region Header | ||||
| /** | ||||
|  * ParserToken.cs | ||||
|  *   Internal representation of the tokens used by the lexer and the parser. | ||||
|  * | ||||
|  * The authors disclaim copyright to this source code. For more details, see | ||||
|  * the COPYING file included with this distribution. | ||||
|  **/ | ||||
| #endregion | ||||
| 
 | ||||
| 
 | ||||
| namespace Guru.LitJson | ||||
| { | ||||
|     internal enum ParserToken | ||||
|     { | ||||
|         // Lexer tokens (see section A.1.1. of the manual) | ||||
|         None = System.Char.MaxValue + 1, | ||||
|         Number, | ||||
|         True, | ||||
|         False, | ||||
|         Null, | ||||
|         CharSeq, | ||||
|         // Single char | ||||
|         Char, | ||||
| 
 | ||||
|         // Parser Rules (see section A.2.1 of the manual) | ||||
|         Text, | ||||
|         Object, | ||||
|         ObjectPrime, | ||||
|         Pair, | ||||
|         PairRest, | ||||
|         Array, | ||||
|         ArrayPrime, | ||||
|         Value, | ||||
|         ValueRest, | ||||
|         String, | ||||
| 
 | ||||
|         // End of input | ||||
|         End, | ||||
| 
 | ||||
|         // The empty rule | ||||
|         Epsilon | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 6a046907ebdf54072ab870aa49b58f76 | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.3 KiB | 
|  | @ -0,0 +1,135 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: f3a96012ad0784fc7893f9b9eb05788e | ||||
| TextureImporter: | ||||
|   internalIDToNameTable: [] | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 12 | ||||
|   mipmaps: | ||||
|     mipMapMode: 0 | ||||
|     enableMipMap: 1 | ||||
|     sRGBTexture: 1 | ||||
|     linearTexture: 0 | ||||
|     fadeOut: 0 | ||||
|     borderMipMap: 0 | ||||
|     mipMapsPreserveCoverage: 0 | ||||
|     alphaTestReferenceValue: 0.5 | ||||
|     mipMapFadeDistanceStart: 1 | ||||
|     mipMapFadeDistanceEnd: 3 | ||||
|   bumpmap: | ||||
|     convertToNormalMap: 0 | ||||
|     externalNormalMap: 0 | ||||
|     heightScale: 0.25 | ||||
|     normalMapFilter: 0 | ||||
|   isReadable: 0 | ||||
|   streamingMipmaps: 0 | ||||
|   streamingMipmapsPriority: 0 | ||||
|   vTOnly: 0 | ||||
|   ignoreMasterTextureLimit: 0 | ||||
|   grayScaleToAlpha: 0 | ||||
|   generateCubemap: 6 | ||||
|   cubemapConvolution: 0 | ||||
|   seamlessCubemap: 0 | ||||
|   textureFormat: 1 | ||||
|   maxTextureSize: 2048 | ||||
|   textureSettings: | ||||
|     serializedVersion: 2 | ||||
|     filterMode: 1 | ||||
|     aniso: 1 | ||||
|     mipBias: 0 | ||||
|     wrapU: 0 | ||||
|     wrapV: 0 | ||||
|     wrapW: 0 | ||||
|   nPOTScale: 1 | ||||
|   lightmap: 0 | ||||
|   compressionQuality: 50 | ||||
|   spriteMode: 0 | ||||
|   spriteExtrude: 1 | ||||
|   spriteMeshType: 1 | ||||
|   alignment: 0 | ||||
|   spritePivot: {x: 0.5, y: 0.5} | ||||
|   spritePixelsToUnits: 100 | ||||
|   spriteBorder: {x: 0, y: 0, z: 0, w: 0} | ||||
|   spriteGenerateFallbackPhysicsShape: 1 | ||||
|   alphaUsage: 1 | ||||
|   alphaIsTransparency: 0 | ||||
|   spriteTessellationDetail: -1 | ||||
|   textureType: 0 | ||||
|   textureShape: 1 | ||||
|   singleChannelComponent: 0 | ||||
|   flipbookRows: 1 | ||||
|   flipbookColumns: 1 | ||||
|   maxTextureSizeSet: 0 | ||||
|   compressionQualitySet: 0 | ||||
|   textureFormatSet: 0 | ||||
|   ignorePngGamma: 0 | ||||
|   applyGammaDecoding: 0 | ||||
|   cookieLightType: 0 | ||||
|   platformSettings: | ||||
|   - serializedVersion: 3 | ||||
|     buildTarget: DefaultTexturePlatform | ||||
|     maxTextureSize: 2048 | ||||
|     resizeAlgorithm: 0 | ||||
|     textureFormat: -1 | ||||
|     textureCompression: 1 | ||||
|     compressionQuality: 50 | ||||
|     crunchedCompression: 0 | ||||
|     allowsAlphaSplitting: 0 | ||||
|     overridden: 0 | ||||
|     androidETC2FallbackOverride: 0 | ||||
|     forceMaximumCompressionQuality_BC6H_BC7: 0 | ||||
|   - serializedVersion: 3 | ||||
|     buildTarget: Standalone | ||||
|     maxTextureSize: 2048 | ||||
|     resizeAlgorithm: 0 | ||||
|     textureFormat: -1 | ||||
|     textureCompression: 1 | ||||
|     compressionQuality: 50 | ||||
|     crunchedCompression: 0 | ||||
|     allowsAlphaSplitting: 0 | ||||
|     overridden: 0 | ||||
|     androidETC2FallbackOverride: 0 | ||||
|     forceMaximumCompressionQuality_BC6H_BC7: 0 | ||||
|   - serializedVersion: 3 | ||||
|     buildTarget: Android | ||||
|     maxTextureSize: 2048 | ||||
|     resizeAlgorithm: 0 | ||||
|     textureFormat: -1 | ||||
|     textureCompression: 1 | ||||
|     compressionQuality: 50 | ||||
|     crunchedCompression: 0 | ||||
|     allowsAlphaSplitting: 0 | ||||
|     overridden: 0 | ||||
|     androidETC2FallbackOverride: 0 | ||||
|     forceMaximumCompressionQuality_BC6H_BC7: 0 | ||||
|   - serializedVersion: 3 | ||||
|     buildTarget: Server | ||||
|     maxTextureSize: 2048 | ||||
|     resizeAlgorithm: 0 | ||||
|     textureFormat: -1 | ||||
|     textureCompression: 1 | ||||
|     compressionQuality: 50 | ||||
|     crunchedCompression: 0 | ||||
|     allowsAlphaSplitting: 0 | ||||
|     overridden: 0 | ||||
|     androidETC2FallbackOverride: 0 | ||||
|     forceMaximumCompressionQuality_BC6H_BC7: 0 | ||||
|   spriteSheet: | ||||
|     serializedVersion: 2 | ||||
|     sprites: [] | ||||
|     outline: [] | ||||
|     physicsShape: [] | ||||
|     bones: [] | ||||
|     spriteID:  | ||||
|     internalID: 0 | ||||
|     vertices: [] | ||||
|     indices:  | ||||
|     edges: [] | ||||
|     weights: [] | ||||
|     secondaryTextures: [] | ||||
|     nameFileIdTable: {} | ||||
|   spritePackingTag:  | ||||
|   pSDRemoveMatte: 0 | ||||
|   pSDShowRemoveMatteOption: 0 | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,100 @@ | |||
| # Guru Framework | ||||
| 
 | ||||
| 
 | ||||
| **Version 2.1.0** | ||||
| 
 | ||||
| - 插件整体调整了文件结构,细分了相关模块的路径,添加了对应的 `asmdef` 文件 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| **Version 2.0.3** | ||||
| 
 | ||||
| - [升级须知](#notice) | ||||
| 
 | ||||
| 
 | ||||
| ## 依赖库 | ||||
| 
 | ||||
| ### Firebase | ||||
| - 整体升级为 10.1.1 | ||||
| 
 | ||||
| ### AppLovin Max | ||||
| - 整体升级为 11.11.3 | ||||
| - 详细的广告Adapter版本, [详见这里](https://docs.google.com/spreadsheets/d/161UnDimGerqetIYNiMCfUBmJ7qozht8z1baxnxRdCnI) | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## 子模块 | ||||
| 
 | ||||
| ### GuruCore | ||||
| GuruSDK 核心逻辑类 | ||||
| 
 | ||||
| ### GuruAds | ||||
| GuruSDK 封装了广告服务相关的接口 | ||||
| - 新增了 Moloco 和 Pubmatic 两个渠道 | ||||
| - 新增了ATTManager 用于管理ATT弹出和相关事件统计 | ||||
| 
 | ||||
| ### GuruAnalytics | ||||
| Guru自打点统计模块 | ||||
| - 更新了用户时长统计修复, 修复 Worker 启动报错的问题 | ||||
| 
 | ||||
| ### GuruConsent | ||||
| 使用 Funding Choices 作为数据的启动广告隐私权限引导模块  | ||||
| 
 | ||||
| ### GuruBuildTool | ||||
| 构建工具合集 | ||||
| - 更新了SKADNetwork 数据 | ||||
| - 更新 Xcode15 构建支持 | ||||
| 
 | ||||
| ### GuruIAP | ||||
| 支付服务相关接口, 底层使用的是 Unity 的 In-App-Purchase 插件 | ||||
| 
 | ||||
| ### GuruEntry | ||||
| 游戏入口模块 | ||||
| 
 | ||||
| 
 | ||||
| ### GuruL10n | ||||
| Guru的翻译模块, 内部衔接了 I2 Localization 插件, 外部衔接中台自动翻译接口 | ||||
| 
 | ||||
| 
 | ||||
| ### GuruRating | ||||
| 游戏评分模块 | ||||
| 
 | ||||
| ### Keywords | ||||
| Max Keywords 上报模块 | ||||
| 
 | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| <span id="notice"></span> | ||||
| ## 升级须知 | ||||
| 
 | ||||
| ### Android  | ||||
| 
 | ||||
| - 需要在 `BuildSettings/Player Settings.../Publishing Settings` 内, 开启使用 `Custom Main Gradle Template` | ||||
| - 可以直接使用中台提供的 `launcherTemplate.gradle` 文件 | ||||
| - 或者在新生成的 `Assets/Plugins/Android/launcherTemplate.gradle` 内添加如下代码: | ||||
|     ```groove | ||||
|     android {     | ||||
|         ... | ||||
|          | ||||
|         lintOptions { | ||||
|             abortOnError false | ||||
|             checkReleaseBuilds false // <---请添加此行代码 | ||||
|         } | ||||
|          | ||||
|          | ||||
|         // 请将模版内的 **PACKAGING_OPTIONS** 替换为如下代码 | ||||
|         packagingOptions { | ||||
|             exclude("META-INF/*.kotlin_module") | ||||
|         } | ||||
|          | ||||
|         ...    | ||||
|     }     | ||||
|     ``` | ||||
| 
 | ||||
| - Android 构建的最小 Target Version 为 21 | ||||
| 
 | ||||
| ### iOS | ||||
| - 构建相关的升级已经提交至 BuildTools 内 | ||||
| - 其他问题持续收集中 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 9d4fe0abfc67449296f3992f2b823b78 | ||||
| timeCreated: 1671010548 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: f0c01eb685db4af99bbfa645d8307495 | ||||
| timeCreated: 1671499352 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 205f90aa56f64c759adf90d34e07fadf | ||||
| timeCreated: 1702973536 | ||||
|  | @ -0,0 +1,150 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using Firebase.RemoteConfig; | ||||
| using Guru; | ||||
| using Guru.LitJson; | ||||
| using UnityEngine; | ||||
| 
 | ||||
| namespace Guru | ||||
| { | ||||
|      | ||||
|      | ||||
|     /// <summary> | ||||
|     /// ABTEST 管理器 | ||||
|     /// </summary> | ||||
|     public class ABTestManager : Singleton<ABTestManager> | ||||
|     { | ||||
| 
 | ||||
|         private FirebaseRemoteConfig _remoteConfig; | ||||
| 
 | ||||
|         private List<ABParamData> _params; | ||||
| 
 | ||||
|          | ||||
|         #region 初始化 | ||||
|          | ||||
|         /// <summary> | ||||
|         ///  初始化 | ||||
|         /// </summary> | ||||
|         public static void Init() | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 Instance.Setup(); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 Debug.LogError(e); | ||||
|             } | ||||
|              | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 安装服务 | ||||
|         /// </summary> | ||||
|         private void Setup() | ||||
|         { | ||||
|             Debug.Log($"[AB] --- <color=#88ff00>ABTest Init</color>"); | ||||
|             _params = new List<ABParamData>(); | ||||
|              | ||||
|             _remoteConfig = FirebaseRemoteConfig.DefaultInstance; | ||||
|              | ||||
|             string strValue; | ||||
|             foreach (var key in _remoteConfig.Keys) | ||||
|             { | ||||
|                 strValue = _remoteConfig.GetValue(key).StringValue; | ||||
|                 AddParam(strValue); | ||||
|             } | ||||
|              | ||||
|             // ------- ABTest ----------- | ||||
|             // Debug.Log($"<color=orange> --- start parse test string --- </color>"); | ||||
|             // var testStr = @"{""enabled"":true,""value"":2,""id"":""B"",""guru_ab_23100715"":""B""}"; | ||||
|             // AddParam(testStr); | ||||
|              | ||||
|             if (_params.Count > 0) | ||||
|             { | ||||
|                 for (int i = 0; i < _params.Count; i++) | ||||
|                 { | ||||
|                     // 上报实验AB属性 | ||||
|                     GuruAnalytics.SetUserProperty(_params[i].id, _params[i].group); | ||||
| #if UNITY_EDITOR | ||||
|                     Debug.Log($"[AB] --- Add AB Param <color=cyan>{_params[i].ToString()}</color>"); | ||||
| #else | ||||
|                     Debug.Log($"[AB] --- Add AB Param {_params[i].ToString()}"); | ||||
| #endif | ||||
|                 } | ||||
|             } | ||||
|          | ||||
|         } | ||||
|          | ||||
|         #endregion | ||||
|          | ||||
|         #region 添加AB参数 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 添加AB参数 | ||||
|         /// </summary> | ||||
|         /// <param name="value"></param> | ||||
|         private void AddParam(string value) | ||||
|         { | ||||
|             if (!string.IsNullOrEmpty(value) && value.Contains("guru_ab_")) | ||||
|             { | ||||
|                 _params.Add(ABParamData.Parse(value)); // 添加参数 | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         #endregion | ||||
|     } | ||||
|      | ||||
|     [Serializable] | ||||
|     internal class ABParamData | ||||
|     { | ||||
|         private const int PARAM_NAME_LENGTH = 23; // 从开始"ab_" 计算, 往后20个字符 | ||||
|          | ||||
|         public string id; | ||||
|         public string group; | ||||
|         public string value; | ||||
|          | ||||
|         public static ABParamData Parse(string value) | ||||
|         { | ||||
|             Debug.Log($"--- ABParamData.Parse: {value}"); | ||||
|             var p = new ABParamData(); | ||||
|             p.value = value; | ||||
|              | ||||
|             // 发现Guru AB测试标志位 | ||||
|             var dict = JsonMapper.ToObject<Dictionary<string, object>>(value); | ||||
|             if (null != dict) | ||||
|             { | ||||
|                 foreach (var k in dict.Keys) | ||||
|                 { | ||||
|                     if (k.StartsWith("guru_ab")) | ||||
|                     { | ||||
|                         p.id = GetItemKey(k); | ||||
|                         p.group = dict[k].ToString(); | ||||
|                         // Debug.Log($"[AB] add property {k}: {dict[k]}"); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             return p; | ||||
|         } | ||||
| 
 | ||||
|         private static string GetItemKey(string raw) | ||||
|         { | ||||
|             var h = raw.Replace("guru_", ""); | ||||
|             var key = h.Substring(0, Mathf.Min(PARAM_NAME_LENGTH, h.Length)); // 最大长度23 | ||||
|             return key;  | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 输出字符串 | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public override string ToString() | ||||
|         { | ||||
|             return $"{id} : {group}"; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 9da3c10a9dde46499798d47cdd48fd70 | ||||
| timeCreated: 1696650618 | ||||
|  | @ -0,0 +1,46 @@ | |||
| 
 | ||||
| # ABTest 中台接口 | ||||
| 
 | ||||
| - [相关实现技术文档链接](https://docs.google.com/document/d/1AG9PLq-dI0plIati2qgVpuD5QchNO2P8phY1GWr8SeQ/edit?pli=1#heading=h.906ruqltpzqz) | ||||
| 
 | ||||
| 
 | ||||
| ## 云控配置 | ||||
| - 需要根据每个测试来配置对应的属性和ID | ||||
| 
 | ||||
|   ```javascript | ||||
|   // 参数 KEY 构成 | ||||
|   guru_ab_    +    231009   +     01 | ||||
|       ^               ^            ^ | ||||
|   固定前缀           年月日       实验序号  | ||||
|    | ||||
|   // 参数值构成 | ||||
|   "A" 或 "B" | ||||
|   "C" 或 "D" | ||||
|     | ||||
|   ``` | ||||
|    | ||||
| 
 | ||||
| - 属性字段是追加在云控参数体内的 | ||||
|     ```json | ||||
|     // 云控的json 参数数据体 | ||||
|     { | ||||
|       "id": 1, | ||||
|       "value": "test", | ||||
|    | ||||
|       "guru_ab_23100901": "A",   // 第一个实验的分组 | ||||
|       "guru_ab_23100902": "C"    // 第二个实验的分组 | ||||
|        | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     ``` | ||||
| 
 | ||||
| ## 结果验证 | ||||
| 
 | ||||
| - 对于已经切换了自打点的项目, 需要BI组配合项目组, 抽取每组实验用户的数据, 可形成有效报告 | ||||
| - 项目接入后在启动时不会卡顿, 项目不会产生异常和崩溃 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: a1e7ab6ebd2348d99444732ad4f6422b | ||||
| timeCreated: 1697167744 | ||||
|  | @ -0,0 +1,30 @@ | |||
| { | ||||
|     "name": "Guru.Runtime", | ||||
|     "rootNamespace": "Guru", | ||||
|     "references": [ | ||||
|         "Adjust", | ||||
|         "MaxSdk", | ||||
|         "MaxSdk.Scripts", | ||||
|         "Amazon", | ||||
|         "OpenWrapSDK", | ||||
|         "UniWebView-CSharp", | ||||
|         "UnityEngine.Purchasing", | ||||
|         "UnityEngine.Purchasing.Apple", | ||||
|         "UnityEngine.Purchasing.Stores", | ||||
|         "UnityEngine.Purchasing.Security", | ||||
|         "UnityEngine.Purchasing.SecurityCore", | ||||
|         "UnityEngine.Purchasing.SecurityStub", | ||||
|         "Google.Play.Review", | ||||
|         "Google.Play.Common", | ||||
|         "Guru.LitJson" | ||||
|     ], | ||||
|     "includePlatforms": [], | ||||
|     "excludePlatforms": [], | ||||
|     "allowUnsafeCode": false, | ||||
|     "overrideReferences": false, | ||||
|     "precompiledReferences": [], | ||||
|     "autoReferenced": true, | ||||
|     "defineConstraints": [], | ||||
|     "versionDefines": [], | ||||
|     "noEngineReferences": false | ||||
| } | ||||
|  | @ -0,0 +1,7 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: e241d247f550f427da05939864204192 | ||||
| AssemblyDefinitionImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,8 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: a66a5db145b064b588d9f4def3d72b12 | ||||
| folderAsset: yes | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 29a493ec2a4443b7a707065c40e88459 | ||||
| timeCreated: 1694079394 | ||||
|  | @ -0,0 +1,132 @@ | |||
| #if UNITY_IOS | ||||
| 
 | ||||
| namespace Guru | ||||
| { | ||||
|     using UnityEngine; | ||||
|     using System; | ||||
|     using Unity.Advertisement.IosSupport; | ||||
|     public class ATTManager | ||||
|     { | ||||
|         public const string Version = "1.0.0"; | ||||
| 
 | ||||
|         public const string ATT_STATUS_AUTHORIZED = "authorized"; | ||||
|         public const string ATT_STATUS_DENIED = "denied"; | ||||
|         public const string ATT_STATUS_RESTRICTED = "restricted"; | ||||
|         public const string ATT_STATUS_NOT_DETERMINED = "notDetermined"; | ||||
|         public const string ATT_STATUS_NOT_APPLICABLE = "notApplicable"; | ||||
|         public const int ATT_REQUIRED_MIN_OS = 14; | ||||
|          | ||||
|         //----------  引导类型 ------------ | ||||
|         public const string GUIDE_TYPE_ADMOB = "admob"; | ||||
|         public const string GUIDE_TYPE_CUSTOM = "custom"; | ||||
|         public const string GUIDE_TYPE_MAX = "max"; | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 获取状态 | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public static string GetStatus() | ||||
|         { | ||||
|             if (!IsATTSupported()) return ATT_STATUS_NOT_APPLICABLE; | ||||
|             var status = GetStatusString(ATTrackingStatusBinding.GetAuthorizationTrackingStatus()); | ||||
|             if(!string.IsNullOrEmpty(status)) return status; | ||||
|             return ATT_STATUS_NOT_APPLICABLE; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 转字符串 | ||||
|         /// </summary> | ||||
|         /// <param name="status"></param> | ||||
|         /// <returns></returns> | ||||
|         public static string GetStatusString(ATTrackingStatusBinding.AuthorizationTrackingStatus status) | ||||
|         { | ||||
|             switch (status) | ||||
|             { | ||||
|                 case ATTrackingStatusBinding.AuthorizationTrackingStatus.NOT_DETERMINED: | ||||
|                     return ATT_STATUS_NOT_DETERMINED; | ||||
|                 case ATTrackingStatusBinding.AuthorizationTrackingStatus.AUTHORIZED: | ||||
|                     return ATT_STATUS_AUTHORIZED; | ||||
|                 case ATTrackingStatusBinding.AuthorizationTrackingStatus.DENIED: | ||||
|                     return ATT_STATUS_DENIED; | ||||
|                 case ATTrackingStatusBinding.AuthorizationTrackingStatus.RESTRICTED: | ||||
|                     return ATT_STATUS_RESTRICTED; | ||||
|             } | ||||
|             return ""; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 状态码转字符串 | ||||
|         /// </summary> | ||||
|         /// <param name="value"></param> | ||||
|         /// <returns></returns> | ||||
|         public static string GetStatusString(int value)  | ||||
|             => GetStatusString((ATTrackingStatusBinding.AuthorizationTrackingStatus)value); | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 是否支持ATT | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         private static bool IsATTSupported() | ||||
|         { | ||||
|             string version = UnityEngine.iOS.Device.systemVersion; | ||||
|              | ||||
|             Debug.Log($"[ATT] --- Get iOS system version: {version}"); | ||||
| 
 | ||||
|             string tmp = version; | ||||
|             if (version.Contains(" ")) | ||||
|             { | ||||
|                 var a1 = version.Split(' '); | ||||
|                 tmp = a1[a1.Length - 1]; | ||||
|             } | ||||
| 
 | ||||
|             string num = tmp; | ||||
|             if (tmp.Contains(".")) | ||||
|             { | ||||
|                 num = tmp.Split('.')[0]; | ||||
|             } | ||||
|              | ||||
|             if (int.TryParse(num, out var ver)) | ||||
|             { | ||||
|                 if (ver >= ATT_REQUIRED_MIN_OS) return true; | ||||
|             } | ||||
| 
 | ||||
|             return false; | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 请求系统弹窗 | ||||
|         /// </summary> | ||||
|         public static void RequestATTDailog(Action<string> callback = null) | ||||
|         { | ||||
|             if (!IsATTSupported()) | ||||
|             { | ||||
|                 callback?.Invoke(ATT_STATUS_NOT_APPLICABLE); //  不支持 | ||||
|                 return; | ||||
|             } | ||||
|              | ||||
|             ATTrackingStatusBinding.RequestAuthorizationTracking(status =>{ | ||||
|                 callback?.Invoke(GetStatusString(status)); | ||||
|             }); | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 启动时检查状态 | ||||
|         /// </summary> | ||||
|         /// <param name="callback"></param> | ||||
|         public static void CheckStatus(Action<string> callback = null) | ||||
|         { | ||||
|             if (!IsATTSupported()) | ||||
|             { | ||||
|                 callback?.Invoke(ATT_STATUS_NOT_APPLICABLE); //  不支持 | ||||
|                 return; | ||||
|             } | ||||
|              | ||||
|             callback?.Invoke(GetStatus()); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: c64a8943316547c88c9ace04dd5e3d05 | ||||
| timeCreated: 1694079403 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 367cb7699f154c8894d8c3ca85c1fe94 | ||||
| timeCreated: 1681280112 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 9bb6c50e89674152823d45b10ce535a2 | ||||
| timeCreated: 1687238820 | ||||
|  | @ -0,0 +1 @@ | |||
| -keep class com.amazon.device.ads.** { *; }  | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 8ce2781a43d0405d8481e54e2a8e5789 | ||||
| timeCreated: 1687238837 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: f0fcdcfefdeb4214bb75f2cc6a8356f8 | ||||
| timeCreated: 1681280138 | ||||
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1,7 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: f5e96341271f7477280791fe0c9a4015 | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,52 @@ | |||
| # GuruAds 扩展 Amazon安装说明 | ||||
| 
 | ||||
| ## Version 1.0.0 | ||||
| 
 | ||||
| ## 更新内容: | ||||
| - 添加 Amazon 广告适配兼容 | ||||
| 
 | ||||
| 
 | ||||
| ## Amazon 使用说明 | ||||
| 
 | ||||
| ### 介绍 | ||||
| - 本扩展基于 GuruCore.Ads.ADService `1.2.0` 开发, | ||||
|   > 低于该版本的Guru框架请先升级至[ Guru 1.8.0 ](https://raw.githubusercontent.com/castbox/unity_gurucore/main/gurucore_1.8.0.unitypackage) | ||||
| - 导入本扩展后, 需要先手动安装 APS 插件 | ||||
|   > unitypackage 可从以下路径解压缩后自行安装: | ||||
|   >    | ||||
|   > Assets/Guru/GuruAds/Editor/Pcakge/unity_aps_1.4.3.zip | ||||
|   >  | ||||
| - 安装完毕后,请打开 GuruSettings 设置对应的 Amazon 广告配置参数 ,详见 `Amazon Setting` | ||||
| 
 | ||||
| ### 代码调用 | ||||
| 
 | ||||
| - 请直接使用 `ADServiceAPS` 来完成所有广告生命周期相关的功能, 它继承了 `IADService` | ||||
| - 实际上 `ADServiceAPS` 继承自 `ADService`。 具备基础功能的同时实现了Amazon的广告请求逻辑。 | ||||
| - 所有的广告申请, 加载和播放结果的回调同之前是一致的。 | ||||
|   ```C# | ||||
|      | ||||
|     // 定义广告实例     | ||||
|     var service = ADService.Instance; | ||||
|      | ||||
|     // 启动广告服务 | ||||
|     bool isDebugMode = true; | ||||
|     service.StartService(() => | ||||
|     { | ||||
|         //TODO 执行广告初始化成功后的逻辑 | ||||
|     }, isDebugMode); | ||||
| 
 | ||||
|     // 显示 Banner | ||||
|     service.ShowBanner(); | ||||
|        | ||||
|     // 显示 IV | ||||
|     service.ShowInterstitialAD("level_end"); | ||||
|        | ||||
|     // 显示 RV | ||||
|     service.ShowRewardedAD("add_free_coin", () => | ||||
|     { | ||||
|         UserData.Coin += 10; | ||||
|     }); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|   ``` | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 6f5bfcb26e384536ab6e134d2cad1c18 | ||||
| timeCreated: 1680158911 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 36da1246d638491bb601be91b8f18091 | ||||
| timeCreated: 1681280144 | ||||
|  | @ -0,0 +1,242 @@ | |||
| /********************************************** | ||||
|  * Amazon 广告渠道 | ||||
|  **********************************************/ | ||||
| namespace Guru | ||||
| { | ||||
|     using AmazonAds; | ||||
|     using UnityEngine; | ||||
|     using System; | ||||
| 
 | ||||
|     internal struct AdSize | ||||
|     { | ||||
|         public int width; | ||||
|         public int height; | ||||
|     }  | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// 广告渠道: Amazon | ||||
|     /// </summary> | ||||
|     public class AdChanelAmazon: IAdChannel, IAsyncRequestChannel | ||||
|     { | ||||
|         #region 广告尺寸 | ||||
|          | ||||
|         // Banner 尺寸参数 | ||||
|         private static AdSize BannerSize = new AdSize() { width = 320, height = 50 }; | ||||
|         // Video 尺寸参数 | ||||
|         private static AdSize VideoSize = new AdSize() { width = 320, height = 480 }; | ||||
|          | ||||
|         #endregion | ||||
|          | ||||
|         #region SLOT IDS | ||||
| 
 | ||||
|         // ---------------  获取各种SlotID -------------------- | ||||
|         private string AmazonBannerSlotID => GuruSettings.Instance.AmazonSetting.BannerSlotID; | ||||
|         private string AmazonInterVideoSlotID => GuruSettings.Instance.AmazonSetting.InterSlotID; | ||||
|         private string AmazonRewardSlotID => GuruSettings.Instance.AmazonSetting.RewardSlotID; | ||||
|         private string AmazonAppID => GuruSettings.Instance.AmazonSetting.AppID; | ||||
|          | ||||
|         // ---------------- Max 广告位ID --------------------  | ||||
|         private string MaxBannerSlotID => GuruSettings.Instance.ADSetting.GetBannerID(); | ||||
|         private string MaxIVSlotID => GuruSettings.Instance.ADSetting.GetInterstitialID(); | ||||
|         private string MaxRVSlotID => GuruSettings.Instance.ADSetting.GetRewardedVideoID(); | ||||
|          | ||||
|         #endregion | ||||
| 
 | ||||
|         #region Async 回调 | ||||
| 
 | ||||
|         public Action<bool, bool> OnBannerRequestOver { get; set; } | ||||
|         public Action<bool, bool> OnInterstitialRequestOver { get; set; } | ||||
|         public Action<bool, bool> OnRewardRequestOver { get; set; } | ||||
|          | ||||
|         #endregion | ||||
| 
 | ||||
|         #region 属性 | ||||
|          | ||||
|         public static readonly string ChanelName = "Amazon"; | ||||
|         public string Name => ChanelName; | ||||
|          | ||||
|         public Action<string> OnRequestOver { get; set; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 当前平台是否可用 | ||||
|         /// </summary> | ||||
|         public bool IsEnabled | ||||
|         { | ||||
|             get | ||||
|             { | ||||
| #if UNITY_EDITOR | ||||
|                 return false;  | ||||
| #endif | ||||
|                 // return GuruSettings.Instance.AmazonSetting.Enable; | ||||
|                 return true; // 常驻开启 | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         #endregion | ||||
|          | ||||
|         #region 初始化 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 初始化平台 | ||||
|         /// </summary> | ||||
|         public void Initialize() | ||||
|         { | ||||
| #if UNITY_EDITOR | ||||
|             Debug.Log($"<color=orange>=== Amazon will not init on Editor ===</color>"); | ||||
| #endif | ||||
|             if (!IsEnabled) | ||||
|             { | ||||
|                  Debug.Log($"[Ads] --- Amazon is not enabled"); | ||||
|                  return; | ||||
|             } | ||||
|              | ||||
|             // 初始化Amazon | ||||
|             Amazon.Initialize (AmazonAppID); | ||||
|             Amazon.SetAdNetworkInfo(new AdNetworkInfo(DTBAdNetwork.MAX)); | ||||
| #if UNITY_EDITOR || DEBUG  | ||||
|             Amazon.EnableTesting (true); // Make sure to take this off when going live. | ||||
| #else | ||||
|             Amazon.EnableLogging (false); | ||||
| #endif | ||||
| 		 | ||||
| #if UNITY_IOS | ||||
|             Amazon.SetAPSPublisherExtendedIdFeatureEnabled(true); | ||||
| #endif | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|         #region Banner | ||||
|          | ||||
|         private APSBannerAdRequest bannerAdRequest; | ||||
|         private bool _firstLoadBanner = true; | ||||
|         public void LoadBannerAD() | ||||
|         { | ||||
|             if (!IsEnabled) return; | ||||
|              | ||||
|             Debug.Log($"--- Amazon banner start load ---"); | ||||
|             if (bannerAdRequest != null) bannerAdRequest.DestroyFetchManager(); | ||||
|             bannerAdRequest = new APSBannerAdRequest(BannerSize.width, BannerSize.height, AmazonBannerSlotID); | ||||
|             bannerAdRequest.onSuccess += (adResponse) => | ||||
|             { | ||||
|                 Debug.Log($"--- Amazon Banner Load Success ---"); | ||||
|                 MaxSdk.SetBannerLocalExtraParameter(MaxBannerSlotID,  | ||||
|                     "amazon_ad_response",  | ||||
|                     adResponse.GetResponse()); | ||||
|                 OnBannerRequestOver?.Invoke(true, _firstLoadBanner); | ||||
|                 _firstLoadBanner = false; | ||||
|             }; | ||||
|              | ||||
|             bannerAdRequest.onFailedWithError += (adError) => | ||||
|             { | ||||
|                 Debug.Log($"--- Amazon Banner Load Fail: [{adError.GetCode()}] {adError.GetMessage()}"); | ||||
|                 MaxSdk.SetBannerLocalExtraParameter(MaxBannerSlotID,  | ||||
|                     "amazon_ad_error",  | ||||
|                     adError.GetAdError()); | ||||
|                 OnBannerRequestOver?.Invoke(false, _firstLoadBanner); | ||||
|             }; | ||||
|              | ||||
|             bannerAdRequest.LoadAd(); | ||||
| 
 | ||||
| #if UNITY_EDITOR | ||||
|             OnBannerRequestOver?.Invoke(true, false); | ||||
| #endif | ||||
|              | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
|         #region Intersitial | ||||
| 
 | ||||
|         private bool _isFirstLoadInter = true; | ||||
|         private APSVideoAdRequest interstitialAdRequest; | ||||
|          | ||||
|         public void LoadInterstitialAD() | ||||
|         { | ||||
|             if (!IsEnabled) return; | ||||
|              | ||||
|             // 首次启动注入渠道参数 | ||||
|             if (_isFirstLoadInter) | ||||
|             { | ||||
|                 Debug.Log($"--- Amazon INTER start load ---"); | ||||
|                 interstitialAdRequest = new APSVideoAdRequest(VideoSize.width, VideoSize.height, AmazonInterVideoSlotID); | ||||
|                 interstitialAdRequest.onSuccess += (adResponse) => | ||||
|                 { | ||||
|                     Debug.Log($"--- Amazon INTER Load Success ---"); | ||||
|                     MaxSdk.SetInterstitialLocalExtraParameter(MaxIVSlotID,  | ||||
|                         "amazon_ad_response", | ||||
|                         adResponse.GetResponse()); | ||||
|                     OnInterstitialRequestOver?.Invoke(true, true); | ||||
|                     _isFirstLoadInter = false; | ||||
|                 }; | ||||
|                 interstitialAdRequest.onFailedWithError += (adError) => | ||||
|                 { | ||||
|                     Debug.Log($"--- Amazon INTER Load Fail: [{adError.GetCode()}] {adError.GetMessage()}"); | ||||
|                     MaxSdk.SetInterstitialLocalExtraParameter(MaxIVSlotID,  | ||||
|                         "amazon_ad_error",  | ||||
|                         adError.GetAdError()); | ||||
|                     OnInterstitialRequestOver?.Invoke(false, true); // 不成功则一直请求Amazon广告 | ||||
|                 }; | ||||
|                 interstitialAdRequest.LoadAd(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 OnInterstitialRequestOver?.Invoke(true, false); // 走默认的广告加载逻辑 | ||||
|             } | ||||
|              | ||||
| #if UNITY_EDITOR | ||||
|             OnInterstitialRequestOver?.Invoke(true, false); | ||||
|             _isFirstLoadInter = false; | ||||
| #endif | ||||
|         } | ||||
|          | ||||
|          | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|         #region Reward | ||||
|          | ||||
|         private bool _firstLoadRewward = true; | ||||
|         private APSVideoAdRequest rewardedVideoAdRequest; | ||||
|          | ||||
|         public void LoadRewardAD() | ||||
|         { | ||||
|             if (!IsEnabled) return; | ||||
|              | ||||
|             if (_firstLoadRewward) | ||||
|             { | ||||
|                 Debug.Log($"--- Amazon Reward start load ---"); | ||||
|                 rewardedVideoAdRequest = new APSVideoAdRequest(VideoSize.width, VideoSize.height, AmazonRewardSlotID); | ||||
|                 rewardedVideoAdRequest.onSuccess += (adResponse) => | ||||
|                 { | ||||
|                     Debug.Log($"--- Amazon Reward Load Success ---"); | ||||
|                     MaxSdk.SetRewardedAdLocalExtraParameter(MaxRVSlotID,  | ||||
|                         "amazon_ad_response", | ||||
|                         adResponse.GetResponse()); | ||||
|                     OnRewardRequestOver?.Invoke(true, true); | ||||
|                     _firstLoadRewward = false; | ||||
|                 }; | ||||
|                 rewardedVideoAdRequest.onFailedWithError += (adError) => | ||||
|                 { | ||||
|                     Debug.Log($"--- Amazon Reward Load Fail: [{adError.GetCode()}] {adError.GetMessage()}"); | ||||
|                     MaxSdk.SetRewardedAdLocalExtraParameter(MaxRVSlotID,  | ||||
|                         "amazon_ad_error",  | ||||
|                         adError.GetAdError()); | ||||
|                     OnRewardRequestOver?.Invoke(false, true);  // 不成功则一直请求Amazon广告 | ||||
|                 }; | ||||
|                 rewardedVideoAdRequest.LoadAd(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 OnRewardRequestOver?.Invoke(true, false); // 走默认的广告加载逻辑 | ||||
|             } | ||||
| #if UNITY_EDITOR | ||||
|             OnRewardRequestOver?.Invoke(true, false); | ||||
| #endif | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|     } | ||||
|      | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 9c01d5cecc9140c8a4a9e98a983299a2 | ||||
| timeCreated: 1681280193 | ||||
|  | @ -0,0 +1,57 @@ | |||
| namespace Guru | ||||
| { | ||||
|     using System; | ||||
|     using UnityEngine; | ||||
| 
 | ||||
|     public partial class GuruSettings | ||||
|     { | ||||
|         [Header("Amazon 广告配置")] | ||||
|         public AmazonSetting AmazonSetting; | ||||
|     } | ||||
|      | ||||
|      | ||||
|     /// <summary> | ||||
|     /// Amazon广告配置 | ||||
|     /// </summary> | ||||
|     [Serializable] | ||||
|     public class AmazonSetting | ||||
|     { | ||||
| 
 | ||||
|         [SerializeField] public bool Enable; | ||||
|         [SerializeField] private AmazonPlatformSetting Android; | ||||
|         [SerializeField] private AmazonPlatformSetting iOS; | ||||
| 		 | ||||
|         /// <summary> | ||||
|         /// 获取AppID | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public AmazonPlatformSetting GetPlatform() | ||||
|         { | ||||
| #if UNITY_IOS | ||||
| 			return iOS;  | ||||
| #else | ||||
|             return Android; | ||||
| #endif  | ||||
|         } | ||||
| 
 | ||||
|         public string AppID => GetPlatform().appID; | ||||
|         public string BannerSlotID => GetPlatform().bannerSlotID; | ||||
|         public string InterSlotID => GetPlatform().interSlotID; | ||||
|         public string RewardSlotID => GetPlatform().rewardSlotID; | ||||
|              | ||||
|     } | ||||
|          | ||||
|          | ||||
|     /// <summary> | ||||
|     /// Amazon平台专属配置 | ||||
|     /// </summary> | ||||
|     [Serializable] | ||||
|     public class AmazonPlatformSetting | ||||
|     { | ||||
|         // public string name;		// 平台名称 | ||||
|         public string appID;		// AppID | ||||
|         public string bannerSlotID;	// Banner ID | ||||
|         public string interSlotID;	// Inter ID | ||||
|         public string rewardSlotID;	// Reward ID | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 074cbc5efb0c40d4856e20904a9b434d | ||||
| timeCreated: 1681281263 | ||||
|  | @ -0,0 +1,8 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: a44918376993443edbe32c4ae267ad11 | ||||
| folderAsset: yes | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 23cd1489a0b9410ea9e6e2f410926351 | ||||
| timeCreated: 1689144991 | ||||
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1,7 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 31dd283a9317e403e9eb07eba271e9c7 | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: f369f6d7d0c6425d88a3b8ec6ec1b4fc | ||||
| timeCreated: 1689145012 | ||||
|  | @ -0,0 +1,53 @@ | |||
| using System; | ||||
| using UnityEngine; | ||||
| 
 | ||||
| namespace Guru | ||||
| { | ||||
|     public partial class GuruSettings | ||||
|     { | ||||
|         [Header("[ Moloco ] 测试广告配置")] [Tooltip("此配置只在测试阶段验证广告时使用")]
 | ||||
|         public MolocoSetting MolocoSetting; | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// Moloco 广告配置 | ||||
|     /// </summary> | ||||
|     [Serializable] | ||||
|     public class MolocoSetting | ||||
|     { | ||||
|         [SerializeField] public bool Enable; | ||||
|         [SerializeField] private MolocoPlatformSetting Android; | ||||
|         [SerializeField] private MolocoPlatformSetting iOS; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 获取AppID | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public MolocoPlatformSetting GetPlatform() | ||||
|         { | ||||
| #if UNITY_IOS | ||||
| 			return iOS; | ||||
| #else | ||||
|             return Android; | ||||
| #endif | ||||
|         } | ||||
| 
 | ||||
|         public string BannerTestUnitID => GetPlatform().bannerTestUnitID; | ||||
|         public string InterTestUnitID => GetPlatform().interTestUnitID; | ||||
|         public string RewardTestUnitID => GetPlatform().rewardTestUnitID; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Moloco 平台专属配置 | ||||
|         /// </summary> | ||||
|         [Serializable] | ||||
|         public class MolocoPlatformSetting | ||||
|         { | ||||
|             // public string name;		// 平台名称 | ||||
|             public string bannerTestUnitID; // Banner ID | ||||
|             public string interTestUnitID; // Inter ID | ||||
|             public string rewardTestUnitID; // Reward ID | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 73843b3931f04824be84b4adcefdbb94 | ||||
| timeCreated: 1689145037 | ||||
|  | @ -0,0 +1,211 @@ | |||
| using UnityEngine; | ||||
| 
 | ||||
| namespace Guru | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Moloco 测试接口 | ||||
|     /// </summary> | ||||
|     public class MolocoTestAPI | ||||
|     { | ||||
|          | ||||
| 
 | ||||
|         #region 初始化 | ||||
| 
 | ||||
| 
 | ||||
|         | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|         #region Banner | ||||
| 
 | ||||
|         private static string _testBannerId; | ||||
|         private static bool _isLoadingBanner = false; | ||||
|         /// <summary> | ||||
|         /// 请求测试广告Ba | ||||
|         /// </summary> | ||||
|         public static void LoadDebugBanner(string bannerId) | ||||
|         { | ||||
|             if (_isLoadingBanner) return; | ||||
|             _isLoadingBanner = true; | ||||
|             _testBannerId = bannerId; | ||||
|             AddBannerCallBacks(); | ||||
|             MaxSdk.CreateBanner(_testBannerId, MaxSdkBase.BannerPosition.BottomCenter); | ||||
|             ShowToast($"Load Banner: {_testBannerId}"); | ||||
|         } | ||||
|         private static void AddBannerCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Banner.OnAdLoadedEvent += OnDebugBannerLoadSuccess; | ||||
|             MaxSdkCallbacks.Banner.OnAdLoadFailedEvent += OnDebugBannerLoadFailed; | ||||
|         } | ||||
|          | ||||
|         private static void RemoveBannerCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Banner.OnAdLoadedEvent -= OnDebugBannerLoadSuccess; | ||||
|             MaxSdkCallbacks.Banner.OnAdLoadFailedEvent -= OnDebugBannerLoadFailed; | ||||
|         } | ||||
| 
 | ||||
|         private static void OnDebugBannerLoadSuccess(string adUnitId, MaxSdkBase.AdInfo adInfo) | ||||
|         { | ||||
|             if (adUnitId == _testBannerId) | ||||
|             { | ||||
|                 RemoveBannerCallBacks(); | ||||
|                 Debug.Log($"[PM] Load Banner success => Revenue: {adInfo.Revenue}"); | ||||
|                 MaxSdk.ShowBanner(adUnitId); | ||||
|                 _isLoadingBanner = false; | ||||
|                  | ||||
|                 ShowToast($"Banner Loaded: {_testBannerId}"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void OnDebugBannerLoadFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo) | ||||
|         { | ||||
|             if (adUnitId == _testBannerId) | ||||
|             { | ||||
|                 RemoveBannerCallBacks(); | ||||
|                 Debug.Log($"[PM] Load Banner fail => Waterfall:{errorInfo.WaterfallInfo.Name}"); | ||||
|                 _isLoadingBanner = false; | ||||
|                  | ||||
|                 ShowToast($"Banner Load fail: {_testBannerId}"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|         #region Interstitial | ||||
| 
 | ||||
| 
 | ||||
|         private static bool _isLoadingIV = false; | ||||
|         private static string _testIVId; | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 请求测试广告IV | ||||
|         /// </summary> | ||||
|         public static void LoadDebugIV(string unitId) | ||||
|         { | ||||
|             if (_isLoadingIV) return; | ||||
|             _isLoadingIV = true; | ||||
|             _testIVId = unitId; | ||||
|             AddIvCallBacks(); | ||||
|             MaxSdk.LoadInterstitial(_testIVId); | ||||
|              | ||||
|             ShowToast($"Load Interstitial: {_testIVId}"); | ||||
|         } | ||||
|          | ||||
|         private static void AddIvCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Interstitial.OnAdLoadedEvent += OnDebugIVLoadSuccess; | ||||
|             MaxSdkCallbacks.Interstitial.OnAdLoadFailedEvent += OnDebugIVLoadFailed; | ||||
|         } | ||||
|          | ||||
|         private static void RemoveIvCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Interstitial.OnAdLoadedEvent -= OnDebugIVLoadSuccess; | ||||
|             MaxSdkCallbacks.Interstitial.OnAdLoadFailedEvent -= OnDebugIVLoadFailed; | ||||
|         } | ||||
| 
 | ||||
|         private static void OnDebugIVLoadSuccess(string adUnitId, MaxSdkBase.AdInfo adInfo) | ||||
|         { | ||||
|             if (adUnitId == _testIVId) | ||||
|             { | ||||
|                 RemoveIvCallBacks(); | ||||
|                 _isLoadingIV = false; | ||||
|                 Debug.Log($"[PM] Load IV success => Revenue: {adInfo.Revenue}"); | ||||
|                 string placement = "pm_test_iv"; | ||||
|                 MaxSdk.ShowInterstitial(adUnitId, placement); | ||||
|                 ShowToast($"Load IV Success: {_testIVId}"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void OnDebugIVLoadFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo) | ||||
|         { | ||||
|             if (adUnitId == _testIVId) | ||||
|             { | ||||
|                 RemoveIvCallBacks(); | ||||
|                 _isLoadingIV = false; | ||||
|                 Debug.Log($"[PM] Load IV fail => Waterfall:{errorInfo.WaterfallInfo.Name}"); | ||||
|                 ShowToast($"Load IV Fail: {_testIVId}"); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         #endregion | ||||
| 
 | ||||
|         #region Reward | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         private static string _testRVId; | ||||
|         private static bool _isLoadingRV = false; | ||||
|         /// <summary> | ||||
|         /// 请求测试广告RV | ||||
|         /// </summary> | ||||
|         public static void LoadDebugRV(string unitId) | ||||
|         { | ||||
|             if (_isLoadingRV) return; | ||||
|             _isLoadingRV = true; | ||||
|             _testRVId = unitId; | ||||
|             AddRvCallBacks(); | ||||
|             MaxSdk.LoadRewardedAd(_testRVId); | ||||
|              | ||||
|             ShowToast($"Load RV: {_testRVId}"); | ||||
|         } | ||||
| 
 | ||||
|         private static void AddRvCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Rewarded.OnAdLoadedEvent += OnDebugRVLoadSuccess; | ||||
|             MaxSdkCallbacks.Rewarded.OnAdLoadFailedEvent += OnDebugRVLoadFailed; | ||||
|         } | ||||
|          | ||||
|         private static void RemoveRvCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Rewarded.OnAdLoadedEvent -= OnDebugRVLoadSuccess; | ||||
|             MaxSdkCallbacks.Rewarded.OnAdLoadFailedEvent -= OnDebugRVLoadFailed; | ||||
|         } | ||||
|          | ||||
|         private static void OnDebugRVLoadSuccess(string adUnitId, MaxSdkBase.AdInfo adInfo) | ||||
|         { | ||||
|             if (adUnitId == _testRVId) | ||||
|             { | ||||
|                 RemoveRvCallBacks(); | ||||
|                 _isLoadingRV = false; | ||||
|                 Debug.Log($"[PM] Load RV success => Revenue: {adInfo.Revenue}"); | ||||
|                 string placement = "pm_test_rv"; | ||||
|                 MaxSdk.ShowRewardedAd(adUnitId, placement); | ||||
|                 ShowToast($"Load RV Success: {_testRVId}"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void OnDebugRVLoadFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo) | ||||
|         { | ||||
|             if (adUnitId == _testRVId) | ||||
|             { | ||||
|                 RemoveRvCallBacks(); | ||||
|                 _isLoadingRV = false; | ||||
|                 Debug.Log($"[PM] Load RV fail => Waterfall:{errorInfo.WaterfallInfo.Name}"); | ||||
|                 ShowToast($"Load RV Fail: {_testRVId}"); | ||||
|             } | ||||
|         } | ||||
|         #endregion | ||||
|          | ||||
|         #region Debug | ||||
| 
 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 显示Toast信息 | ||||
|         /// </summary> | ||||
|         /// <param name="msg"></param> | ||||
|         public static void ShowToast(string msg) | ||||
|         { | ||||
| #if UNITY_ANDROID    | ||||
|             // U3D2Android.ShowToast(msg); | ||||
| #else | ||||
|             Debug.Log(msg); | ||||
| #endif | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 92c8ebc4f05c4729b6ef6a6bae5a34b7 | ||||
| timeCreated: 1689147226 | ||||
|  | @ -0,0 +1,8 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 476080445a424f538e3295b6d0c39c37 | ||||
| folderAsset: yes | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,8 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 4f27758688594110b42e5d6cc9368f2b | ||||
| folderAsset: yes | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1 @@ | |||
| -keep class com.pubmatic.sdk.** { *; } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 337880599b034517bf8ff594099c5c1d | ||||
| timeCreated: 1687158363 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: c6fc887e2efc448b85609ea99608acdd | ||||
| timeCreated: 1681289567 | ||||
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1,7 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 3a5b29c0662724638bd2fb91e3a98972 | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,31 @@ | |||
| # PubMatic 广告插件 | ||||
| 
 | ||||
| ## Version 1.0.0 | ||||
| 
 | ||||
| 使用方法: | ||||
| - 先解压缩Package内的zip文档 | ||||
| - 导入两个unitypackage文件 | ||||
| - 将 PubMatic 对应的的 AdChannelPubMatic.cs 文件导入项目 | ||||
| - 在 AdService 内注册AdChannelPubMatic. (需要升级 ADService ) | ||||
| - 在 PlayerSettings 内添加 `AD_PUBMATIC` 的宏 | ||||
| - 在 proguard-user.txt 内添加下面的代码: | ||||
|     ```yaml | ||||
|     # PubMatic  | ||||
|     -keep class com.pubmatic.** { *; } | ||||
|     ``` | ||||
| 
 | ||||
| 广告申请和展示时按照正常的 MAX 广告申请接口调用 | ||||
|   | ||||
| 测试时, 需要使用专用的Debug接口直接拉起 PubMatic 测试广告 | ||||
| ```csharp | ||||
| 
 | ||||
|     Debug.Log($"--- 显示 PubMatic Banner ---"); | ||||
|     AdChannelPubMatic.RequestDebugBanner(); | ||||
| 
 | ||||
|     Debug.Log($"--- 显示 PubMatic IV ---"); | ||||
|     AdChannelPubMatic.LoadDebugIV(); | ||||
| 
 | ||||
|     Debug.Log($"--- 显示 PubMatic RV ---"); | ||||
|     AdChannelPubMatic.RequestDebugRV(); | ||||
| 
 | ||||
| ``` | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 40bcecbb98df437bae363dfc4956bed4 | ||||
| timeCreated: 1681451207 | ||||
|  | @ -0,0 +1,8 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 22a8f46f2a1cc4ebd830e5dd9ec2a898 | ||||
| folderAsset: yes | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,370 @@ | |||
| /********************************************** | ||||
|  * Pubmatic 广告渠道 | ||||
|  **********************************************/ | ||||
| namespace Guru | ||||
| { | ||||
|     using OpenWrapSDK; | ||||
|     using System; | ||||
|     using OpenWrapSDK.Mediation.AppLovinMAX; | ||||
|     using UnityEngine; | ||||
|      | ||||
|     public class AdChannelPubMatic: IAdChannel | ||||
|     { | ||||
|         #region 属性定义 | ||||
|          | ||||
|         public static readonly string ChanelName = "PubMatic"; | ||||
|         public string Name => ChanelName; | ||||
|          | ||||
|         public Action<string> OnRequestOver { get; set; } | ||||
| 
 | ||||
| 
 | ||||
|         // ---------------  获取各种SlotID -------------------- | ||||
|         private static string PMBannerUnitID => GuruSettings.Instance.PubmaticSetting.BannerUnitID; | ||||
|         private static string PMInterUnitID => GuruSettings.Instance.PubmaticSetting.InterUnitID; | ||||
|         private static string PMRewardUnitID => GuruSettings.Instance.PubmaticSetting.RewardUnitID; | ||||
|         private static string PMStoreUrl => GuruSettings.Instance.PubmaticSetting.StoreUrl; | ||||
| 
 | ||||
|         public static readonly int BidRequestTimeout = 5; // 请求超时 (秒) | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 当前平台是否可用 | ||||
|         /// </summary> | ||||
|         public bool IsEnabled | ||||
|         { | ||||
|             get | ||||
|             { | ||||
| #if UNITY_EDITOR | ||||
|                 return false;  | ||||
| #endif | ||||
|                 // return GuruSettings.Instance.PubmaticSetting.Enable; | ||||
|                 return true; // 常驻开启 | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|         #region 初始化 | ||||
| 
 | ||||
|         /* | ||||
|          * You must set the App Store/Google Play Store storeURL of your app | ||||
|          * before it can request an ad using OpenWrap SDK. | ||||
|          * The storeURL is the URL where users can download your app from the App Store/Google Play Store. | ||||
|          */ | ||||
|         public void Initialize() | ||||
|         { | ||||
| #if UNITY_EDITOR | ||||
|                 Debug.Log($"<color=orange>=== PubMatic will not init on Editor ===</color>"); | ||||
| #endif | ||||
|             if (!IsEnabled) | ||||
|             { | ||||
|                 Debug.Log($"[Ads] --- PubMatic is not enabled"); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             var appInfo = new POBApplicationInfo(); | ||||
|             appInfo.StoreURL = new Uri(PMStoreUrl); | ||||
|             POBOpenWrapSDK.SetApplicationInfo(appInfo); | ||||
|         } | ||||
|       | ||||
|         #endregion | ||||
|          | ||||
|         #region 基础参数设置 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 设置Banner参数 | ||||
|         /// </summary> | ||||
|         /// <param name="adUnitId"></param> | ||||
|         /// <param name="key"></param> | ||||
|         /// <param name="value"></param> | ||||
|         private static void SetBannerParams(string adUnitId, string key, object value) | ||||
|         { | ||||
| #if UNITY_IOS | ||||
|             MaxSdk.SetBannerLocalExtraParameter(adUnitId,  | ||||
|                 key,  | ||||
|                 POBMAXUtil.GetIntPtr(adUnitId, value)); | ||||
| #elif UNITY_ANDROID | ||||
|             MaxSdk.SetBannerLocalExtraParameter(adUnitId,  | ||||
|                 key,  | ||||
|                 POBMAXUtil.GetAndroidJavaObject(value)); | ||||
| #endif | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 设置IV参数 | ||||
|         /// </summary> | ||||
|         /// <param name="adUnitId"></param> | ||||
|         /// <param name="key"></param> | ||||
|         /// <param name="value"></param> | ||||
|         private static void SetIVParams(string adUnitId, string key, object value) | ||||
|         { | ||||
| #if UNITY_IOS | ||||
|             MaxSdk.SetInterstitialLocalExtraParameter(adUnitId,  | ||||
|                 key,  | ||||
|                 POBMAXUtil.GetIntPtr(adUnitId, value)); | ||||
| #elif UNITY_ANDROID | ||||
|             MaxSdk.SetInterstitialLocalExtraParameter(adUnitId,  | ||||
|                 key,  | ||||
|                 POBMAXUtil.GetAndroidJavaObject(value)); | ||||
| #endif | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 设置RV参数 | ||||
|         /// </summary> | ||||
|         /// <param name="adUnitId"></param> | ||||
|         /// <param name="key"></param> | ||||
|         /// <param name="value"></param> | ||||
|         private static void SetRVParams(string adUnitId, string key, object value) | ||||
|         { | ||||
| #if UNITY_IOS | ||||
|             MaxSdk.SetRewardedAdLocalExtraParameter(adUnitId,  | ||||
|                 key,  | ||||
|                 POBMAXUtil.GetIntPtr(adUnitId, value)); | ||||
| #elif UNITY_ANDROID | ||||
|             MaxSdk.SetRewardedAdLocalExtraParameter(adUnitId,  | ||||
|                 key,  | ||||
|                 POBMAXUtil.GetAndroidJavaObject(value)); | ||||
| #endif | ||||
|         } | ||||
| 
 | ||||
|          | ||||
|         //---------------- 设置广告超时 ------------------------- | ||||
| 
 | ||||
|         private void SetBannerTimeout(string adUnitId, int timeout = 5) | ||||
|         { | ||||
|             SetBannerParams(adUnitId, POBMAXConstants.NetworkTimeoutKey, timeout); | ||||
|         } | ||||
|         private void SetIVTimeout(string adUnitId, int timeout = 5) | ||||
|         { | ||||
|             SetIVParams(adUnitId, POBMAXConstants.NetworkTimeoutKey, timeout); | ||||
|         } | ||||
|          | ||||
|         private void SetRVTimeout(string adUnitId, int timeout = 5) | ||||
|         { | ||||
|             SetRVParams(adUnitId, POBMAXConstants.NetworkTimeoutKey, timeout); | ||||
|         } | ||||
|          | ||||
|         //------------------ 打开测试广告 ---------------------------- | ||||
| 
 | ||||
|         private void EnableBannerTestAds(string adUnitId) | ||||
|         { | ||||
|             SetBannerParams(adUnitId, POBMAXConstants.EnableTestModeKey, true); | ||||
|         } | ||||
|         private void EnableIVTestAds(string adUnitId) | ||||
|         { | ||||
|             SetIVParams(adUnitId, POBMAXConstants.EnableTestModeKey, true); | ||||
|         } | ||||
|         private void EnableRVTestAds(string adUnitId) | ||||
|         { | ||||
|             SetRVParams(adUnitId, POBMAXConstants.EnableTestModeKey, true); | ||||
|         } | ||||
| 
 | ||||
|         //------------------- 打开调试模式 --------------------------- | ||||
|         private static void EnableBannerDebugMode(string adUnitId) | ||||
|         { | ||||
|             SetBannerParams(adUnitId, POBMAXConstants.EnableDebugModeKey, true); | ||||
|         } | ||||
|         private static void EnableIVDebugMode(string adUnitId) | ||||
|         { | ||||
|             SetIVParams(adUnitId, POBMAXConstants.EnableDebugModeKey, true); | ||||
|         } | ||||
|         private static void EnableRVDebugMode(string adUnitId) | ||||
|         { | ||||
|             SetRVParams(adUnitId, POBMAXConstants.EnableDebugModeKey, true); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|         #region Banner | ||||
| 
 | ||||
|         public void LoadBannerAD() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         private static bool _isLoadingBanner = false; | ||||
|         /// <summary> | ||||
|         /// 请求测试广告Ba | ||||
|         /// </summary> | ||||
|         public static void RequestDebugBanner() | ||||
|         { | ||||
|             if (_isLoadingBanner) return; | ||||
|             _isLoadingBanner = true; | ||||
|             EnableBannerDebugMode(PMBannerUnitID); | ||||
|             AddBannerCallBacks(); | ||||
|             MaxSdk.CreateBanner(PMBannerUnitID, MaxSdkBase.BannerPosition.BottomCenter); | ||||
|             ShowToast($"Load Banner: {PMBannerUnitID}"); | ||||
|         } | ||||
|         private static void AddBannerCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Banner.OnAdLoadedEvent += OnDebugBannerLoadSuccess; | ||||
|             MaxSdkCallbacks.Banner.OnAdLoadFailedEvent += OnDebugBannerLoadFailed; | ||||
|         } | ||||
|          | ||||
|         private static void RemoveBannerCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Banner.OnAdLoadedEvent -= OnDebugBannerLoadSuccess; | ||||
|             MaxSdkCallbacks.Banner.OnAdLoadFailedEvent -= OnDebugBannerLoadFailed; | ||||
|         } | ||||
| 
 | ||||
|         private static void OnDebugBannerLoadSuccess(string adUnitId, MaxSdkBase.AdInfo adInfo) | ||||
|         { | ||||
|             if (adUnitId == PMBannerUnitID) | ||||
|             { | ||||
|                 RemoveBannerCallBacks(); | ||||
|                 Debug.Log($"[PM] Load Banner success => Revenue: {adInfo.Revenue}"); | ||||
|                 MaxSdk.ShowBanner(adUnitId); | ||||
|                 _isLoadingBanner = false; | ||||
|                  | ||||
|                 ShowToast($"Banner Loaded: {PMBannerUnitID}"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void OnDebugBannerLoadFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo) | ||||
|         { | ||||
|             if (adUnitId == PMBannerUnitID) | ||||
|             { | ||||
|                 RemoveBannerCallBacks(); | ||||
|                 Debug.Log($"[PM] Load Banner fail => Waterfall:{errorInfo.WaterfallInfo.Name}"); | ||||
|                 _isLoadingBanner = false; | ||||
|                  | ||||
|                 ShowToast($"Banner Load fail: {PMBannerUnitID}"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region Interstitial | ||||
| 
 | ||||
|         public void LoadInterstitialAD() | ||||
|         { | ||||
|         } | ||||
|          | ||||
|          | ||||
|         private static bool _isLoadingIV = false; | ||||
|         /// <summary> | ||||
|         /// 请求测试广告IV | ||||
|         /// </summary> | ||||
|         public static void LoadDebugIV() | ||||
|         { | ||||
|             if (_isLoadingIV) return; | ||||
|             _isLoadingIV = true; | ||||
|             EnableIVDebugMode(PMInterUnitID); | ||||
|             AddIvCallBacks(); | ||||
|             MaxSdk.LoadInterstitial(PMInterUnitID); | ||||
|              | ||||
|             ShowToast($"Load Interstitial: {PMInterUnitID}"); | ||||
|         } | ||||
|          | ||||
|         private static void AddIvCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Interstitial.OnAdLoadedEvent += OnDebugIVLoadSuccess; | ||||
|             MaxSdkCallbacks.Interstitial.OnAdLoadFailedEvent += OnDebugIVLoadFailed; | ||||
|         } | ||||
|          | ||||
|         private static void RemoveIvCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Interstitial.OnAdLoadedEvent -= OnDebugIVLoadSuccess; | ||||
|             MaxSdkCallbacks.Interstitial.OnAdLoadFailedEvent -= OnDebugIVLoadFailed; | ||||
|         } | ||||
| 
 | ||||
|         private static void OnDebugIVLoadSuccess(string adUnitId, MaxSdkBase.AdInfo adInfo) | ||||
|         { | ||||
|             if (adUnitId == PMInterUnitID) | ||||
|             { | ||||
|                 RemoveIvCallBacks(); | ||||
|                 _isLoadingIV = false; | ||||
|                 Debug.Log($"[PM] Load IV success => Revenue: {adInfo.Revenue}"); | ||||
|                 string placement = "pm_test_iv"; | ||||
|                 MaxSdk.ShowInterstitial(adUnitId, placement); | ||||
|                 ShowToast($"Load IV Success: {PMInterUnitID}"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void OnDebugIVLoadFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo) | ||||
|         { | ||||
|             if (adUnitId == PMInterUnitID) | ||||
|             { | ||||
|                 RemoveIvCallBacks(); | ||||
|                 _isLoadingIV = false; | ||||
|                 Debug.Log($"[PM] Load IV fail => Waterfall:{errorInfo.WaterfallInfo.Name}"); | ||||
|                 ShowToast($"Load IV Fail: {PMInterUnitID}"); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         #endregion | ||||
| 
 | ||||
|         #region Reward | ||||
| 
 | ||||
|         public void LoadRewardAD() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         private static bool _isLoadingRV = false; | ||||
|         /// <summary> | ||||
|         /// 请求测试广告RV | ||||
|         /// </summary> | ||||
|         public static void RequestDebugRV() | ||||
|         { | ||||
|             if (_isLoadingRV) return; | ||||
|             _isLoadingRV = true; | ||||
|             EnableIVDebugMode(PMRewardUnitID); | ||||
|             AddRvCallBacks(); | ||||
|             MaxSdk.LoadRewardedAd(PMRewardUnitID); | ||||
|              | ||||
|             ShowToast($"Load RV: {PMInterUnitID}"); | ||||
|         } | ||||
| 
 | ||||
|         private static void AddRvCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Rewarded.OnAdLoadedEvent += OnDebugRVLoadSuccess; | ||||
|             MaxSdkCallbacks.Rewarded.OnAdLoadFailedEvent += OnDebugRVLoadFailed; | ||||
|         } | ||||
|          | ||||
|         private static void RemoveRvCallBacks() | ||||
|         { | ||||
|             MaxSdkCallbacks.Rewarded.OnAdLoadedEvent -= OnDebugRVLoadSuccess; | ||||
|             MaxSdkCallbacks.Rewarded.OnAdLoadFailedEvent -= OnDebugRVLoadFailed; | ||||
|         } | ||||
|          | ||||
|         private static void OnDebugRVLoadSuccess(string adUnitId, MaxSdkBase.AdInfo adInfo) | ||||
|         { | ||||
|             if (adUnitId == PMRewardUnitID) | ||||
|             { | ||||
|                 RemoveRvCallBacks(); | ||||
|                 _isLoadingRV = false; | ||||
|                 Debug.Log($"[PM] Load RV success => Revenue: {adInfo.Revenue}"); | ||||
|                 string placement = "pm_test_rv"; | ||||
|                 MaxSdk.ShowRewardedAd(adUnitId, placement); | ||||
|                 ShowToast($"Load RV Success: {PMRewardUnitID}"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void OnDebugRVLoadFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo) | ||||
|         { | ||||
|             if (adUnitId == PMRewardUnitID) | ||||
|             { | ||||
|                 RemoveRvCallBacks(); | ||||
|                 _isLoadingRV = false; | ||||
|                 Debug.Log($"[PM] Load RV fail => Waterfall:{errorInfo.WaterfallInfo.Name}"); | ||||
|                 ShowToast($"Load RV Fail: {PMRewardUnitID}"); | ||||
|             } | ||||
|         } | ||||
|         #endregion | ||||
|          | ||||
|         #region Debug | ||||
|          | ||||
|         private static void ShowToast(string msg) | ||||
|         { | ||||
| #if UNITY_ANDROID    | ||||
|             DeviceUtil.ShowToast(msg); | ||||
| #endif | ||||
|         } | ||||
|          | ||||
|         #endregion | ||||
|       | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: d1e329abcf494bd19dfc930b04c0ba5e | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,67 @@ | |||
| //================================================ | ||||
| // Company Name: Castbox | ||||
| // Project: Ball Sort Puzzle | ||||
| // Author: HYZ | ||||
| // CreateTime: 2023-04-12 21:06:02 | ||||
| // Version: 1.0.0 | ||||
| // Desc:  | ||||
| //================================================ | ||||
| 
 | ||||
| using UnityEngine.Serialization; | ||||
| 
 | ||||
| namespace Guru | ||||
| { | ||||
|     using System; | ||||
|     using UnityEngine; | ||||
|      | ||||
|     public partial class GuruSettings | ||||
|     { | ||||
|         [Header("Pubmatic 广告配置")] | ||||
|         public PubmaticSetting PubmaticSetting; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// Amazon广告配置 | ||||
|     /// </summary> | ||||
|     [Serializable] | ||||
|     public class PubmaticSetting | ||||
|     { | ||||
|         [SerializeField] public bool Enable; | ||||
|         [SerializeField] private PubmaticPlatformSetting Android; | ||||
|         [SerializeField] private PubmaticPlatformSetting iOS; | ||||
| 	 | ||||
|         /// <summary> | ||||
|         /// 获取AppID | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public PubmaticPlatformSetting GetPlatform() | ||||
|         { | ||||
| #if UNITY_IOS | ||||
| 			return iOS;  | ||||
| #else | ||||
|             return Android; | ||||
| #endif  | ||||
|         } | ||||
|          | ||||
|         public string BannerUnitID => GetPlatform().bannerUnitID; | ||||
|         public string InterUnitID => GetPlatform().interUnitID; | ||||
|         public string RewardUnitID => GetPlatform().rewardUnitID; | ||||
|         public string StoreUrl => GetPlatform().storeUrl; | ||||
| 
 | ||||
|     } | ||||
|      | ||||
|     /// <summary> | ||||
|     /// Amazon平台专属配置 | ||||
|     /// </summary> | ||||
|     [Serializable] | ||||
|     public class PubmaticPlatformSetting | ||||
|     { | ||||
|         // public string name;		// 平台名称 | ||||
|         public string storeUrl; // 平台商店地址 | ||||
|         public string bannerUnitID;	// Banner ID | ||||
|         public string interUnitID;	// Inter ID | ||||
|         public string rewardUnitID;	// Reward ID | ||||
|     } | ||||
|      | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: f7d6b41f0f5449be8ac0c4d1829bb330 | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,8 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: cd2ad07dfc12b418db1bcd4b3a316329 | ||||
| folderAsset: yes | ||||
| DefaultImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 729cc47bf56d436ba4c20380ca1e5e59 | ||||
| timeCreated: 1673860499 | ||||
|  | @ -0,0 +1,35 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!--  | ||||
| Sample Dependencies.xml: | ||||
|     https://github.com/googlesamples/unity-jar-resolver/blob/master/sample/Assets/ExternalDependencyManager/Editor/SampleDependencies.xml | ||||
| --> | ||||
| <dependencies> | ||||
|     <androidPackages> | ||||
|         <androidPackage spec="androidx.core:core:1.7.0" /> | ||||
| <!--        <androidPackage spec="androidx.appcompat:appcompat:1.5.1" />--> | ||||
|         <androidPackage spec="androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1" /> | ||||
|         <androidPackage spec="androidx.work:work-runtime:2.7.1" /> | ||||
|         <androidPackage spec="androidx.work:work-runtime-ktx:2.7.1" /> | ||||
|         <androidPackage spec="androidx.work:work-rxjava2:2.7.1" /> | ||||
|         <androidPackage spec="androidx.lifecycle:lifecycle-process:2.4.0" /> | ||||
|         <androidPackage spec="com.jakewharton.timber:timber:4.7.1" /> | ||||
|         <androidPackage spec="com.google.code.gson:gson:2.8.5" /> | ||||
|         <androidPackage spec="androidx.room:room-runtime:2.4.3" /> | ||||
|         <androidPackage spec="androidx.room:room-rxjava2:2.4.3" /> | ||||
|         <androidPackage spec="com.squareup.retrofit2:retrofit:2.7.1" /> | ||||
|         <androidPackage spec="com.squareup.retrofit2:converter-gson:2.7.1" /> | ||||
|         <androidPackage spec="com.squareup.retrofit2:adapter-rxjava2:2.7.1" /> | ||||
|         <androidPackage spec="com.squareup.okhttp3:okhttp:4.9.3" /> | ||||
|          | ||||
| <!--        <androidPackage spec="com.mapzen:on-the-road:0.8.1" />--> | ||||
| <!--        <androidPackage spec="com.squareup.retrofit2:retrofit:2.7.1" />--> | ||||
|     </androidPackages> | ||||
|     <iosPods> | ||||
|         <iosPod name="GuruAnalyticsLib" version="0.2.16" bitcodeEnabled="false"> | ||||
|             <sources> | ||||
|                 <source>git@github.com:castbox/GuruSpecs.git</source> | ||||
|             </sources> | ||||
|         </iosPod> | ||||
|         <iosPod name="JJException" bitcodeEnabled="false" /> | ||||
|     </iosPods> | ||||
| </dependencies> | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: b9cafb1d82bb45598fdd566d9b8f6a80 | ||||
| timeCreated: 1674110869 | ||||
|  | @ -0,0 +1,2 @@ | |||
| -keep class com.guru.** { *; } | ||||
| -keep class guru.core.** { *; } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue