فهرست منبع

启用本地排行榜

slambb 5 ماه پیش
والد
کامیت
f667540c71
93فایلهای تغییر یافته به همراه11628 افزوده شده و 119 حذف شده
  1. 10 0
      Assets/AddressableAssetsData/link.xml
  2. 7 0
      Assets/AddressableAssetsData/link.xml.meta
  3. 1 1
      Assets/BowArrow/InfraredCamera/InfraredDemo.cs
  4. 5 5
      Assets/BowArrow/Scenes/GameChallengeScene/GameChallenge.unity
  5. 14 0
      Assets/BowArrow/Scripts/Components/TextAutoLanguage2/Resources/TextAutoLanguage2/cn.json
  6. 13 0
      Assets/BowArrow/Scripts/Components/TextAutoLanguage2/Resources/TextAutoLanguage2/en.json
  7. 1 0
      Assets/BowArrow/Scripts/Expand/UserGameAnalyse.cs
  8. 3 1
      Assets/BowArrow/Scripts/Expand/UserGameAnalyse1.cs
  9. 3 0
      Assets/BowArrow/Scripts/GameChallenge/Views/HunterGameSettleView.cs
  10. 3 0
      Assets/BowArrow/Scripts/Network/SocketComp/RankComp.cs
  11. 7 0
      Assets/BowArrow/Scripts/View/TimeLimitGameSettleView.cs
  12. 43 5
      Assets/DuckHunter/Scripts/GameManager.cs
  13. 12 4
      Assets/DuckHunter/Scripts/GameUI.cs
  14. 33 2
      Assets/FruitMaster/Scripts/GamingManager.cs
  15. 3 0
      Assets/FruitMaster/Scripts/OverallLogics.cs
  16. 16 0
      Assets/Game_Hyperspace/Script/GeneratingTarget.cs
  17. 4 4
      Assets/InfraredProject/uvc/UVCInfrared.dll.meta
  18. 8 0
      Assets/RankDemo.meta
  19. 8 0
      Assets/RankDemo/Editor.meta
  20. 55 0
      Assets/RankDemo/Editor/RankEditorTool.cs
  21. 11 0
      Assets/RankDemo/Editor/RankEditorTool.cs.meta
  22. 8 0
      Assets/RankDemo/Plugins.meta
  23. BIN
      Assets/RankDemo/Plugins/.DS_Store
  24. 8 0
      Assets/RankDemo/Plugins/Android.meta
  25. BIN
      Assets/RankDemo/Plugins/Android/.DS_Store
  26. 8 0
      Assets/RankDemo/Plugins/Android/libs.meta
  27. BIN
      Assets/RankDemo/Plugins/Android/libs/.DS_Store
  28. 8 0
      Assets/RankDemo/Plugins/Android/libs/arm64-v8a.meta
  29. BIN
      Assets/RankDemo/Plugins/Android/libs/arm64-v8a/libsqlite3.so
  30. 80 0
      Assets/RankDemo/Plugins/Android/libs/arm64-v8a/libsqlite3.so.meta
  31. 8 0
      Assets/RankDemo/Plugins/Android/libs/armeabi-v7a.meta
  32. BIN
      Assets/RankDemo/Plugins/Android/libs/armeabi-v7a/libsqlite3.so
  33. 80 0
      Assets/RankDemo/Plugins/Android/libs/armeabi-v7a/libsqlite3.so.meta
  34. 8 0
      Assets/RankDemo/Plugins/Android/libs/x86.meta
  35. BIN
      Assets/RankDemo/Plugins/Android/libs/x86/libsqlite3.so
  36. 80 0
      Assets/RankDemo/Plugins/Android/libs/x86/libsqlite3.so.meta
  37. 8 0
      Assets/RankDemo/Plugins/x64.meta
  38. BIN
      Assets/RankDemo/Plugins/x64/sqlite3.dll
  39. 80 0
      Assets/RankDemo/Plugins/x64/sqlite3.dll.meta
  40. 8 0
      Assets/RankDemo/Plugins/x86.meta
  41. BIN
      Assets/RankDemo/Plugins/x86/sqlite3.dll
  42. 80 0
      Assets/RankDemo/Plugins/x86/sqlite3.dll.meta
  43. 8 0
      Assets/RankDemo/Prefabs.meta
  44. 922 0
      Assets/RankDemo/Prefabs/RankItem.prefab
  45. 7 0
      Assets/RankDemo/Prefabs/RankItem.prefab.meta
  46. 373 0
      Assets/RankDemo/Prefabs/item.prefab
  47. 7 0
      Assets/RankDemo/Prefabs/item.prefab.meta
  48. 698 0
      Assets/RankDemo/RankUIScene.unity
  49. 7 0
      Assets/RankDemo/RankUIScene.unity.meta
  50. 8 0
      Assets/RankDemo/Resources.meta
  51. 8 0
      Assets/RankDemo/Resources/SmartBow.meta
  52. 8 0
      Assets/RankDemo/Resources/SmartBow/Prefabs.meta
  53. 8 0
      Assets/RankDemo/Resources/SmartBow/Prefabs/Views.meta
  54. 1943 0
      Assets/RankDemo/Resources/SmartBow/Prefabs/Views/GameRankView.prefab
  55. 7 0
      Assets/RankDemo/Resources/SmartBow/Prefabs/Views/GameRankView.prefab.meta
  56. 8 0
      Assets/RankDemo/SQLite4Unity3d.meta
  57. BIN
      Assets/RankDemo/SQLite4Unity3d/.DS_Store
  58. 23 0
      Assets/RankDemo/SQLite4Unity3d/RankEntry.cs
  59. 11 0
      Assets/RankDemo/SQLite4Unity3d/RankEntry.cs.meta
  60. 271 0
      Assets/RankDemo/SQLite4Unity3d/RankService.cs
  61. 11 0
      Assets/RankDemo/SQLite4Unity3d/RankService.cs.meta
  62. 3377 0
      Assets/RankDemo/SQLite4Unity3d/SQLite.cs
  63. 11 0
      Assets/RankDemo/SQLite4Unity3d/SQLite.cs.meta
  64. 8 0
      Assets/RankDemo/Script.meta
  65. 210 0
      Assets/RankDemo/Script/RankItemUI.cs
  66. 11 0
      Assets/RankDemo/Script/RankItemUI.cs.meta
  67. 578 0
      Assets/RankDemo/Script/RankManager.cs
  68. 11 0
      Assets/RankDemo/Script/RankManager.cs.meta
  69. 279 0
      Assets/RankDemo/Script/RankUpAnimator.cs
  70. 11 0
      Assets/RankDemo/Script/RankUpAnimator.cs.meta
  71. 197 0
      Assets/RankDemo/Script/RankUpLooper.cs
  72. 11 0
      Assets/RankDemo/Script/RankUpLooper.cs.meta
  73. 8 0
      Assets/RankDemo/Texture.meta
  74. BIN
      Assets/RankDemo/Texture/rank.png
  75. 135 0
      Assets/RankDemo/Texture/rank.png.meta
  76. BIN
      Assets/RankDemo/Texture/rank__01.png
  77. 135 0
      Assets/RankDemo/Texture/rank__01.png.meta
  78. BIN
      Assets/RankDemo/Texture/rank__02.png
  79. 135 0
      Assets/RankDemo/Texture/rank__02.png.meta
  80. BIN
      Assets/RankDemo/Texture/rank__03.png
  81. 135 0
      Assets/RankDemo/Texture/rank__03.png.meta
  82. BIN
      Assets/RankDemo/Texture/rank__04.png
  83. 135 0
      Assets/RankDemo/Texture/rank__04.png.meta
  84. BIN
      Assets/RankDemo/Texture/rank__04_1.png
  85. 135 0
      Assets/RankDemo/Texture/rank__04_1.png.meta
  86. BIN
      Assets/RankDemo/Texture/rank__05.png
  87. 135 0
      Assets/RankDemo/Texture/rank__05.png.meta
  88. 818 96
      Assets/SmartBow/Resources/SmartBow/Prefabs/Views/Home/SettingsView.prefab
  89. 84 0
      Assets/SmartBow/Scripts/Views/SettingsViewParts/BoxBackStageManagement.cs
  90. 3 1
      Assets/SmartBow/Scripts/Views/ViewManager2.cs
  91. BIN
      Assets/StreamingAssets/rank.db
  92. 7 0
      Assets/StreamingAssets/rank.db.meta
  93. 7 0
      Assets/WildAttack/Scripts/Manager/GameMananger.cs

+ 10 - 0
Assets/AddressableAssetsData/link.xml

@@ -0,0 +1,10 @@
+<linker>
+  <assembly fullname="Unity.Addressables, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" preserve="all">
+    <type fullname="UnityEngine.AddressableAssets.Addressables" preserve="all" />
+  </assembly>
+  <assembly fullname="Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" preserve="all">
+    <type fullname="UnityEngine.ResourceManagement.ResourceProviders.InstanceProvider" preserve="all" />
+    <type fullname="UnityEngine.ResourceManagement.ResourceProviders.LegacyResourcesProvider" preserve="all" />
+    <type fullname="UnityEngine.ResourceManagement.ResourceProviders.SceneProvider" preserve="all" />
+  </assembly>
+</linker>

+ 7 - 0
Assets/AddressableAssetsData/link.xml.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: bc5c84c528283674fab21bce0738e2e0
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1 - 1
Assets/BowArrow/InfraredCamera/InfraredDemo.cs

@@ -107,7 +107,7 @@ public class InfraredDemo : JCUnityLib.ViewBase
         GUIStyle labelFont = new GUIStyle();
         labelFont.normal.textColor = new Color(1, 0.6f, 0.6f);
         labelFont.fontSize = Mathf.CeilToInt(Screen.height * 0.03f);
-        GUI.Label(new Rect(Screen.width / 100, Screen.height / 100, 100, 100), "game-20250409-1422-5-1", labelFont);
+        GUI.Label(new Rect(Screen.width / 100, Screen.height / 100, 100, 100), "game-20250516-1422-5-1", labelFont);
     }
 
     void Update()

+ 5 - 5
Assets/BowArrow/Scenes/GameChallengeScene/GameChallenge.unity

@@ -21329,7 +21329,7 @@ MonoBehaviour:
   m_ScaleFactor: 1
   m_ReferenceResolution: {x: 1280, y: 720}
   m_ScreenMatchMode: 0
-  m_MatchWidthOrHeight: 0
+  m_MatchWidthOrHeight: 1
   m_PhysicalUnit: 3
   m_FallbackScreenDPI: 96
   m_DefaultSpriteDPI: 96
@@ -24076,8 +24076,8 @@ RectTransform:
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
   m_AnchorMin: {x: 0, y: 1}
   m_AnchorMax: {x: 0, y: 1}
-  m_AnchoredPosition: {x: 28.832998, y: -16.5}
-  m_SizeDelta: {x: 37.665997, y: 33}
+  m_AnchoredPosition: {x: 30, y: -16.5}
+  m_SizeDelta: {x: 40, y: 33}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!114 &1047161075
 MonoBehaviour:
@@ -27623,8 +27623,8 @@ RectTransform:
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
   m_AnchorMin: {x: 0, y: 1}
   m_AnchorMax: {x: 0, y: 1}
-  m_AnchoredPosition: {x: 29.646412, y: -16.5}
-  m_SizeDelta: {x: 0, y: 33}
+  m_AnchoredPosition: {x: 30, y: -16.5}
+  m_SizeDelta: {x: 40, y: 33}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!114 &1203594963
 MonoBehaviour:

+ 14 - 0
Assets/BowArrow/Scripts/Components/TextAutoLanguage2/Resources/TextAutoLanguage2/cn.json

@@ -504,6 +504,17 @@
   "Rank_Name": "名字",
   "Rank_Score": "分数",
   "Rank_Country": "地区",
+
+  /**
+  本地排行榜
+  **/
+  "BowGod": "弓神",
+  "BowEmperor": "弓皇",
+  "BowKing": "弓王",
+  "GunGod": "枪神",
+  "GunEmperor": "枪皇",
+  "GunKing": "枪王",
+
   /**
   设置页面
   **/
@@ -530,6 +541,9 @@
   "DeviceConnect": "设备连接",
   "CoinRatio": "投币比例(局)",
   "GameDuration": "游戏时长(局)",
+  "ClearLocalRank": "本地排行榜",
+  "ClearLocalRankSelected": "清空选择",
+  "ClearLocalRankAll": "清空全部",
 
 
   "CalibrationTime": "视角校准时间 (3~20s)",

+ 13 - 0
Assets/BowArrow/Scripts/Components/TextAutoLanguage2/Resources/TextAutoLanguage2/en.json

@@ -554,6 +554,16 @@
   "Rank_Name": "Name",
   "Rank_Score": "Score",
   "Rank_Country": "Country",
+
+  /**
+  本地排行榜
+  **/
+  "BowGod": "BowGod",
+  "BowEmperor": "Bow\nEmperor",
+  "BowKing": "BowKing",
+  "GunGod": "GunGod",
+  "GunEmperor": "Gun\nEmperor",
+  "GunKing": "GunKing",
   /**
   设置页面
   **/
@@ -580,6 +590,9 @@
   "DeviceConnect": "Device Connect",
   "CoinRatio": "Coin Ratio(per round)",
   "GameDuration": "Game Duration(per round)",
+  "ClearLocalRank": "Local leaderboard",
+  "ClearLocalRankSelected": "Clear Selected",
+  "ClearLocalRankAll": "Clear All",
 
   "CalibrationTime": "Calibration Time (3~20s)",
   "BowToScreenDisBest": "Best Bow-to-screen Distance",

+ 1 - 0
Assets/BowArrow/Scripts/Expand/UserGameAnalyse.cs

@@ -2,6 +2,7 @@ using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using System;
+using LocalRank;
 
 /* 用户游戏情况统计分析-主要向服务器是上传用户游戏数据 */
 public class UserGameAnalyse : MonoBehaviour

+ 3 - 1
Assets/BowArrow/Scripts/Expand/UserGameAnalyse1.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using LocalRank;
 using UnityEngine;
 using UnityEngine.SceneManagement;
 
@@ -131,13 +132,14 @@ public class UserGameAnalyse1 : MonoBehaviour
         GameResultView gameResultView = resultObj.GetComponent<GameResultView>();
         gameResultView.OnBackClicked += callback;
         gameResultView.setGameResultInfo(gameInfo.textId, (int)allTimeSecond, allShootingCount);
-        onResetOverlayData();
+       
         //b端直接返回,不处理弹出框
         if (CommonConfig.StandaloneModeOrPlatformB)
         {
             resultObj.SetActive(false);
             callback?.Invoke();
         }
+        onResetOverlayData();
         return gameResultView;
     }
 

+ 3 - 0
Assets/BowArrow/Scripts/GameChallenge/Views/HunterGameSettleView.cs

@@ -9,6 +9,9 @@ public class HunterGameSettleView : MonoBehaviour
     // Start is called before the first frame update
     void Start()
     {
+        //设置一下需要上传排行榜的分数,先写死了
+       // LocalRank.RankManager.SetCurrentScore(1500);
+
         ChallengeGameMode gameMode = (ChallengeGameMode) GameMgr.ins.gameMode;
         string res = gameMode.Settle()[0].ToString();
         if (res == "胜利") {

+ 3 - 0
Assets/BowArrow/Scripts/Network/SocketComp/RankComp.cs

@@ -20,6 +20,9 @@ public class RankComp : JCUnityLib.Singleton<RankComp>
     //单机上传结果
     public void uploadSinglePlayerGameRes(int score)
     {
+        //设置一下需要上传排行榜的分数
+       // LocalRank.RankManager.SetCurrentScore(score);
+
         //rankComp.uploadSeasonSinglePlayerGameRes 使用赛季上传分数接口,替换rankComp.uploadSinglePlayerGameRes
         UserPlayer.ins.call(
             "rankComp.uploadSeasonSinglePlayerGameRes",

+ 7 - 0
Assets/BowArrow/Scripts/View/TimeLimitGameSettleView.cs

@@ -40,6 +40,13 @@ public class TimeLimitGameSettleView : MonoBehaviour
         AudioMgr.ins.PlayWin();
         SimulateMouseController.ins?.AddOpenLocker("NotGame");
         GameOverInterface.OnGameOver(GameMgr.gameType);
+
+        if (CommonConfig.StandaloneModeOrPlatformB)
+        {
+            //设置一下需要上传排行榜的分数
+            LocalRank.RankManager.SetCurrentScore((int)score);
+            LocalRank.RankManager.CreateRankView(GameMgr.gameType, null);
+        }
     }
 
     public void OnClick_Back() {

+ 43 - 5
Assets/DuckHunter/Scripts/GameManager.cs

@@ -1,5 +1,4 @@
-using System.Collections;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.EventSystems;
 
@@ -77,7 +76,14 @@ namespace DuckHunter
                 if (EventSystem.current.currentSelectedGameObject == null)
                 {
                     CrossHair.Instance.transform.position = Input.mousePosition;
-                    OnModuleShooting(10);
+
+                    #if UNITY_EDITOR    
+                            bool isAdd = true;
+                    #else
+                            bool isAdd = false;
+                    #endif
+
+                    OnModuleShooting(10, isAdd);
                 }
             }
         }
@@ -424,10 +430,15 @@ namespace DuckHunter
                 //通关失败
                 TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_OVER, null, () =>
                 {
-                    UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
+                    //UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
+                    //失败时候也时候弹出排行榜
+                    UploadBestScoreToLocalRank(() => {
+                        UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
+                    });
                 });
                 AudioManager.Instance.PlayGameOver();
                 Debug.Log("通关失败");
+
             }
             else
             {
@@ -459,6 +470,7 @@ namespace DuckHunter
         //野鸭退出时候保存分数到服务器
         public void onUploadScore()
         {
+            //uploadScore = 500;
             if (uploadScore > 0)
             {
                 Debug.Log("野鸭上传的积分为:" + uploadScore);
@@ -477,12 +489,38 @@ namespace DuckHunter
                 {
                     DefaultLevel = level + 1;
                     AutoNextLevel = true;
+                    //小于20,就是未完全通关
+                    UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
+                }
+                else {
+                    //完全通过时候弹出排行榜
+                    UploadBestScoreToLocalRank(() => {
+                        UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
+                    });
                 }
-                UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
+                Debug.Log("野鸭跳转关卡:"+ DefaultLevel);
+               
+                //UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
             });
             AudioManager.Instance.PlayGamePass();
             Debug.Log("通关成功");
         }
+        /// <summary>
+        /// 把累计得分记录到本地数据库
+        /// </summary>
+        public void UploadBestScoreToLocalRank(System.Action callback) {
+            if (CommonConfig.StandaloneModeOrPlatformB)
+            {
+                //获取当前记录的最高分数
+                LocalRank.RankManager.SetCurrentScore(_CumulativeScore);
+                LocalRank.RankManager.CreateRankView(GlobalData.singlePlayerGameType, callback);
+            }
+            else
+            {
+                callback?.Invoke();
+            }
+        }
+
         int _arrowCount;
         int arrowCount
         {

+ 12 - 4
Assets/DuckHunter/Scripts/GameUI.cs

@@ -325,11 +325,19 @@ namespace DuckHunter
                 Debug.Log("野鸭btnBack上传的积分:");
                 GameManager.Instance.onUploadScore();
 
-                //结束游戏页面
-                gameResultView = GameManager.Instance.userGameAnalyse1.showResultView(() =>
-                {
-                    UnityEngine.SceneManagement.SceneManager.LoadScene("Home", UnityEngine.SceneManagement.LoadSceneMode.Single);
+                //处理本地排行榜
+                GameManager.Instance.UploadBestScoreToLocalRank(()=> {
+                    //结束游戏页面
+                    gameResultView = GameManager.Instance.userGameAnalyse1.showResultView(() =>
+                    {
+                        UnityEngine.SceneManagement.SceneManager.LoadScene("Home", UnityEngine.SceneManagement.LoadSceneMode.Single);
+                    });
                 });
+                ////结束游戏页面
+                //gameResultView = GameManager.Instance.userGameAnalyse1.showResultView(() =>
+                //{
+                //    UnityEngine.SceneManagement.SceneManager.LoadScene("Home", UnityEngine.SceneManagement.LoadSceneMode.Single);
+                //});
 
                 num += 1;
                 return;

+ 33 - 2
Assets/FruitMaster/Scripts/GamingManager.cs

@@ -542,6 +542,15 @@ public class GamingManager : MonoBehaviour
         bGameStarted = false;
         ShowGamingUI(false);
 
+        if (CommonConfig.StandaloneModeOrPlatformB)
+        {
+            //uploadScore = 455;
+            //设置一下需要上传排行榜的分数
+            LocalRank.RankManager.SetCurrentScore((int)uploadScore);
+            //这里切水果可能会重复调用。加个数值判断,简单的防止重复调用
+            if(uploadScore>0) LocalRank.RankManager.CreateRankView(GlobalData.singlePlayerGameType, null);
+        }
+
         //水果上传分数
         onUploadScore();
 
@@ -568,7 +577,24 @@ public class GamingManager : MonoBehaviour
         if (num == 0)
         {
             onUploadScore();
-
+            ////点击退出按钮时候。先滚动排行榜再退出
+            //if (CommonConfig.StandaloneModeOrPlatformB)
+            //{
+            //    LocalRank.RankManager.CreateRankView(GlobalData.singlePlayerGameType, ()=> {
+            //        //结束游戏页面
+            //        gameResultView = userGameAnalyse1.showResultView(() =>
+            //        {
+            //            UnityEngine.SceneManagement.SceneManager.LoadScene("Home", UnityEngine.SceneManagement.LoadSceneMode.Single);
+            //        });
+            //    });
+            //}
+            //else {
+            //    //结束游戏页面
+            //    gameResultView = userGameAnalyse1.showResultView(() =>
+            //    {
+            //        UnityEngine.SceneManagement.SceneManager.LoadScene("Home", UnityEngine.SceneManagement.LoadSceneMode.Single);
+            //    });
+            //}
             //结束游戏页面
             gameResultView = userGameAnalyse1.showResultView(() =>
             {
@@ -765,7 +791,12 @@ public class GamingManager : MonoBehaviour
     private void MouseFireArrow(Vector3 screenPos)
     {
         Vector3 worldPos = Cam.ScreenToWorldPoint(new Vector3(screenPos.x, screenPos.y, 10.0f));
-        FireArrow(20.0f, worldPos - Cam.transform.position);
+#if UNITY_EDITOR
+        bool isAdd = true;
+#else
+        bool isAdd = false;
+#endif
+        FireArrow(20.0f, worldPos - Cam.transform.position, isAdd);
     }
 
     private void OnFruitHit(FruitBehavior fb, Vector3 hitPoint, bool bCritical)

+ 3 - 0
Assets/FruitMaster/Scripts/OverallLogics.cs

@@ -253,6 +253,9 @@ public class OverallLogics : MonoBehaviour
     {
         Scores.text = "Scores   " + scores;
 
+        //设置一下需要上传排行榜的分数
+        // LocalRank.RankManager.SetCurrentScore((int)scores);
+
         if (reason == EndGameReason.GameOver)
         {
             bPlayingGameOverAnim = true;

+ 16 - 0
Assets/Game_Hyperspace/Script/GeneratingTarget.cs

@@ -441,6 +441,7 @@ public class GeneratingTarget : MonoBehaviour
         isbegin = false;
         countDownTimeCache = 0;
 
+        onShowRankView();
         //游戏结束上传分数
         onUploadScore();
 
@@ -566,6 +567,10 @@ public class GeneratingTarget : MonoBehaviour
 
     public void GameOverGrade(int score)
     {
+        //打靶游戏最近一次分数
+        //设置一下需要上传排行榜的分数
+        //LocalRank.RankManager.SetCurrentScore((int)score);
+
         hitCountUI.text = hitCount.ToString();
 
         var bulletUse = bulletCount - font.Clip;
@@ -694,6 +699,17 @@ public class GeneratingTarget : MonoBehaviour
             _score = 0;
         }
     }
+
+    public void onShowRankView() {
+        if (CommonConfig.StandaloneModeOrPlatformB)
+        {
+            //_score = 400;
+            //设置一下需要上传排行榜的分数
+            LocalRank.RankManager.SetCurrentScore((int)_score);
+            LocalRank.RankManager.CreateRankView(GlobalData.singlePlayerGameType, null);
+        }
+    }
+
     #endregion
 }
 

+ 4 - 4
Assets/InfraredProject/uvc/UVCInfrared.dll.meta

@@ -16,17 +16,17 @@ PluginImporter:
     second:
       enabled: 0
       settings:
-        Exclude Android: 1
+        Exclude Android: 0
         Exclude Editor: 0
         Exclude Linux64: 0
         Exclude OSXUniversal: 0
         Exclude Win: 0
         Exclude Win64: 0
-        Exclude iOS: 1
+        Exclude iOS: 0
   - first:
       Android: Android
     second:
-      enabled: 0
+      enabled: 1
       settings:
         CPU: ARMv7
   - first:
@@ -75,7 +75,7 @@ PluginImporter:
   - first:
       iPhone: iOS
     second:
-      enabled: 0
+      enabled: 1
       settings:
         AddToEmbeddedBinaries: false
         CPU: AnyCPU

+ 8 - 0
Assets/RankDemo.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 897542fa2b264e3499f532c6dea9315d
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Editor.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c8e0ae0b370a3e34d80fe82ef64cbd3f
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 55 - 0
Assets/RankDemo/Editor/RankEditorTool.cs

@@ -0,0 +1,55 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections.Generic;
+namespace LocalRank
+{
+    public static class RankEditorTool
+    {
+        // 动态获取 GameId 列表
+        private static List<int> GameIds => RankService.GetAllGameIds();
+        // 自定义 GameId 列表 
+        private static readonly List<int> CustomGameIds = new List<int> { 1, 13, 14, 15, 16 };
+
+        [MenuItem("Tools/排行榜/创建排行榜表")]
+        public static void CreateAllRankTables()
+        {
+            foreach (var gameId in CustomGameIds)
+            {
+                RankService.CreateTableIfNotExists(gameId);
+                Debug.Log($"已创建排行榜表:rank_game_{gameId}");
+            }
+
+            EditorUtility.DisplayDialog("操作完成", "已创建所有排行榜表", "好的");
+        }
+
+        [MenuItem("Tools/排行榜/清空所有排行榜表")]
+        public static void ClearAllRankTables()
+        {
+            if (!EditorUtility.DisplayDialog("警告", "你确定要清空所有排行榜数据吗?此操作不可撤销!", "确定", "取消"))
+                return;
+
+            foreach (var gameId in GameIds)
+            {
+                RankService.ClearTable(gameId);
+                Debug.Log($"已清空排行榜表:rank_game_{gameId}");
+            }
+
+            EditorUtility.DisplayDialog("操作完成", "已清空所有排行榜表数据", "好的");
+        }
+
+        [MenuItem("Tools/排行榜/打印所有排行榜数据")]
+        public static void PrintAllRanks()
+        {
+            foreach (var gameId in GameIds)
+            {
+                var (list, _, count) = RankService.GetRankList(gameId, -1);
+                Debug.Log($"[rank_game_{gameId}] 总记录数:{count}");
+                foreach (var entry in list)
+                {
+                    Debug.Log($"[{entry.Rank}] {entry.Nickname} - {entry.Score} {(entry.IsSelf ? "(自己)" : "")}");
+                }
+            }
+            EditorUtility.DisplayDialog("打印完成", "已在控制台输出所有排行榜数据", "好的");
+        }
+    }
+}

+ 11 - 0
Assets/RankDemo/Editor/RankEditorTool.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9a4b6d205d8abd947bfbde8625c29ada
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Plugins.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e370cb38bef17064dabaface00e3d1c5
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Plugins/.DS_Store


+ 8 - 0
Assets/RankDemo/Plugins/Android.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9852095d4f942164b93631f4b1ae150f
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Plugins/Android/.DS_Store


+ 8 - 0
Assets/RankDemo/Plugins/Android/libs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f96f649cc548cad41876425c558015f7
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Plugins/Android/libs/.DS_Store


+ 8 - 0
Assets/RankDemo/Plugins/Android/libs/arm64-v8a.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ab444c48fa2e924439dfc1e3db4fb8a4
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Plugins/Android/libs/arm64-v8a/libsqlite3.so


+ 80 - 0
Assets/RankDemo/Plugins/Android/libs/arm64-v8a/libsqlite3.so.meta

@@ -0,0 +1,80 @@
+fileFormatVersion: 2
+guid: 2b2532f5c724b534cb442919de0925b1
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      : Any
+    second:
+      enabled: 0
+      settings:
+        Exclude Android: 0
+        Exclude Editor: 1
+        Exclude Linux64: 1
+        Exclude OSXUniversal: 1
+        Exclude Win: 1
+        Exclude Win64: 1
+        Exclude iOS: 1
+  - first:
+      Android: Android
+    second:
+      enabled: 1
+      settings:
+        CPU: ARM64
+  - first:
+      Any: 
+    second:
+      enabled: 0
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+        DefaultValueInitialized: true
+        OS: AnyOS
+  - first:
+      Standalone: Linux64
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: OSXUniversal
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: Win
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: Win64
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      iPhone: iOS
+    second:
+      enabled: 0
+      settings:
+        AddToEmbeddedBinaries: false
+        CPU: AnyCPU
+        CompileFlags: 
+        FrameworkDependencies: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Plugins/Android/libs/armeabi-v7a.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 28f2620a7b5687646bd70be453002fb1
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Plugins/Android/libs/armeabi-v7a/libsqlite3.so


+ 80 - 0
Assets/RankDemo/Plugins/Android/libs/armeabi-v7a/libsqlite3.so.meta

@@ -0,0 +1,80 @@
+fileFormatVersion: 2
+guid: e90a7dca41dd28349b5f0938be2ee238
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      : Any
+    second:
+      enabled: 0
+      settings:
+        Exclude Android: 0
+        Exclude Editor: 1
+        Exclude Linux64: 1
+        Exclude OSXUniversal: 1
+        Exclude Win: 1
+        Exclude Win64: 1
+        Exclude iOS: 1
+  - first:
+      Android: Android
+    second:
+      enabled: 1
+      settings:
+        CPU: ARMv7
+  - first:
+      Any: 
+    second:
+      enabled: 0
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+        DefaultValueInitialized: true
+        OS: AnyOS
+  - first:
+      Standalone: Linux64
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: OSXUniversal
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: Win
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: Win64
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      iPhone: iOS
+    second:
+      enabled: 0
+      settings:
+        AddToEmbeddedBinaries: false
+        CPU: AnyCPU
+        CompileFlags: 
+        FrameworkDependencies: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Plugins/Android/libs/x86.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e5fc46faaefd1854eb2a3effe056357d
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Plugins/Android/libs/x86/libsqlite3.so


+ 80 - 0
Assets/RankDemo/Plugins/Android/libs/x86/libsqlite3.so.meta

@@ -0,0 +1,80 @@
+fileFormatVersion: 2
+guid: 11c680d85d9464c4bb36747418fcada6
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      : Any
+    second:
+      enabled: 0
+      settings:
+        Exclude Android: 0
+        Exclude Editor: 1
+        Exclude Linux64: 1
+        Exclude OSXUniversal: 1
+        Exclude Win: 1
+        Exclude Win64: 1
+        Exclude iOS: 1
+  - first:
+      Android: Android
+    second:
+      enabled: 1
+      settings:
+        CPU: X86_64
+  - first:
+      Any: 
+    second:
+      enabled: 0
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+        DefaultValueInitialized: true
+        OS: AnyOS
+  - first:
+      Standalone: Linux64
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: OSXUniversal
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: Win
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      Standalone: Win64
+    second:
+      enabled: 0
+      settings:
+        CPU: None
+  - first:
+      iPhone: iOS
+    second:
+      enabled: 0
+      settings:
+        AddToEmbeddedBinaries: false
+        CPU: AnyCPU
+        CompileFlags: 
+        FrameworkDependencies: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Plugins/x64.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: eeaf57f3c2f92704daac03733940df1b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Plugins/x64/sqlite3.dll


+ 80 - 0
Assets/RankDemo/Plugins/x64/sqlite3.dll.meta

@@ -0,0 +1,80 @@
+fileFormatVersion: 2
+guid: e56da183a7ce86e408b9917998f3a1ee
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      : Any
+    second:
+      enabled: 0
+      settings:
+        Exclude Android: 1
+        Exclude Editor: 0
+        Exclude Linux64: 0
+        Exclude OSXUniversal: 0
+        Exclude Win: 0
+        Exclude Win64: 0
+        Exclude iOS: 1
+  - first:
+      Android: Android
+    second:
+      enabled: 0
+      settings:
+        CPU: ARMv7
+  - first:
+      Any: 
+    second:
+      enabled: 0
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 1
+      settings:
+        CPU: x86_64
+        DefaultValueInitialized: true
+        OS: AnyOS
+  - first:
+      Standalone: Linux64
+    second:
+      enabled: 1
+      settings:
+        CPU: None
+  - first:
+      Standalone: OSXUniversal
+    second:
+      enabled: 1
+      settings:
+        CPU: None
+  - first:
+      Standalone: Win
+    second:
+      enabled: 1
+      settings:
+        CPU: None
+  - first:
+      Standalone: Win64
+    second:
+      enabled: 1
+      settings:
+        CPU: None
+  - first:
+      iPhone: iOS
+    second:
+      enabled: 0
+      settings:
+        AddToEmbeddedBinaries: false
+        CPU: AnyCPU
+        CompileFlags: 
+        FrameworkDependencies: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Plugins/x86.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 03498069a2293024ca2513f9dd4a4d80
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Plugins/x86/sqlite3.dll


+ 80 - 0
Assets/RankDemo/Plugins/x86/sqlite3.dll.meta

@@ -0,0 +1,80 @@
+fileFormatVersion: 2
+guid: 43e5e3f64d942a048ad1f2b1f2e8a1dd
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      : Any
+    second:
+      enabled: 0
+      settings:
+        Exclude Android: 1
+        Exclude Editor: 1
+        Exclude Linux64: 0
+        Exclude OSXUniversal: 0
+        Exclude Win: 0
+        Exclude Win64: 0
+        Exclude iOS: 1
+  - first:
+      Android: Android
+    second:
+      enabled: 0
+      settings:
+        CPU: ARMv7
+  - first:
+      Any: 
+    second:
+      enabled: 0
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+        DefaultValueInitialized: true
+        OS: AnyOS
+  - first:
+      Standalone: Linux64
+    second:
+      enabled: 1
+      settings:
+        CPU: None
+  - first:
+      Standalone: OSXUniversal
+    second:
+      enabled: 1
+      settings:
+        CPU: x86
+  - first:
+      Standalone: Win
+    second:
+      enabled: 1
+      settings:
+        CPU: x86
+  - first:
+      Standalone: Win64
+    second:
+      enabled: 1
+      settings:
+        CPU: None
+  - first:
+      iPhone: iOS
+    second:
+      enabled: 0
+      settings:
+        AddToEmbeddedBinaries: false
+        CPU: AnyCPU
+        CompileFlags: 
+        FrameworkDependencies: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Prefabs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0c3accd56ec86374db7e5a223fa390b4
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 922 - 0
Assets/RankDemo/Prefabs/RankItem.prefab

@@ -0,0 +1,922 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &554455402995935311
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2458476100413831150}
+  - component: {fileID: 6115569171396479750}
+  - component: {fileID: 3185012323442255610}
+  m_Layer: 5
+  m_Name: Image
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &2458476100413831150
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 554455402995935311}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 832898112561691029}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 1.5}
+  m_Pivot: {x: 0.5, y: 0}
+--- !u!222 &6115569171396479750
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 554455402995935311}
+  m_CullTransparentMesh: 1
+--- !u!114 &3185012323442255610
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 554455402995935311}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 0.43137255}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!1 &832898112334673535
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 832898112334673534}
+  - component: {fileID: 832898112334673532}
+  - component: {fileID: 832898112334673533}
+  m_Layer: 5
+  m_Name: Name
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 0
+--- !u!224 &832898112334673534
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112334673535}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 3659066005014099935}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: -256.70016, y: -25}
+  m_SizeDelta: {x: 156.3997, y: 30}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &832898112334673532
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112334673535}
+  m_CullTransparentMesh: 1
+--- !u!114 &832898112334673533
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112334673535}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 12800000, guid: 6b6cc7ab59ef00947950b61fdca2d042, type: 3}
+    m_FontSize: 14
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 10
+    m_MaxSize: 40
+    m_Alignment: 3
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: New Text
+--- !u!1 &832898112561691030
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 832898112561691029}
+  - component: {fileID: 832898112561691027}
+  - component: {fileID: 832898112561691028}
+  - component: {fileID: 9185976299326908605}
+  - component: {fileID: 3023514414911811684}
+  - component: {fileID: 1186969225910988005}
+  m_Layer: 5
+  m_Name: RankItem
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &832898112561691029
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 3659066005014099935}
+  - {fileID: 2458476100413831150}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 530, y: 70}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &832898112561691027
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_CullTransparentMesh: 1
+--- !u!114 &832898112561691028
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 21300000, guid: cd169d64f12d9d147bea319978a5ea4f, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!225 &9185976299326908605
+CanvasGroup:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_Enabled: 1
+  m_Alpha: 1
+  m_Interactable: 1
+  m_BlocksRaycasts: 1
+  m_IgnoreParentGroups: 0
+--- !u!114 &3023514414911811684
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_Enabled: 0
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_EffectColor: {r: 1, g: 0.8797743, b: 0.2216981, a: 1}
+  m_EffectDistance: {x: 3, y: 3}
+  m_UseGraphicAlpha: 1
+--- !u!114 &1186969225910988005
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 47285bf021b82ab4aa3af99b40c042c4, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  rankIndexText: {fileID: 832898112334673533}
+  infoText: {fileID: 832898113075269754}
+  avatarImage: {fileID: 832898113181171497}
+  iconTransform: {fileID: 6508610744115872410}
+  iconImage: {fileID: 3615622347550131226}
+  iconText: {fileID: 5654358528171311603}
+  outline: {fileID: 3023514414911811684}
+  firstPlaceSprite:
+    sprite: {fileID: 21300000, guid: 57a60eccffe60214c8ab5a3df9459659, type: 3}
+    size: {x: 100, y: 60}
+    bowTextKey: BowGod
+    gunTextKey: GunGod
+  secondPlaceSprite:
+    sprite: {fileID: 21300000, guid: 85a2a6d848aa741458e09f4ae3101774, type: 3}
+    size: {x: 83, y: 48}
+    bowTextKey: BowEmperor
+    gunTextKey: GunEmperor
+  thirdPlaceSprite:
+    sprite: {fileID: 21300000, guid: a4118a0f7030fcc4ca88fff25884e504, type: 3}
+    size: {x: 68, y: 48}
+    bowTextKey: BowKing
+    gunTextKey: GunKing
+  titleText: {fileID: 581418049955302731}
+  selfSprite: {fileID: 21300000, guid: 07c163659ccbe054bbe34e9487d085ac, type: 3}
+  otherSprite: {fileID: 21300000, guid: cd169d64f12d9d147bea319978a5ea4f, type: 3}
+  otherTopSprite: {fileID: 21300000, guid: acf4bfc90969db545b51e2bdb508143c, type: 3}
+--- !u!1 &832898113075269756
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 832898113075269755}
+  - component: {fileID: 832898113075269753}
+  - component: {fileID: 832898113075269754}
+  m_Layer: 5
+  m_Name: Score
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &832898113075269755
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113075269756}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 2700919806368996517}
+  m_Father: {fileID: 3659066005014099935}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 276, y: 28}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &832898113075269753
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113075269756}
+  m_CullTransparentMesh: 1
+--- !u!114 &832898113075269754
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113075269756}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 12800000, guid: 6b6cc7ab59ef00947950b61fdca2d042, type: 3}
+    m_FontSize: 24
+    m_FontStyle: 1
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 40
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 1
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: New Text
+--- !u!1 &832898113181171499
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 832898113181171498}
+  - component: {fileID: 832898113181171496}
+  - component: {fileID: 832898113181171497}
+  m_Layer: 5
+  m_Name: Avatar
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 0
+--- !u!224 &832898113181171498
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113181171499}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 7537517811441696733}
+  m_Father: {fileID: 3659066005014099935}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: -314.8999, y: -25}
+  m_SizeDelta: {x: 40, y: 40}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &832898113181171496
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113181171499}
+  m_CullTransparentMesh: 1
+--- !u!114 &832898113181171497
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113181171499}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!1 &1913051710494382432
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2700919806368996517}
+  m_Layer: 5
+  m_Name: GameObject
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &2700919806368996517
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1913051710494382432}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 832898113075269755}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 100, y: 100}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!1 &3221256388225767998
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 7537517811441696733}
+  m_Layer: 5
+  m_Name: GameObject
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &7537517811441696733
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3221256388225767998}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 832898113181171498}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 100, y: 100}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!1 &6823839332133900444
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2660638499431028102}
+  - component: {fileID: 2092377113212998699}
+  - component: {fileID: 5654358528171311603}
+  m_Layer: 5
+  m_Name: text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 0
+--- !u!224 &2660638499431028102
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6823839332133900444}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 6508610744115872410}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 100, y: 60}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &2092377113212998699
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6823839332133900444}
+  m_CullTransparentMesh: 1
+--- !u!114 &5654358528171311603
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6823839332133900444}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 12800000, guid: 6b6cc7ab59ef00947950b61fdca2d042, type: 3}
+    m_FontSize: 28
+    m_FontStyle: 1
+    m_BestFit: 0
+    m_MinSize: 0
+    m_MaxSize: 40
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 1
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: 111
+--- !u!1 &7689929013825315098
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 3659066005014099935}
+  - component: {fileID: 3813832183125806175}
+  m_Layer: 5
+  m_Name: Infos
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &3659066005014099935
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7689929013825315098}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 6508610744115872410}
+  - {fileID: 832898113181171498}
+  - {fileID: 832898112334673534}
+  - {fileID: 832898113075269755}
+  m_Father: {fileID: 832898112561691029}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &3813832183125806175
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7689929013825315098}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 130
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 3
+  m_Spacing: 10
+  m_ChildForceExpandWidth: 0
+  m_ChildForceExpandHeight: 1
+  m_ChildControlWidth: 0
+  m_ChildControlHeight: 0
+  m_ChildScaleWidth: 0
+  m_ChildScaleHeight: 0
+  m_ReverseArrangement: 0
+--- !u!1 &7701058500389533559
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2940127483142359962}
+  - component: {fileID: 4965005837733034660}
+  - component: {fileID: 3615622347550131226}
+  m_Layer: 5
+  m_Name: Icon
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &2940127483142359962
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7701058500389533559}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 6508610744115872410}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 100, y: 60}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &4965005837733034660
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7701058500389533559}
+  m_CullTransparentMesh: 1
+--- !u!114 &3615622347550131226
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7701058500389533559}
+  m_Enabled: 0
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!1 &7939309948901421944
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6508610744115872410}
+  - component: {fileID: 5089918006690368362}
+  m_Layer: 5
+  m_Name: Rank
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &6508610744115872410
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7939309948901421944}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 4161731302994152105}
+  - {fileID: 2940127483142359962}
+  - {fileID: 2660638499431028102}
+  - {fileID: 2791680619679986247}
+  m_Father: {fileID: 3659066005014099935}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 100, y: 60}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &5089918006690368362
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7939309948901421944}
+  m_CullTransparentMesh: 1
+--- !u!1 &8217389586052904347
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2791680619679986247}
+  m_Layer: 5
+  m_Name: GameObject
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &2791680619679986247
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8217389586052904347}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 6508610744115872410}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 100, y: 100}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!1 &8422444897698682803
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4161731302994152105}
+  - component: {fileID: 2151918531277895303}
+  - component: {fileID: 581418049955302731}
+  m_Layer: 5
+  m_Name: Title
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &4161731302994152105
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8422444897698682803}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 6508610744115872410}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0.5}
+  m_AnchorMax: {x: 0, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 107.66, y: 60}
+  m_Pivot: {x: 1, y: 0.5}
+--- !u!222 &2151918531277895303
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8422444897698682803}
+  m_CullTransparentMesh: 1
+--- !u!114 &581418049955302731
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8422444897698682803}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 12800000, guid: 6b6cc7ab59ef00947950b61fdca2d042, type: 3}
+    m_FontSize: 24
+    m_FontStyle: 1
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 40
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: 

+ 7 - 0
Assets/RankDemo/Prefabs/RankItem.prefab.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: e0f300258cc55d1449fd16d4c283cc6a
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 373 - 0
Assets/RankDemo/Prefabs/item.prefab

@@ -0,0 +1,373 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &832898112334673535
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 832898112334673534}
+  - component: {fileID: 832898112334673532}
+  - component: {fileID: 832898112334673533}
+  m_Layer: 5
+  m_Name: Name
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &832898112334673534
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112334673535}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 832898112561691029}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 62.53, y: 30}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &832898112334673532
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112334673535}
+  m_CullTransparentMesh: 1
+--- !u!114 &832898112334673533
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112334673535}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 14
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 10
+    m_MaxSize: 40
+    m_Alignment: 3
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: New Text
+--- !u!1 &832898112561691030
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 832898112561691029}
+  - component: {fileID: 832898112561691026}
+  - component: {fileID: 832898112561691027}
+  - component: {fileID: 832898112561691028}
+  - component: {fileID: 832898112561691025}
+  - component: {fileID: 9185976299326908605}
+  m_Layer: 5
+  m_Name: item
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &832898112561691029
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 832898113181171498}
+  - {fileID: 832898112334673534}
+  - {fileID: 832898113075269755}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 300, y: 50}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &832898112561691026
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 0
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 3
+  m_Spacing: 10
+  m_ChildForceExpandWidth: 0
+  m_ChildForceExpandHeight: 1
+  m_ChildControlWidth: 0
+  m_ChildControlHeight: 0
+  m_ChildScaleWidth: 0
+  m_ChildScaleHeight: 0
+  m_ReverseArrangement: 0
+--- !u!222 &832898112561691027
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_CullTransparentMesh: 1
+--- !u!114 &832898112561691028
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 0.4339623, g: 0.4339623, b: 0.4339623, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &832898112561691025
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: cfabb0440166ab443bba8876756fdfa9, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_EffectColor: {r: 1, g: 0.95706415, b: 0.0047169924, a: 0.5}
+  m_EffectDistance: {x: 1, y: -1}
+  m_UseGraphicAlpha: 1
+--- !u!225 &9185976299326908605
+CanvasGroup:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898112561691030}
+  m_Enabled: 1
+  m_Alpha: 1
+  m_Interactable: 1
+  m_BlocksRaycasts: 1
+  m_IgnoreParentGroups: 0
+--- !u!1 &832898113075269756
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 832898113075269755}
+  - component: {fileID: 832898113075269753}
+  - component: {fileID: 832898113075269754}
+  m_Layer: 5
+  m_Name: Score
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &832898113075269755
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113075269756}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 832898112561691029}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 177.47, y: 30}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &832898113075269753
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113075269756}
+  m_CullTransparentMesh: 1
+--- !u!114 &832898113075269754
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113075269756}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 14
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 10
+    m_MaxSize: 40
+    m_Alignment: 3
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: New Text
+--- !u!1 &832898113181171499
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 832898113181171498}
+  - component: {fileID: 832898113181171496}
+  - component: {fileID: 832898113181171497}
+  m_Layer: 5
+  m_Name: Avatar
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &832898113181171498
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113181171499}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 832898112561691029}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 40, y: 40}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &832898113181171496
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113181171499}
+  m_CullTransparentMesh: 1
+--- !u!114 &832898113181171497
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 832898113181171499}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1

+ 7 - 0
Assets/RankDemo/Prefabs/item.prefab.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: ad6559b205f14b94bba51baf5d7cf522
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 698 - 0
Assets/RankDemo/RankUIScene.unity

@@ -0,0 +1,698 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 0}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 12
+  m_GIWorkflowMode: 1
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 0
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    m_PVRDirectSampleCount: 32
+    m_PVRSampleCount: 512
+    m_PVRBounces: 2
+    m_PVREnvironmentSampleCount: 256
+    m_PVREnvironmentReferencePointCount: 2048
+    m_PVRFilteringMode: 1
+    m_PVRDenoiserTypeDirect: 1
+    m_PVRDenoiserTypeIndirect: 1
+    m_PVRDenoiserTypeAO: 1
+    m_PVRFilterTypeDirect: 0
+    m_PVRFilterTypeIndirect: 0
+    m_PVRFilterTypeAO: 0
+    m_PVREnvironmentMIS: 1
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_LightingSettings: {fileID: 0}
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    maxJobWorkers: 0
+    preserveTilesOutsideBounds: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &274814416
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 274814419}
+  - component: {fileID: 274814418}
+  - component: {fileID: 274814417}
+  m_Layer: 0
+  m_Name: Main Camera
+  m_TagString: MainCamera
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!81 &274814417
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 274814416}
+  m_Enabled: 1
+--- !u!20 &274814418
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 274814416}
+  m_Enabled: 1
+  serializedVersion: 2
+  m_ClearFlags: 2
+  m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0}
+  m_projectionMatrixMode: 1
+  m_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  m_FocalLength: 50
+  m_NormalizedViewPortRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+  near clip plane: 0.01
+  far clip plane: 1000
+  field of view: 60
+  orthographic: 0
+  orthographic size: 5
+  m_Depth: -1
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingPath: -1
+  m_TargetTexture: {fileID: 0}
+  m_TargetDisplay: 0
+  m_TargetEye: 3
+  m_HDR: 1
+  m_AllowMSAA: 1
+  m_AllowDynamicResolution: 0
+  m_ForceIntoRT: 0
+  m_OcclusionCulling: 1
+  m_StereoConvergence: 10
+  m_StereoSeparation: 0.022
+--- !u!4 &274814419
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 274814416}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 1377349644}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &384536615
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 384536616}
+  m_Layer: 0
+  m_Name: SmartBowDemoUI
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &384536616
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 384536615}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 1377349644}
+  - {fileID: 1690510351}
+  - {fileID: 1252904044}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &446118639
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 446118642}
+  - component: {fileID: 446118641}
+  - component: {fileID: 446118640}
+  m_Layer: 0
+  m_Name: "\u8FD0\u884C\u65F6\u63A7\u5236\u53F0\uFF08\u5728\u5C4F\u5E55\u753B\u4E2A\u5708\u5373\u53EF\u6253\u5F00\uFF09"
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &446118640
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 446118639}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 6767a180de870304caa2013b2772dd62, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+--- !u!114 &446118641
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 446118639}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 600c02144c4813244abd262cbcbe8825, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  show: 0
+  UserData: 
+  fps: 0
+  fpsText: 
+  images:
+    clearImage: {fileID: 2800000, guid: 112c6fcf56e349449ab2e6ad76b67816, type: 3}
+    collapseImage: {fileID: 2800000, guid: 4623f326a884a2546ab39078bf7822c3, type: 3}
+    clearOnNewSceneImage: {fileID: 2800000, guid: 3a6bc61a8319b1949ab9f1f2db1302b4, type: 3}
+    showTimeImage: {fileID: 2800000, guid: 782e03669fa4a614e89ef56252134250, type: 3}
+    showSceneImage: {fileID: 2800000, guid: ff4dfb29f203a174ab8e4c498afe908a, type: 3}
+    userImage: {fileID: 2800000, guid: 2bcdc012e7356f1449ce7d3a31dc458c, type: 3}
+    showMemoryImage: {fileID: 2800000, guid: f447d62f2dacf9843be7cbf168a3a9d0, type: 3}
+    softwareImage: {fileID: 2800000, guid: 6c91fc88ee6c791468318d85febfb48d, type: 3}
+    dateImage: {fileID: 2800000, guid: a7561cd0a9f62a84e99bff1abce2a222, type: 3}
+    showFpsImage: {fileID: 2800000, guid: 90b2f48155dc0e74f8e428561ac79da5, type: 3}
+    infoImage: {fileID: 2800000, guid: 2954bef266e6d794aba08ceacc887a0f, type: 3}
+    saveLogsImage: {fileID: 2800000, guid: 4a4821d80a1fc774fb76eac6213544e7, type: 3}
+    searchImage: {fileID: 2800000, guid: bfef37b5a26d2264798616d960451329, type: 3}
+    copyImage: {fileID: 2800000, guid: 7f36d71624c630046b855909c497be17, type: 3}
+    copyAllImage: {fileID: 2800000, guid: 10189803ef22ba546b7f511c1b908fe5, type: 3}
+    closeImage: {fileID: 2800000, guid: b65e9be99974bc94eab5d6698811d0b8, type: 3}
+    buildFromImage: {fileID: 2800000, guid: 8702be598dd9f504ca33be2afee2ca33, type: 3}
+    systemInfoImage: {fileID: 2800000, guid: e9011b1dc9256ad4d9c19a31c595f95f, type: 3}
+    graphicsInfoImage: {fileID: 2800000, guid: 999d31716332cc04eb4abc9c9270b0ca, type: 3}
+    backImage: {fileID: 2800000, guid: a0632a18e7c665641b94fea66506ab50, type: 3}
+    logImage: {fileID: 2800000, guid: e876b803a4dd5c5488078071d15aa9c0, type: 3}
+    warningImage: {fileID: 2800000, guid: 1066be8e7b994b94c8a182b8dbe30705, type: 3}
+    errorImage: {fileID: 2800000, guid: 7640ebf8b3a92124d821d3b4b8b3fd7e, type: 3}
+    barImage: {fileID: 2800000, guid: 8128d4f4c0193e34586f9631ef7d4787, type: 3}
+    button_activeImage: {fileID: 2800000, guid: 2580a2e903691e44282e56ed6e0ff37a, type: 3}
+    even_logImage: {fileID: 2800000, guid: d27aad55b568c6544b0b95a95da44bc7, type: 3}
+    odd_logImage: {fileID: 2800000, guid: 8ffbb44a2c3adae45913474e4fd487f5, type: 3}
+    selectedImage: {fileID: 2800000, guid: 17117a429b08e7e43b0b6c8421de69fe, type: 3}
+    reporterScrollerSkin: {fileID: 11400000, guid: 1cc68832d00d3284a9324a4dc05be753, type: 2}
+  size: {x: 32, y: 32}
+  maxSize: 20
+  numOfCircleToShow: 1
+  Initialized: 0
+--- !u!4 &446118642
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 446118639}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1252904041
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1252904044}
+  - component: {fileID: 1252904043}
+  - component: {fileID: 1252904042}
+  m_Layer: 0
+  m_Name: EventSystem
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 0
+--- !u!114 &1252904042
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1252904041}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_SendPointerHoverToParent: 1
+  m_HorizontalAxis: Horizontal
+  m_VerticalAxis: Vertical
+  m_SubmitButton: Submit
+  m_CancelButton: Cancel
+  m_InputActionsPerSecond: 10
+  m_RepeatDelay: 0.5
+  m_ForceModuleActive: 0
+--- !u!114 &1252904043
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1252904041}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_FirstSelected: {fileID: 0}
+  m_sendNavigationEvents: 1
+  m_DragThreshold: 10
+--- !u!4 &1252904044
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1252904041}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 384536616}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1377349643
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1377349644}
+  m_Layer: 0
+  m_Name: GameScene
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &1377349644
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1377349643}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 1959500036}
+  - {fileID: 274814419}
+  m_Father: {fileID: 384536616}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!224 &1690510351 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+  m_PrefabInstance: {fileID: 8582933151553536290}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1 &1959500034
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1959500036}
+  - component: {fileID: 1959500035}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &1959500035
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1959500034}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+  m_Intensity: 1
+  m_Range: 10
+  m_SpotAngle: 30
+  m_InnerSpotAngle: 21.80208
+  m_CookieSize: 10
+  m_Shadows:
+    m_Type: 2
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    m_Bias: 0.05
+    m_NormalBias: 0.4
+    m_NearPlane: 0.2
+    m_CullingMatrixOverride:
+      e00: 1
+      e01: 0
+      e02: 0
+      e03: 0
+      e10: 0
+      e11: 1
+      e12: 0
+      e13: 0
+      e20: 0
+      e21: 0
+      e22: 1
+      e23: 0
+      e30: 0
+      e31: 0
+      e32: 0
+      e33: 1
+    m_UseCullingMatrixOverride: 0
+  m_Cookie: {fileID: 0}
+  m_DrawHalo: 0
+  m_Flare: {fileID: 0}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 4
+  m_LightShadowCasterMode: 0
+  m_AreaSize: {x: 1, y: 1}
+  m_BounceIntensity: 1
+  m_ColorTemperature: 6570
+  m_UseColorTemperature: 0
+  m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+  m_UseBoundingSphereOverride: 0
+  m_UseViewFrustumForShadowCasterCull: 1
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &1959500036
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1959500034}
+  m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+  m_LocalPosition: {x: 0, y: 3, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 1377349644}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!1001 &8582933151553536290
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 384536616}
+    m_Modifications:
+    - target: {fileID: 8582933151342045850, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933151342045850, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933151342045850, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933151342045850, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933151457695969, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933151457695969, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933151457695969, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933151457695969, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933151718510481, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933151718510481, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933151718510481, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933151718510481, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933152968673542, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933152968673542, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933152968673542, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933152968673542, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309225, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_Name
+      value: CanvasUI
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_RootOrder
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 8582933153101309229, guid: e2564163341a2554d8159cfb558fec94, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: e2564163341a2554d8159cfb558fec94, type: 3}

+ 7 - 0
Assets/RankDemo/RankUIScene.unity.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 7173b18860282b74dbb46f8bb78cc41c
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Resources.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 253627ea04e52954881b1f59b345ebb5
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Resources/SmartBow.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f21d618fb008a8948a2f4cbdff7a5410
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Resources/SmartBow/Prefabs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 45243d6709c725c4c98e9b68546c77e4
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Resources/SmartBow/Prefabs/Views.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 6f8f72be161cab34fb6306d18b9a18ac
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1943 - 0
Assets/RankDemo/Resources/SmartBow/Prefabs/Views/GameRankView.prefab

@@ -0,0 +1,1943 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &166466195468712490
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5918385189898779557}
+  - component: {fileID: 6786890353898456468}
+  - component: {fileID: 4708992531964230687}
+  - component: {fileID: 1804611349558052203}
+  m_Layer: 5
+  m_Name: Score
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &5918385189898779557
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 166466195468712490}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 1285710280589416306}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: 378, y: -28}
+  m_SizeDelta: {x: 276, y: 28}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &6786890353898456468
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 166466195468712490}
+  m_CullTransparentMesh: 1
+--- !u!114 &4708992531964230687
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 166466195468712490}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 24
+    m_FontStyle: 1
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 40
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 1
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: "\u5206\u6570"
+--- !u!114 &1804611349558052203
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 166466195468712490}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0f4efe98aab6c6b41a7ee1f4c49df27b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  textKey: Rank_Score
+  layoutRebuildObject: {fileID: 0}
+  languageFontSizes: []
+--- !u!1 &558028252054463097
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1285710280589416306}
+  - component: {fileID: 6758032184908672733}
+  - component: {fileID: 1805802022692243149}
+  - component: {fileID: 6660133634176868524}
+  m_Layer: 5
+  m_Name: RankTitle
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &1285710280589416306
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 558028252054463097}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 2919214174691129240}
+  - {fileID: 5918385189898779557}
+  m_Father: {fileID: 8582933152727474795}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 56}
+  m_Pivot: {x: 0.5, y: 1}
+--- !u!114 &6758032184908672733
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 558028252054463097}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 130
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 3
+  m_Spacing: 10
+  m_ChildForceExpandWidth: 0
+  m_ChildForceExpandHeight: 1
+  m_ChildControlWidth: 0
+  m_ChildControlHeight: 0
+  m_ChildScaleWidth: 0
+  m_ChildScaleHeight: 0
+  m_ReverseArrangement: 0
+--- !u!222 &1805802022692243149
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 558028252054463097}
+  m_CullTransparentMesh: 1
+--- !u!114 &6660133634176868524
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 558028252054463097}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 0.07058824, g: 0.19607843, b: 0.29411766, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!1 &6759586844101234343
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2919214174691129240}
+  - component: {fileID: 7735084627922651718}
+  - component: {fileID: 1393347800307797172}
+  - component: {fileID: 7416333900509645250}
+  m_Layer: 5
+  m_Name: text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &2919214174691129240
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6759586844101234343}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 1285710280589416306}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: 180, y: -28}
+  m_SizeDelta: {x: 100, y: 60}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &7735084627922651718
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6759586844101234343}
+  m_CullTransparentMesh: 1
+--- !u!114 &1393347800307797172
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6759586844101234343}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 28
+    m_FontStyle: 1
+    m_BestFit: 0
+    m_MinSize: 0
+    m_MaxSize: 40
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 1
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: "\u6392\u540D"
+--- !u!114 &7416333900509645250
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6759586844101234343}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0f4efe98aab6c6b41a7ee1f4c49df27b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  textKey: Rank_Number
+  layoutRebuildObject: {fileID: 0}
+  languageFontSizes: []
+--- !u!1 &8582933151329797276
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933151329797277}
+  m_Layer: 5
+  m_Name: ViewportParent
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933151329797277
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151329797276}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 8582933152159014744}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: -0.0000038146973}
+  m_Pivot: {x: 0, y: 1}
+--- !u!1 &8582933151342045845
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933151342045850}
+  - component: {fileID: 8582933151342045849}
+  - component: {fileID: 8582933151342045848}
+  - component: {fileID: 8582933151342045851}
+  m_Layer: 5
+  m_Name: UploadSelfBtn
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933151342045850
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151342045845}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 8582933152153721052}
+  m_Father: {fileID: 8582933152963006991}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: 163.28564, y: -289.95563}
+  m_SizeDelta: {x: 320, y: 60}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8582933151342045849
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151342045845}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933151342045848
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151342045845}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+  m_Type: 1
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &8582933151342045851
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151342045845}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Navigation:
+    m_Mode: 3
+    m_WrapAround: 0
+    m_SelectOnUp: {fileID: 0}
+    m_SelectOnDown: {fileID: 0}
+    m_SelectOnLeft: {fileID: 0}
+    m_SelectOnRight: {fileID: 0}
+  m_Transition: 1
+  m_Colors:
+    m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+    m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+    m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+    m_ColorMultiplier: 1
+    m_FadeDuration: 0.1
+  m_SpriteState:
+    m_HighlightedSprite: {fileID: 0}
+    m_PressedSprite: {fileID: 0}
+    m_SelectedSprite: {fileID: 0}
+    m_DisabledSprite: {fileID: 0}
+  m_AnimationTriggers:
+    m_NormalTrigger: Normal
+    m_HighlightedTrigger: Highlighted
+    m_PressedTrigger: Pressed
+    m_SelectedTrigger: Selected
+    m_DisabledTrigger: Disabled
+  m_Interactable: 1
+  m_TargetGraphic: {fileID: 8582933151342045848}
+  m_OnClick:
+    m_PersistentCalls:
+      m_Calls:
+      - m_Target: {fileID: 7385291475288086742}
+        m_TargetAssemblyTypeName: LocalRank.RankManager, Assembly-CSharp
+        m_MethodName: UploadTestRandomScoreToUserId
+        m_Mode: 1
+        m_Arguments:
+          m_ObjectArgument: {fileID: 0}
+          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+          m_IntArgument: 0
+          m_FloatArgument: 0
+          m_StringArgument: 
+          m_BoolArgument: 0
+        m_CallState: 2
+--- !u!1 &8582933151457695968
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933151457695969}
+  - component: {fileID: 8582933151457695972}
+  - component: {fileID: 8582933151457695975}
+  - component: {fileID: 8582933151457695974}
+  m_Layer: 5
+  m_Name: InputField (Legacy)
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933151457695969
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151457695968}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 8582933153119767865}
+  - {fileID: 8582933151886782672}
+  m_Father: {fileID: 8582933152963006991}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: 163.28564, y: -159.97781}
+  m_SizeDelta: {x: 320, y: 60}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8582933151457695972
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151457695968}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933151457695975
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151457695968}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0}
+  m_Type: 1
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &8582933151457695974
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151457695968}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Navigation:
+    m_Mode: 3
+    m_WrapAround: 0
+    m_SelectOnUp: {fileID: 0}
+    m_SelectOnDown: {fileID: 0}
+    m_SelectOnLeft: {fileID: 0}
+    m_SelectOnRight: {fileID: 0}
+  m_Transition: 1
+  m_Colors:
+    m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+    m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+    m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+    m_ColorMultiplier: 1
+    m_FadeDuration: 0.1
+  m_SpriteState:
+    m_HighlightedSprite: {fileID: 0}
+    m_PressedSprite: {fileID: 0}
+    m_SelectedSprite: {fileID: 0}
+    m_DisabledSprite: {fileID: 0}
+  m_AnimationTriggers:
+    m_NormalTrigger: Normal
+    m_HighlightedTrigger: Highlighted
+    m_PressedTrigger: Pressed
+    m_SelectedTrigger: Selected
+    m_DisabledTrigger: Disabled
+  m_Interactable: 1
+  m_TargetGraphic: {fileID: 8582933151457695975}
+  m_TextComponent: {fileID: 8582933151886782673}
+  m_Placeholder: {fileID: 8582933153119767870}
+  m_ContentType: 2
+  m_InputType: 0
+  m_AsteriskChar: 42
+  m_KeyboardType: 4
+  m_LineType: 0
+  m_HideMobileInput: 0
+  m_CharacterValidation: 1
+  m_CharacterLimit: 0
+  m_OnSubmit:
+    m_PersistentCalls:
+      m_Calls: []
+  m_OnDidEndEdit:
+    m_PersistentCalls:
+      m_Calls: []
+  m_OnValueChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+  m_CustomCaretColor: 0
+  m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412}
+  m_Text: 
+  m_CaretBlinkRate: 0.85
+  m_CaretWidth: 1
+  m_ReadOnly: 0
+  m_ShouldActivateOnSelect: 1
+--- !u!1 &8582933151718510480
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933151718510481}
+  - component: {fileID: 8582933151718510484}
+  - component: {fileID: 8582933151718510487}
+  - component: {fileID: 8582933151718510486}
+  m_Layer: 5
+  m_Name: UploadMultiBtn
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 0
+--- !u!224 &8582933151718510481
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151718510480}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 8582933152665661228}
+  m_Father: {fileID: 8582933152963006991}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: 163.28564, y: -127.48335}
+  m_SizeDelta: {x: 320, y: 60}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8582933151718510484
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151718510480}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933151718510487
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151718510480}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+  m_Type: 1
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &8582933151718510486
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151718510480}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Navigation:
+    m_Mode: 3
+    m_WrapAround: 0
+    m_SelectOnUp: {fileID: 0}
+    m_SelectOnDown: {fileID: 0}
+    m_SelectOnLeft: {fileID: 0}
+    m_SelectOnRight: {fileID: 0}
+  m_Transition: 1
+  m_Colors:
+    m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+    m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+    m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+    m_ColorMultiplier: 1
+    m_FadeDuration: 0.1
+  m_SpriteState:
+    m_HighlightedSprite: {fileID: 0}
+    m_PressedSprite: {fileID: 0}
+    m_SelectedSprite: {fileID: 0}
+    m_DisabledSprite: {fileID: 0}
+  m_AnimationTriggers:
+    m_NormalTrigger: Normal
+    m_HighlightedTrigger: Highlighted
+    m_PressedTrigger: Pressed
+    m_SelectedTrigger: Selected
+    m_DisabledTrigger: Disabled
+  m_Interactable: 1
+  m_TargetGraphic: {fileID: 8582933151718510487}
+  m_OnClick:
+    m_PersistentCalls:
+      m_Calls:
+      - m_Target: {fileID: 7385291475288086742}
+        m_TargetAssemblyTypeName: LocalRank.RankManager, Assembly-CSharp
+        m_MethodName: TestData
+        m_Mode: 1
+        m_Arguments:
+          m_ObjectArgument: {fileID: 0}
+          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+          m_IntArgument: 6
+          m_FloatArgument: 0
+          m_StringArgument: 
+          m_BoolArgument: 0
+        m_CallState: 2
+--- !u!1 &8582933151886782675
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933151886782672}
+  - component: {fileID: 8582933151886782678}
+  - component: {fileID: 8582933151886782673}
+  m_Layer: 5
+  m_Name: Text (Legacy)
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933151886782672
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151886782675}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 8582933151457695969}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: -0.5}
+  m_SizeDelta: {x: -20, y: -13}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8582933151886782678
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151886782675}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933151886782673
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933151886782675}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 28
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 40
+    m_Alignment: 0
+    m_AlignByGeometry: 0
+    m_RichText: 0
+    m_HorizontalOverflow: 1
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: 
+--- !u!1 &8582933152153721055
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933152153721052}
+  - component: {fileID: 8582933152153721634}
+  - component: {fileID: 8582933152153721053}
+  m_Layer: 5
+  m_Name: Text (Legacy)
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933152153721052
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152153721055}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 8582933151342045850}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8582933152153721634
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152153721055}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933152153721053
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152153721055}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 30
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 3
+    m_MaxSize: 40
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: "\u5F53\u524DId\u7684\u968F\u673A\u5206\u6570"
+--- !u!1 &8582933152159014747
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933152159014744}
+  - component: {fileID: 8582933152159014751}
+  - component: {fileID: 8582933152159014750}
+  - component: {fileID: 8582933152159014745}
+  - component: {fileID: 4957514643731832028}
+  m_Layer: 5
+  m_Name: Scroll View
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933152159014744
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152159014747}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1.5, y: 1.5, z: 1.5}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 8582933152727474795}
+  - {fileID: 8582933151329797277}
+  - {fileID: 8582933152963006991}
+  m_Father: {fileID: 8582933152756725551}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 530, y: 760}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8582933152159014751
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152159014747}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933152159014750
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152159014747}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 0.07058824, g: 0.19607843, b: 0.29411766, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 1
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &8582933152159014745
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152159014747}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Content: {fileID: 8582933153078014794}
+  m_Horizontal: 0
+  m_Vertical: 1
+  m_MovementType: 1
+  m_Elasticity: 0.1
+  m_Inertia: 1
+  m_DecelerationRate: 0.135
+  m_ScrollSensitivity: 1
+  m_Viewport: {fileID: 8582933152727474795}
+  m_HorizontalScrollbar: {fileID: 0}
+  m_VerticalScrollbar: {fileID: 0}
+  m_HorizontalScrollbarVisibility: 2
+  m_VerticalScrollbarVisibility: 2
+  m_HorizontalScrollbarSpacing: -3
+  m_VerticalScrollbarSpacing: -3
+  m_OnValueChanged:
+    m_PersistentCalls:
+      m_Calls: []
+--- !u!114 &4957514643731832028
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152159014747}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_EffectColor: {r: 0, g: 0, b: 0, a: 0.5}
+  m_EffectDistance: {x: 3, y: 3}
+  m_UseGraphicAlpha: 1
+--- !u!1 &8582933152665661231
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933152665661228}
+  - component: {fileID: 8582933152665661234}
+  - component: {fileID: 8582933152665661229}
+  m_Layer: 5
+  m_Name: Text (Legacy)
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933152665661228
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152665661231}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 8582933151718510481}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8582933152665661234
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152665661231}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933152665661229
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152665661231}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 30
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 3
+    m_MaxSize: 40
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: "\u4E0A\u4F20\u591A\u6761\u6570\u636E"
+--- !u!1 &8582933152727474794
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933152727474795}
+  - component: {fileID: 8582933152727474798}
+  - component: {fileID: 8582933152727474793}
+  - component: {fileID: 8582933152727474792}
+  m_Layer: 5
+  m_Name: Viewport
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933152727474795
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152727474794}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 8582933153078014794}
+  - {fileID: 1285710280589416306}
+  m_Father: {fileID: 8582933152159014744}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0, y: 1}
+--- !u!222 &8582933152727474798
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152727474794}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933152727474793
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152727474794}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0}
+  m_Type: 1
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &8582933152727474792
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152727474794}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_ShowMaskGraphic: 0
+--- !u!1 &8582933152756725550
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933152756725551}
+  - component: {fileID: 8582933152756725549}
+  - component: {fileID: 8582933152756725548}
+  - component: {fileID: 1984446254774750218}
+  m_Layer: 5
+  m_Name: Panel
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 0
+--- !u!224 &8582933152756725551
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152756725550}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 8582933152159014744}
+  m_Father: {fileID: 8582933153101309229}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8582933152756725549
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152756725550}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933152756725548
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152756725550}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 0.2264151, g: 0.2264151, b: 0.2264151, a: 0.78431374}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 1
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &1984446254774750218
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152756725550}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Navigation:
+    m_Mode: 3
+    m_WrapAround: 0
+    m_SelectOnUp: {fileID: 0}
+    m_SelectOnDown: {fileID: 0}
+    m_SelectOnLeft: {fileID: 0}
+    m_SelectOnRight: {fileID: 0}
+  m_Transition: 0
+  m_Colors:
+    m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+    m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+    m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+    m_ColorMultiplier: 1
+    m_FadeDuration: 0.1
+  m_SpriteState:
+    m_HighlightedSprite: {fileID: 0}
+    m_PressedSprite: {fileID: 0}
+    m_SelectedSprite: {fileID: 0}
+    m_DisabledSprite: {fileID: 0}
+  m_AnimationTriggers:
+    m_NormalTrigger: Normal
+    m_HighlightedTrigger: Highlighted
+    m_PressedTrigger: Pressed
+    m_SelectedTrigger: Selected
+    m_DisabledTrigger: Disabled
+  m_Interactable: 1
+  m_TargetGraphic: {fileID: 8582933152756725548}
+  m_OnClick:
+    m_PersistentCalls:
+      m_Calls:
+      - m_Target: {fileID: 7385291475288086742}
+        m_TargetAssemblyTypeName: LocalRank.RankManager, Assembly-CSharp
+        m_MethodName: OnClick_Back
+        m_Mode: 1
+        m_Arguments:
+          m_ObjectArgument: {fileID: 0}
+          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+          m_IntArgument: 0
+          m_FloatArgument: 0
+          m_StringArgument: 
+          m_BoolArgument: 0
+        m_CallState: 2
+--- !u!1 &8582933152773891445
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933152773891450}
+  - component: {fileID: 8582933152773891448}
+  - component: {fileID: 8582933152773891451}
+  m_Layer: 5
+  m_Name: Text (Legacy)
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933152773891450
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152773891445}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 8582933152968673542}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8582933152773891448
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152773891445}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933152773891451
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152773891445}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 30
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 3
+    m_MaxSize: 40
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: "\u65B0\u7528\u6237Id\u5206\u6570"
+--- !u!1 &8582933152963006990
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933152963006991}
+  - component: {fileID: 8582933152963006988}
+  m_Layer: 5
+  m_Name: GameObject
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 0
+--- !u!224 &8582933152963006991
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152963006990}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 8582933152968673542}
+  - {fileID: 8582933151718510481}
+  - {fileID: 8582933151457695969}
+  - {fileID: 8582933151342045850}
+  m_Father: {fileID: 8582933152159014744}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 544, y: 25.5333}
+  m_SizeDelta: {x: 326.5713, y: 384.9334}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &8582933152963006988
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152963006990}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 0
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 1
+  m_Spacing: 5
+  m_ChildForceExpandWidth: 1
+  m_ChildForceExpandHeight: 1
+  m_ChildControlWidth: 0
+  m_ChildControlHeight: 0
+  m_ChildScaleWidth: 0
+  m_ChildScaleHeight: 0
+  m_ReverseArrangement: 0
+--- !u!1 &8582933152968673537
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933152968673542}
+  - component: {fileID: 8582933152968673541}
+  - component: {fileID: 8582933152968673540}
+  - component: {fileID: 8582933152968673543}
+  m_Layer: 5
+  m_Name: UploadNewSelfBtn
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933152968673542
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152968673537}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 8582933152773891450}
+  m_Father: {fileID: 8582933152963006991}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 0, y: 1}
+  m_AnchoredPosition: {x: 163.28564, y: -30}
+  m_SizeDelta: {x: 320, y: 60}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8582933152968673541
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152968673537}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933152968673540
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152968673537}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+  m_Type: 1
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &8582933152968673543
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933152968673537}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Navigation:
+    m_Mode: 3
+    m_WrapAround: 0
+    m_SelectOnUp: {fileID: 0}
+    m_SelectOnDown: {fileID: 0}
+    m_SelectOnLeft: {fileID: 0}
+    m_SelectOnRight: {fileID: 0}
+  m_Transition: 1
+  m_Colors:
+    m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+    m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+    m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+    m_ColorMultiplier: 1
+    m_FadeDuration: 0.1
+  m_SpriteState:
+    m_HighlightedSprite: {fileID: 0}
+    m_PressedSprite: {fileID: 0}
+    m_SelectedSprite: {fileID: 0}
+    m_DisabledSprite: {fileID: 0}
+  m_AnimationTriggers:
+    m_NormalTrigger: Normal
+    m_HighlightedTrigger: Highlighted
+    m_PressedTrigger: Pressed
+    m_SelectedTrigger: Selected
+    m_DisabledTrigger: Disabled
+  m_Interactable: 1
+  m_TargetGraphic: {fileID: 8582933152968673540}
+  m_OnClick:
+    m_PersistentCalls:
+      m_Calls:
+      - m_Target: {fileID: 7385291475288086742}
+        m_TargetAssemblyTypeName: LocalRank.RankManager, Assembly-CSharp
+        m_MethodName: UploadTestRandomScoreToNewId
+        m_Mode: 1
+        m_Arguments:
+          m_ObjectArgument: {fileID: 0}
+          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+          m_IntArgument: 0
+          m_FloatArgument: 0
+          m_StringArgument: 
+          m_BoolArgument: 0
+        m_CallState: 2
+--- !u!1 &8582933153078014789
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933153078014794}
+  - component: {fileID: 8582933153078014795}
+  m_Layer: 5
+  m_Name: Content
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933153078014794
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933153078014789}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 8582933152727474795}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 760}
+  m_Pivot: {x: 0, y: 1}
+--- !u!114 &8582933153078014795
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933153078014789}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 0
+    m_Right: 0
+    m_Top: 58
+    m_Bottom: 0
+  m_ChildAlignment: 1
+  m_Spacing: 0
+  m_ChildForceExpandWidth: 1
+  m_ChildForceExpandHeight: 0
+  m_ChildControlWidth: 0
+  m_ChildControlHeight: 0
+  m_ChildScaleWidth: 0
+  m_ChildScaleHeight: 0
+  m_ReverseArrangement: 0
+--- !u!1 &8582933153101309225
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933153101309229}
+  - component: {fileID: 8582933153101309228}
+  - component: {fileID: 8582933153101309231}
+  - component: {fileID: 8582933153101309230}
+  - component: {fileID: 6892107432493493544}
+  - component: {fileID: 7385291475288086742}
+  m_Layer: 5
+  m_Name: GameRankView
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933153101309229
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933153101309225}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 0, y: 0, z: 0}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 8582933152756725551}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0, y: 0}
+--- !u!223 &8582933153101309228
+Canvas:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933153101309225}
+  m_Enabled: 1
+  serializedVersion: 3
+  m_RenderMode: 0
+  m_Camera: {fileID: 0}
+  m_PlaneDistance: 100
+  m_PixelPerfect: 0
+  m_ReceivesEvents: 1
+  m_OverrideSorting: 0
+  m_OverridePixelPerfect: 0
+  m_SortingBucketNormalizedSize: 0
+  m_VertexColorAlwaysGammaSpace: 0
+  m_AdditionalShaderChannelsFlag: 25
+  m_SortingLayerID: 0
+  m_SortingOrder: 1002
+  m_TargetDisplay: 0
+--- !u!114 &8582933153101309231
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933153101309225}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_UiScaleMode: 1
+  m_ReferencePixelsPerUnit: 100
+  m_ScaleFactor: 1
+  m_ReferenceResolution: {x: 2352, y: 1170}
+  m_ScreenMatchMode: 0
+  m_MatchWidthOrHeight: 1
+  m_PhysicalUnit: 3
+  m_FallbackScreenDPI: 96
+  m_DefaultSpriteDPI: 96
+  m_DynamicPixelsPerUnit: 1
+  m_PresetInfoIsWorld: 0
+--- !u!114 &8582933153101309230
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933153101309225}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreReversedGraphics: 1
+  m_BlockingObjects: 0
+  m_BlockingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+--- !u!114 &6892107432493493544
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933153101309225}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 63bc5ec02b5696847aaeca582ea6894a, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  scrollRect: {fileID: 8582933152159014745}
+  content: {fileID: 8582933153078014794}
+  viewport: {fileID: 8582933152727474795}
+  viewportParent: {fileID: 8582933151329797277}
+  targetItem: {fileID: 832898112561691029, guid: ad6559b205f14b94bba51baf5d7cf522, type: 3}
+  targetRankIndex: 0
+  scrollSpeed: 2000
+  scrollDuration: 1.5
+  scaleCurve:
+    serializedVersion: 2
+    m_Curve:
+    - serializedVersion: 3
+      time: 0
+      value: 1
+      inSlope: 0
+      outSlope: 0
+      tangentMode: 0
+      weightedMode: 0
+      inWeight: 0
+      outWeight: 0
+    - serializedVersion: 3
+      time: 0.9973999
+      value: 1.0012817
+      inSlope: 0.0012850796
+      outSlope: 0.15771048
+      tangentMode: 5
+      weightedMode: 0
+      inWeight: 0.33333334
+      outWeight: 0.33333334
+    - serializedVersion: 3
+      time: 1.5
+      value: 1.5
+      inSlope: 0
+      outSlope: 0
+      tangentMode: 0
+      weightedMode: 0
+      inWeight: 0
+      outWeight: 0
+    m_PreInfinity: 2
+    m_PostInfinity: 2
+    m_RotationOrder: 4
+  hangTime: 0.3
+  moveEase: 1
+  contentResetThreshold: 100
+  stopDelay: 0.5
+--- !u!114 &7385291475288086742
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933153101309225}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 3920a0111cbfc2041b34acfa68d1c9bd, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  Panel: {fileID: 8582933152756725551}
+  content: {fileID: 8582933153078014794}
+  itemPrefab: {fileID: 832898112561691030, guid: e0f300258cc55d1449fd16d4c283cc6a, type: 3}
+  inputField: {fileID: 8582933151457695974}
+--- !u!1 &8582933153119767864
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8582933153119767865}
+  - component: {fileID: 8582933153119767871}
+  - component: {fileID: 8582933153119767870}
+  m_Layer: 5
+  m_Name: Placeholder
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8582933153119767865
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933153119767864}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 8582933151457695969}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: -0.5}
+  m_SizeDelta: {x: -20, y: -13}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8582933153119767871
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933153119767864}
+  m_CullTransparentMesh: 1
+--- !u!114 &8582933153119767870
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8582933153119767864}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 28
+    m_FontStyle: 2
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 40
+    m_Alignment: 0
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: "\u8F93\u5165\u81EA\u5B9A\u4E49\u5206\u6570"

+ 7 - 0
Assets/RankDemo/Resources/SmartBow/Prefabs/Views/GameRankView.prefab.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: e2564163341a2554d8159cfb558fec94
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/SQLite4Unity3d.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 094a72d0135f6714d8794de509679447
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/SQLite4Unity3d/.DS_Store


+ 23 - 0
Assets/RankDemo/SQLite4Unity3d/RankEntry.cs

@@ -0,0 +1,23 @@
+using SQLite4Unity3d;
+using System;
+
+namespace LocalRank {
+    public class RankEntry
+    {
+        [PrimaryKey, AutoIncrement]
+        public int Id { get; set; }
+
+        public int UserId { get; set; }
+        public int GameType { get; set; }
+        public int Score { get; set; }
+        public string Nickname { get; set; }
+        public string Country { get; set; }
+        public string State { get; set; }
+        public string City { get; set; }
+
+        public DateTime CreateTime { get; set; }
+        public DateTime UpdateTime { get; set; }
+    }
+
+}
+

+ 11 - 0
Assets/RankDemo/SQLite4Unity3d/RankEntry.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 726556887f07f524c9811d277a35948a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 271 - 0
Assets/RankDemo/SQLite4Unity3d/RankService.cs

@@ -0,0 +1,271 @@
+using System;
+using Mono.Data.Sqlite;
+using UnityEngine;
+using System.Collections.Generic;
+using System.IO;
+
+namespace LocalRank
+{
+    public class RankService
+    {
+        private const string DatabaseName = "rank.db";
+        private static string DbFullPath;
+        static RankService()
+        {
+#if UNITY_EDITOR
+            DbFullPath = Path.Combine(Application.streamingAssetsPath, DatabaseName);
+#else
+            var filepath = Path.Combine(Application.persistentDataPath, DatabaseName);
+            if (!File.Exists(filepath))
+            {
+                Debug.Log("Database not in Persistent path, copying from StreamingAssets...");
+
+#if UNITY_ANDROID
+                var sourcePath = "jar:file://" + Application.dataPath + "!/assets/" + DatabaseName;
+                var www = new WWW(sourcePath);
+                while (!www.isDone) { }
+                File.WriteAllBytes(filepath, www.bytes);
+
+#elif UNITY_IOS
+                var sourcePath = Path.Combine(Application.dataPath + "/Raw", DatabaseName);
+                File.Copy(sourcePath, filepath);
+
+#elif UNITY_STANDALONE_OSX
+                var sourcePath = Path.Combine(Application.dataPath + "/Resources/Data/StreamingAssets", DatabaseName);
+                File.Copy(sourcePath, filepath);
+
+#else
+                var sourcePath = Path.Combine(Application.streamingAssetsPath, DatabaseName);
+                File.Copy(sourcePath, filepath);
+#endif
+
+                Debug.Log("Database copied to: " + filepath);
+            }
+
+            DbFullPath = filepath;
+#endif
+        }
+        //private static string DbPath => $"URI=file:{Application.persistentDataPath}/rank.db";
+        private static string DbPath => $"URI=file:{DbFullPath}";
+        // 检查表是否存在
+        public static bool IsTableExists(int gameId)
+        {
+            using var conn = new SqliteConnection(DbPath);
+            conn.Open();
+            using var cmd = conn.CreateCommand();
+            cmd.CommandText = $@"
+                SELECT COUNT(*) 
+                FROM sqlite_master 
+                WHERE type = 'table' AND name = 'rank_game_{gameId}';
+            ";
+            return Convert.ToInt32(cmd.ExecuteScalar()) > 0;
+        }
+
+        // 创建表格(如果表不存在)
+        public static void CreateTableIfNotExists(int gameId)
+        {
+            if (IsTableExists(gameId)) return; // 如果表已存在,直接返回
+
+            using var conn = new SqliteConnection(DbPath);
+            conn.Open();
+            using var cmd = conn.CreateCommand();
+            cmd.CommandText = $@"
+                CREATE TABLE IF NOT EXISTS rank_game_{gameId} (
+                    id INTEGER PRIMARY KEY AUTOINCREMENT,
+                    userId INTEGER NOT NULL,
+                    nickname TEXT,
+                    avatarUrl TEXT,
+                    score INTEGER,
+                    update_time DATETIME DEFAULT CURRENT_TIMESTAMP
+                );
+            ";
+            cmd.ExecuteNonQuery();
+        }
+
+        // 清空表格
+        public static void ClearTable(int gameId)
+        {
+            using var conn = new SqliteConnection(DbPath);
+            conn.Open();
+
+            // 检查表是否存在
+            using var checkCmd = conn.CreateCommand();
+            checkCmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='rank_game_{gameId}';";
+            var result = checkCmd.ExecuteScalar();
+
+            if (result != null)
+            {
+                using var cmd = conn.CreateCommand();
+                cmd.CommandText = $"DELETE FROM rank_game_{gameId};";
+                cmd.ExecuteNonQuery();
+            }
+            // 如果表不存在则跳过,无需操作
+        }
+        /// <summary>
+        /// 获取当前存在的全部id
+        /// </summary>
+        /// <returns></returns>
+        public static List<int> GetAllGameIds()
+        {
+            var gameIds = new List<int>();
+
+            using var conn = new SqliteConnection(DbPath);
+            conn.Open();
+
+            using var cmd = conn.CreateCommand();
+            cmd.CommandText = @"
+        SELECT name 
+        FROM sqlite_master 
+        WHERE type='table' AND name LIKE 'rank_game_%';
+    ";
+
+            using var reader = cmd.ExecuteReader();
+            while (reader.Read())
+            {
+                var tableName = reader.GetString(0); // 例如 "rank_game_5"
+                if (tableName.StartsWith("rank_game_"))
+                {
+                    var idPart = tableName.Substring("rank_game_".Length);
+                    if (int.TryParse(idPart, out int gameId))
+                    {
+                        gameIds.Add(gameId);
+                    }
+                }
+            }
+
+            return gameIds;
+        }
+
+
+        // 上传分数(如果是新用户,插入;如果是高分,更新)
+        public static void UploadScore(int gameId, int userId, string nickname, string avatarUrl, int score)
+        {
+            CreateTableIfNotExists(gameId);
+
+            using var conn = new SqliteConnection(DbPath);
+            conn.Open();
+
+            using var cmd = conn.CreateCommand();
+
+            // 查询旧分数
+            cmd.CommandText = $"SELECT score FROM rank_game_{gameId} WHERE userId = @userId;";
+            cmd.Parameters.AddWithValue("@userId", userId);
+            var reader = cmd.ExecuteReader();
+            int? oldScore = null;
+            if (reader.Read()) oldScore = reader.GetInt32(0);
+            reader.Close();
+
+            if (oldScore == null)
+            {
+                // 新用户插入
+                cmd.CommandText = $@"INSERT INTO rank_game_{gameId} (userId, nickname, avatarUrl, score) 
+                                 VALUES (@userId, @nickname, @avatarUrl, @score);";
+            }
+            else if (score > oldScore)
+            {
+                // 更新高分
+                cmd.CommandText = $@"UPDATE rank_game_{gameId} 
+                                 SET score = @score, update_time = CURRENT_TIMESTAMP 
+                                 WHERE userId = @userId;";
+            }
+            else
+            {
+                return; // 分数没提升
+            }
+
+            cmd.Parameters.AddWithValue("@nickname", nickname);
+            cmd.Parameters.AddWithValue("@avatarUrl", avatarUrl);
+            cmd.Parameters.AddWithValue("@score", score);
+            cmd.ExecuteNonQuery();
+        }
+
+
+        public class RankEntry
+        {
+            public string Nickname;
+            public string AvatarUrl;
+            public int Score;
+            public int Rank;
+            public bool IsSelf;
+        }
+
+        public static (List<RankEntry> resultList, int userRank, int totalCount) GetRankList(int gameId, int userId)
+        {
+            var result = new List<RankEntry>();
+
+            using var conn = new SqliteConnection(DbPath);
+            conn.Open();
+
+            using var cmd = conn.CreateCommand();
+            cmd.CommandText = $"SELECT userId, nickname, avatarUrl, score, update_time FROM rank_game_{gameId} ORDER BY score DESC, update_time DESC;";
+            using var reader = cmd.ExecuteReader();
+
+            var allRanks = new List<RankEntry>();
+            int currentRank = 1;
+            int userIndex = -1;
+
+            while (reader.Read())
+            {
+                var entry = new RankEntry
+                {
+                    Nickname = reader.GetString(1),
+                    AvatarUrl = reader.GetString(2),
+                    Score = reader.GetInt32(3),
+                    Rank = currentRank++,
+                    IsSelf = reader.GetInt32(0) == userId
+                };
+
+                if (entry.IsSelf)
+                    userIndex = allRanks.Count;
+
+                allRanks.Add(entry);
+            }
+
+            reader.Close();
+
+            // 加入前三名
+            for (int i = 0; i < Math.Min(3, allRanks.Count); i++)
+            {
+                result.Add(allRanks[i]);
+            }
+
+            // 加入中间的自己 + 周围 7 条数据
+            if (userIndex == -1)
+            {
+                // 用户不存在
+                result.Add(new RankEntry
+                {
+                    Rank = -1,
+                    IsSelf = true,
+                    Nickname = "None",
+                    AvatarUrl = "",
+                    Score = 0
+                });
+            }
+            else
+            {
+                // 起始从第4条开始找
+                int centerStart = Math.Max(3, userIndex - 3);
+                int centerEnd = Math.Min(allRanks.Count, centerStart + 7);
+
+                for (int i = centerStart; i < centerEnd; i++)
+                {
+                    result.Add(allRanks[i]);
+                }
+            }
+
+            return (result, userIndex == -1 ? -1 : allRanks[userIndex].Rank, allRanks.Count);
+        }
+
+        /// <summary>
+        /// 用设备唯一标识(如 SystemInfo.deviceUniqueIdentifier)做基础,然后加时间戳或随机数避免重复
+        /// </summary>
+        /// <returns></returns>
+        public static int GenerateLocalUserId()
+        {
+            return Math.Abs($"{SystemInfo.deviceUniqueIdentifier}_{DateTime.UtcNow.Ticks}".GetHashCode());
+        }
+    }
+
+
+}

+ 11 - 0
Assets/RankDemo/SQLite4Unity3d/RankService.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c7f22d8f989168543beb9dcc3ee8423a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 3377 - 0
Assets/RankDemo/SQLite4Unity3d/SQLite.cs

@@ -0,0 +1,3377 @@
+//
+// Copyright (c) 2009-2012 Krueger Systems, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+#if WINDOWS_PHONE && !USE_WP8_NATIVE_SQLITE
+#define USE_CSHARP_SQLITE
+#endif
+
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Threading;
+
+#if USE_CSHARP_SQLITE
+using Sqlite3 = Community.CsharpSqlite.Sqlite3;
+using Sqlite3DatabaseHandle = Community.CsharpSqlite.Sqlite3.sqlite3;
+using Sqlite3Statement = Community.CsharpSqlite.Sqlite3.Vdbe;
+#elif USE_WP8_NATIVE_SQLITE
+using Sqlite3 = Sqlite.Sqlite3;
+using Sqlite3DatabaseHandle = Sqlite.Database;
+using Sqlite3Statement = Sqlite.Statement;
+#else
+using Sqlite3DatabaseHandle = System.IntPtr;
+using Sqlite3Statement = System.IntPtr;
+#endif
+
+namespace SQLite4Unity3d
+{
+	public class SQLiteException : Exception
+	{
+		public SQLite3.Result Result { get; private set; }
+
+		protected SQLiteException (SQLite3.Result r,string message) : base(message)
+		{
+			Result = r;
+		}
+
+		public static SQLiteException New (SQLite3.Result r, string message)
+		{
+			return new SQLiteException (r, message);
+		}
+	}
+
+	public class NotNullConstraintViolationException : SQLiteException
+	{
+		public IEnumerable<TableMapping.Column> Columns { get; protected set; }
+
+		protected NotNullConstraintViolationException (SQLite3.Result r, string message)
+			: this (r, message, null, null)
+		{
+
+		}
+
+		protected NotNullConstraintViolationException (SQLite3.Result r, string message, TableMapping mapping, object obj)
+			: base (r, message)
+		{
+			if (mapping != null && obj != null) {
+				this.Columns = from c in mapping.Columns
+							   where c.IsNullable == false && c.GetValue(obj) == null
+							   select c;
+			}
+		}
+
+		public static new NotNullConstraintViolationException New (SQLite3.Result r, string message)
+		{
+			return new NotNullConstraintViolationException (r, message);
+		}
+
+		public static NotNullConstraintViolationException New (SQLite3.Result r, string message, TableMapping mapping, object obj)
+		{
+			return new NotNullConstraintViolationException (r, message, mapping, obj);
+		}
+
+		public static NotNullConstraintViolationException New (SQLiteException exception, TableMapping mapping, object obj)
+		{
+			return new NotNullConstraintViolationException (exception.Result, exception.Message, mapping, obj);
+		}
+	}
+
+	[Flags]
+	public enum SQLiteOpenFlags {
+		ReadOnly = 1, ReadWrite = 2, Create = 4,
+		NoMutex = 0x8000, FullMutex = 0x10000,
+		SharedCache = 0x20000, PrivateCache = 0x40000,
+		ProtectionComplete = 0x00100000,
+		ProtectionCompleteUnlessOpen = 0x00200000,
+		ProtectionCompleteUntilFirstUserAuthentication = 0x00300000,
+		ProtectionNone = 0x00400000
+	}
+
+	[Flags]
+	public enum CreateFlags
+	{
+		None = 0,
+		ImplicitPK = 1,    // create a primary key for field called 'Id' (Orm.ImplicitPkName)
+		ImplicitIndex = 2, // create an index for fields ending in 'Id' (Orm.ImplicitIndexSuffix)
+		AllImplicit = 3,   // do both above
+
+		AutoIncPK = 4      // force PK field to be auto inc
+	}
+
+	/// <summary>
+	/// Represents an open connection to a SQLite database.
+	/// </summary>
+	public partial class SQLiteConnection : IDisposable
+	{
+		private bool _open;
+		private TimeSpan _busyTimeout;
+		private Dictionary<string, TableMapping> _mappings = null;
+		private Dictionary<string, TableMapping> _tables = null;
+		private System.Diagnostics.Stopwatch _sw;
+		private TimeSpan _elapsed = default(TimeSpan);
+
+		private int _transactionDepth = 0;
+		private Random _rand = new Random ();
+
+		public Sqlite3DatabaseHandle Handle { get; private set; }
+		internal static readonly Sqlite3DatabaseHandle NullHandle = default(Sqlite3DatabaseHandle);
+
+		public string DatabasePath { get; private set; }
+
+		// Dictionary of synchronization objects.
+		//
+		// To prevent database disruption, a database file must be accessed *synchronously*.
+		// For the purpose we create synchronous objects for each database file and store in the
+		// static dictionary to share it among all connections.
+		// The key of the dictionary is database file path and its value is an object to be used
+		// by lock() statement.
+		//
+		// Use case:
+		// - database file lock is done implicitly and automatically.
+		// - To prepend deadlock, application may lock a database file explicity by either way:
+		//   - RunInTransaction(Action) locks the database during the transaction (for insert/update)
+		//   - RunInDatabaseLock(Action) similarly locks the database but no transaction (for query)
+		private static Dictionary<string, object> syncObjects = new Dictionary<string, object>();
+
+		#region debug tracing
+
+		public bool Trace { get; set; }
+        public bool TimeExecution { get; set; }
+
+		public delegate void TraceHandler (string message);
+		public event TraceHandler TraceEvent;
+
+		internal void InvokeTrace (string message)
+		{
+			if (TraceEvent != null) {
+				TraceEvent(message);
+			}
+		}
+
+		public delegate void TimeExecutionHandler (TimeSpan executionTime, TimeSpan totalExecutionTime);
+		public event TimeExecutionHandler TimeExecutionEvent;
+
+		internal void InvokeTimeExecution(TimeSpan executionTime, TimeSpan totalExecutionTime)
+		{
+			if (TimeExecutionEvent != null) {
+				TimeExecutionEvent(executionTime, totalExecutionTime);
+			}
+		}
+
+		#endregion
+
+		public bool StoreDateTimeAsTicks { get; private set; }
+
+		/// <summary>
+		/// Constructs a new SQLiteConnection and opens a SQLite database specified by databasePath.
+		/// </summary>
+		/// <param name="databasePath">
+		/// Specifies the path to the database file.
+		/// </param>
+		/// <param name="storeDateTimeAsTicks">
+		/// Specifies whether to store DateTime properties as ticks (true) or strings (false). You
+		/// absolutely do want to store them as Ticks in all new projects. The default of false is
+		/// only here for backwards compatibility. There is a *significant* speed advantage, with no
+		/// down sides, when setting storeDateTimeAsTicks = true.
+		/// </param>
+		public SQLiteConnection (string databasePath, bool storeDateTimeAsTicks = false)
+			: this (databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks)
+		{
+		}
+
+		/// <summary>
+		/// Constructs a new SQLiteConnection and opens a SQLite database specified by databasePath.
+		/// </summary>
+		/// <param name="databasePath">
+		/// Specifies the path to the database file.
+		/// </param>
+		/// <param name="storeDateTimeAsTicks">
+		/// Specifies whether to store DateTime properties as ticks (true) or strings (false). You
+		/// absolutely do want to store them as Ticks in all new projects. The default of false is
+		/// only here for backwards compatibility. There is a *significant* speed advantage, with no
+		/// down sides, when setting storeDateTimeAsTicks = true.
+		/// </param>
+		public SQLiteConnection (string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = false)
+		{
+			if (string.IsNullOrEmpty (databasePath))
+				throw new ArgumentException ("Must be specified", "databasePath");
+
+			DatabasePath = databasePath;
+			mayCreateSyncObject(databasePath);
+
+#if NETFX_CORE
+			SQLite3.SetDirectory(/*temp directory type*/2, Windows.Storage.ApplicationData.Current.TemporaryFolder.Path);
+#endif
+
+			Sqlite3DatabaseHandle handle;
+
+#if SILVERLIGHT || USE_CSHARP_SQLITE
+			var r = SQLite3.Open (databasePath, out handle, (int)openFlags, IntPtr.Zero);
+#else
+			// open using the byte[]
+			// in the case where the path may include Unicode
+			// force open to using UTF-8 using sqlite3_open_v2
+			var databasePathAsBytes = GetNullTerminatedUtf8 (DatabasePath);
+			var r = SQLite3.Open (databasePathAsBytes, out handle, (int) openFlags, IntPtr.Zero);
+#endif
+
+			Handle = handle;
+			if (r != SQLite3.Result.OK) {
+				throw SQLiteException.New (r, String.Format ("Could not open database file: {0} ({1})", DatabasePath, r));
+			}
+			_open = true;
+
+			StoreDateTimeAsTicks = storeDateTimeAsTicks;
+			
+			BusyTimeout = TimeSpan.FromSeconds (0.1);
+		}
+		
+		static SQLiteConnection ()
+		{
+			if (_preserveDuringLinkMagic) {
+				var ti = new ColumnInfo ();
+				ti.Name = "magic";
+			}
+		}
+
+		void mayCreateSyncObject(string databasePath)
+		{
+			if (!syncObjects.ContainsKey(databasePath)) {
+				syncObjects[databasePath] = new object();
+			}
+		}
+
+		/// <summary>
+		/// Gets the synchronous object, to be lock the database file for updating.
+		/// </summary>
+		/// <value>The sync object.</value>
+		public object SyncObject { get { return syncObjects[DatabasePath];} }
+
+		public void EnableLoadExtension(int onoff)
+		{
+			SQLite3.Result r = SQLite3.EnableLoadExtension(Handle, onoff);
+			if (r != SQLite3.Result.OK) {
+				string msg = SQLite3.GetErrmsg (Handle);
+				throw SQLiteException.New (r, msg);
+			}
+		}
+
+		static byte[] GetNullTerminatedUtf8 (string s)
+		{
+			var utf8Length = System.Text.Encoding.UTF8.GetByteCount (s);
+			var bytes = new byte [utf8Length + 1];
+			utf8Length = System.Text.Encoding.UTF8.GetBytes(s, 0, s.Length, bytes, 0);
+			return bytes;
+		}
+		
+		/// <summary>
+		/// Used to list some code that we want the MonoTouch linker
+		/// to see, but that we never want to actually execute.
+		/// </summary>
+		#pragma warning disable 649
+		static bool _preserveDuringLinkMagic;
+		#pragma warning restore 649
+
+		/// <summary>
+		/// Sets a busy handler to sleep the specified amount of time when a table is locked.
+		/// The handler will sleep multiple times until a total time of <see cref="BusyTimeout"/> has accumulated.
+		/// </summary>
+		public TimeSpan BusyTimeout {
+			get { return _busyTimeout; }
+			set {
+				_busyTimeout = value;
+				if (Handle != NullHandle) {
+					SQLite3.BusyTimeout (Handle, (int)_busyTimeout.TotalMilliseconds);
+				}
+			}
+		}
+
+		/// <summary>
+		/// Returns the mappings from types to tables that the connection
+		/// currently understands.
+		/// </summary>
+		public IEnumerable<TableMapping> TableMappings {
+			get {
+				return _tables != null ? _tables.Values : Enumerable.Empty<TableMapping> ();
+			}
+		}
+
+		/// <summary>
+		/// Retrieves the mapping that is automatically generated for the given type.
+		/// </summary>
+		/// <param name="type">
+		/// The type whose mapping to the database is returned.
+		/// </param>         
+		/// <param name="createFlags">
+		/// Optional flags allowing implicit PK and indexes based on naming conventions
+		/// </param>     
+		/// <returns>
+		/// The mapping represents the schema of the columns of the database and contains 
+		/// methods to set and get properties of objects.
+		/// </returns>
+		public TableMapping GetMapping(Type type, CreateFlags createFlags = CreateFlags.None)
+		{
+			if (_mappings == null) {
+				_mappings = new Dictionary<string, TableMapping> ();
+			}
+			TableMapping map;
+			if (!_mappings.TryGetValue (type.FullName, out map)) {
+				map = new TableMapping (type, createFlags);
+				_mappings [type.FullName] = map;
+			}
+			return map;
+		}
+		
+		/// <summary>
+		/// Retrieves the mapping that is automatically generated for the given type.
+		/// </summary>
+		/// <returns>
+		/// The mapping represents the schema of the columns of the database and contains 
+		/// methods to set and get properties of objects.
+		/// </returns>
+		public TableMapping GetMapping<T> ()
+		{
+			return GetMapping (typeof (T));
+		}
+
+		private struct IndexedColumn
+		{
+			public int Order;
+			public string ColumnName;
+		}
+
+		private struct IndexInfo
+		{
+			public string IndexName;
+			public string TableName;
+			public bool Unique;
+			public List<IndexedColumn> Columns;
+		}
+
+		/// <summary>
+		/// Executes a "drop table" on the database.  This is non-recoverable.
+		/// </summary>
+		public int DropTable<T>()
+		{
+			var map = GetMapping (typeof (T));
+
+			var query = string.Format("drop table if exists \"{0}\"", map.TableName);
+
+			return Execute (query);
+		}
+		
+		/// <summary>
+		/// Executes a "create table if not exists" on the database. It also
+		/// creates any specified indexes on the columns of the table. It uses
+		/// a schema automatically generated from the specified type. You can
+		/// later access this schema by calling GetMapping.
+		/// </summary>
+		/// <returns>
+		/// The number of entries added to the database schema.
+		/// </returns>
+		public int CreateTable<T>(CreateFlags createFlags = CreateFlags.None)
+		{
+			return CreateTable(typeof (T), createFlags);
+		}
+
+		/// <summary>
+		/// Executes a "create table if not exists" on the database. It also
+		/// creates any specified indexes on the columns of the table. It uses
+		/// a schema automatically generated from the specified type. You can
+		/// later access this schema by calling GetMapping.
+		/// </summary>
+		/// <param name="ty">Type to reflect to a database table.</param>
+		/// <param name="createFlags">Optional flags allowing implicit PK and indexes based on naming conventions.</param>  
+		/// <returns>
+		/// The number of entries added to the database schema.
+		/// </returns>
+		public int CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None)
+		{
+			if (_tables == null) {
+				_tables = new Dictionary<string, TableMapping> ();
+			}
+			TableMapping map;
+			if (!_tables.TryGetValue (ty.FullName, out map)) {
+				map = GetMapping (ty, createFlags);
+				_tables.Add (ty.FullName, map);
+			}
+			var query = "create table if not exists \"" + map.TableName + "\"(\n";
+			
+			var decls = map.Columns.Select (p => Orm.SqlDecl (p, StoreDateTimeAsTicks));
+			var decl = string.Join (",\n", decls.ToArray ());
+			query += decl;
+			query += ")";
+			
+			var count = Execute (query);
+			
+			if (count == 0) { //Possible bug: This always seems to return 0?
+				// Table already exists, migrate it
+				MigrateTable (map);
+			}
+
+			var indexes = new Dictionary<string, IndexInfo> ();
+			foreach (var c in map.Columns) {
+				foreach (var i in c.Indices) {
+					var iname = i.Name ?? map.TableName + "_" + c.Name;
+					IndexInfo iinfo;
+					if (!indexes.TryGetValue (iname, out iinfo)) {
+						iinfo = new IndexInfo {
+							IndexName = iname,
+							TableName = map.TableName,
+							Unique = i.Unique,
+							Columns = new List<IndexedColumn> ()
+						};
+						indexes.Add (iname, iinfo);
+					}
+
+					if (i.Unique != iinfo.Unique)
+						throw new Exception ("All the columns in an index must have the same value for their Unique property");
+
+					iinfo.Columns.Add (new IndexedColumn {
+						Order = i.Order,
+						ColumnName = c.Name
+					});
+				}
+			}
+
+			foreach (var indexName in indexes.Keys) {
+				var index = indexes[indexName];
+				string[] columnNames = new string[index.Columns.Count];
+				if (index.Columns.Count == 1) {
+					columnNames[0] = index.Columns[0].ColumnName;
+				} else {
+					index.Columns.Sort((lhs, rhs) => {
+						return lhs.Order - rhs.Order;
+					});
+					for (int i = 0, end = index.Columns.Count; i < end; ++i) {
+						columnNames[i] = index.Columns[i].ColumnName;
+					}
+				}
+				count += CreateIndex(indexName, index.TableName, columnNames, index.Unique);
+			}
+			
+			return count;
+		}
+
+		/// <summary>
+		/// Creates an index for the specified table and columns.
+		/// </summary>
+		/// <param name="indexName">Name of the index to create</param>
+		/// <param name="tableName">Name of the database table</param>
+		/// <param name="columnNames">An array of column names to index</param>
+		/// <param name="unique">Whether the index should be unique</param>
+		public int CreateIndex(string indexName, string tableName, string[] columnNames, bool unique = false)
+		{
+			const string sqlFormat = "create {2} index if not exists \"{3}\" on \"{0}\"(\"{1}\")";
+			var sql = String.Format(sqlFormat, tableName, string.Join ("\", \"", columnNames), unique ? "unique" : "", indexName);
+			return Execute(sql);
+		}
+
+		/// <summary>
+		/// Creates an index for the specified table and column.
+		/// </summary>
+		/// <param name="indexName">Name of the index to create</param>
+		/// <param name="tableName">Name of the database table</param>
+		/// <param name="columnName">Name of the column to index</param>
+		/// <param name="unique">Whether the index should be unique</param>
+		public int CreateIndex(string indexName, string tableName, string columnName, bool unique = false)
+		{
+			return CreateIndex(indexName, tableName, new string[] { columnName }, unique);
+		}
+		
+		/// <summary>
+		/// Creates an index for the specified table and column.
+		/// </summary>
+		/// <param name="tableName">Name of the database table</param>
+		/// <param name="columnName">Name of the column to index</param>
+		/// <param name="unique">Whether the index should be unique</param>
+		public int CreateIndex(string tableName, string columnName, bool unique = false)
+		{
+			return CreateIndex(tableName + "_" + columnName, tableName, columnName, unique);
+		}
+
+		/// <summary>
+		/// Creates an index for the specified table and columns.
+		/// </summary>
+		/// <param name="tableName">Name of the database table</param>
+		/// <param name="columnNames">An array of column names to index</param>
+		/// <param name="unique">Whether the index should be unique</param>
+		public int CreateIndex(string tableName, string[] columnNames, bool unique = false)
+		{
+			return CreateIndex(tableName + "_" + string.Join ("_", columnNames), tableName, columnNames, unique);
+		}
+
+		/// <summary>
+		/// Creates an index for the specified object property.
+		/// e.g. CreateIndex<Client>(c => c.Name);
+		/// </summary>
+		/// <typeparam name="T">Type to reflect to a database table.</typeparam>
+		/// <param name="property">Property to index</param>
+		/// <param name="unique">Whether the index should be unique</param>
+		public void CreateIndex<T>(Expression<Func<T, object>> property, bool unique = false)
+		{
+			MemberExpression mx;
+			if (property.Body.NodeType == ExpressionType.Convert)
+			{
+				mx = ((UnaryExpression)property.Body).Operand as MemberExpression;
+			}
+			else
+			{
+				mx= (property.Body as MemberExpression);
+			}
+			var propertyInfo = mx.Member as PropertyInfo;
+			if (propertyInfo == null)
+			{
+				throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
+			}
+
+			var propName = propertyInfo.Name;
+
+			var map = GetMapping<T>();
+			var colName = map.FindColumnWithPropertyName(propName).Name;
+
+			CreateIndex(map.TableName, colName, unique);
+		}
+
+		public class ColumnInfo
+		{
+//			public int cid { get; set; }
+
+			[Column ("name")]
+			public string Name { get; set; }
+
+//			[Column ("type")]
+//			public string ColumnType { get; set; }
+
+			public int notnull { get; set; }
+
+//			public string dflt_value { get; set; }
+
+//			public int pk { get; set; }
+
+			public override string ToString ()
+			{
+				return Name;
+			}
+		}
+
+		public List<ColumnInfo> GetTableInfo (string tableName)
+		{
+			var query = "pragma table_info(\"" + tableName + "\")";			
+			return Query<ColumnInfo> (query);
+		}
+
+		void MigrateTable (TableMapping map)
+		{
+			var existingCols = GetTableInfo (map.TableName);
+			
+			var toBeAdded = new List<TableMapping.Column> ();
+			
+			foreach (var p in map.Columns) {
+				var found = false;
+				foreach (var c in existingCols) {
+					found = (string.Compare (p.Name, c.Name, StringComparison.OrdinalIgnoreCase) == 0);
+					if (found)
+						break;
+				}
+				if (!found) {
+					toBeAdded.Add (p);
+				}
+			}
+			
+			foreach (var p in toBeAdded) {
+				var addCol = "alter table \"" + map.TableName + "\" add column " + Orm.SqlDecl (p, StoreDateTimeAsTicks);
+				Execute (addCol);
+			}
+		}
+
+		/// <summary>
+		/// Creates a new SQLiteCommand. Can be overridden to provide a sub-class.
+		/// </summary>
+		/// <seealso cref="SQLiteCommand.OnInstanceCreated"/>
+		protected virtual SQLiteCommand NewCommand ()
+		{
+			return new SQLiteCommand (this);
+		}
+
+		/// <summary>
+		/// Creates a new SQLiteCommand given the command text with arguments. Place a '?'
+		/// in the command text for each of the arguments.
+		/// </summary>
+		/// <param name="cmdText">
+		/// The fully escaped SQL.
+		/// </param>
+		/// <param name="args">
+		/// Arguments to substitute for the occurences of '?' in the command text.
+		/// </param>
+		/// <returns>
+		/// A <see cref="SQLiteCommand"/>
+		/// </returns>
+		public SQLiteCommand CreateCommand (string cmdText, params object[] ps)
+		{
+			if (!_open)
+				throw SQLiteException.New (SQLite3.Result.Error, "Cannot create commands from unopened database");
+
+			var cmd = NewCommand ();
+			cmd.CommandText = cmdText;
+			foreach (var o in ps) {
+				cmd.Bind (o);
+			}
+			return cmd;
+		}
+
+		/// <summary>
+		/// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
+		/// in the command text for each of the arguments and then executes that command.
+		/// Use this method instead of Query when you don't expect rows back. Such cases include
+		/// INSERTs, UPDATEs, and DELETEs.
+		/// You can set the Trace or TimeExecution properties of the connection
+		/// to profile execution.
+		/// </summary>
+		/// <param name="query">
+		/// The fully escaped SQL.
+		/// </param>
+		/// <param name="args">
+		/// Arguments to substitute for the occurences of '?' in the query.
+		/// </param>
+		/// <returns>
+		/// The number of rows modified in the database as a result of this execution.
+		/// </returns>
+		public int Execute (string query, params object[] args)
+		{
+			var cmd = CreateCommand (query, args);
+			
+			if (TimeExecution) {
+				if (_sw == null) {
+					_sw = new Stopwatch ();
+				}
+				_sw.Reset ();
+				_sw.Start ();
+			}
+
+			var r = cmd.ExecuteNonQuery ();
+			
+			if (TimeExecution) {
+				_sw.Stop ();
+				_elapsed += _sw.Elapsed;
+				this.InvokeTimeExecution (_sw.Elapsed, _elapsed);
+			}
+			
+			return r;
+		}
+
+		public T ExecuteScalar<T> (string query, params object[] args)
+		{
+			var cmd = CreateCommand (query, args);
+			
+			if (TimeExecution) {
+				if (_sw == null) {
+					_sw = new Stopwatch ();
+				}
+				_sw.Reset ();
+				_sw.Start ();
+			}
+			
+			var r = cmd.ExecuteScalar<T> ();
+			
+			if (TimeExecution) {
+				_sw.Stop ();
+				_elapsed += _sw.Elapsed;
+				this.InvokeTimeExecution (_sw.Elapsed, _elapsed);
+			}
+			
+			return r;
+		}
+
+		/// <summary>
+		/// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
+		/// in the command text for each of the arguments and then executes that command.
+		/// It returns each row of the result using the mapping automatically generated for
+		/// the given type.
+		/// </summary>
+		/// <param name="query">
+		/// The fully escaped SQL.
+		/// </param>
+		/// <param name="args">
+		/// Arguments to substitute for the occurences of '?' in the query.
+		/// </param>
+		/// <returns>
+		/// An enumerable with one result for each row returned by the query.
+		/// </returns>
+		public List<T> Query<T> (string query, params object[] args) where T : new()
+		{
+			var cmd = CreateCommand (query, args);
+			return cmd.ExecuteQuery<T> ();
+		}
+
+		/// <summary>
+		/// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
+		/// in the command text for each of the arguments and then executes that command.
+		/// It returns each row of the result using the mapping automatically generated for
+		/// the given type.
+		/// </summary>
+		/// <param name="query">
+		/// The fully escaped SQL.
+		/// </param>
+		/// <param name="args">
+		/// Arguments to substitute for the occurences of '?' in the query.
+		/// </param>
+		/// <returns>
+		/// An enumerable with one result for each row returned by the query.
+		/// The enumerator will call sqlite3_step on each call to MoveNext, so the database
+		/// connection must remain open for the lifetime of the enumerator.
+		/// </returns>
+		public IEnumerable<T> DeferredQuery<T>(string query, params object[] args) where T : new()
+		{
+			var cmd = CreateCommand(query, args);
+			return cmd.ExecuteDeferredQuery<T>();
+		}
+
+		/// <summary>
+		/// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
+		/// in the command text for each of the arguments and then executes that command.
+		/// It returns each row of the result using the specified mapping. This function is
+		/// only used by libraries in order to query the database via introspection. It is
+		/// normally not used.
+		/// </summary>
+		/// <param name="map">
+		/// A <see cref="TableMapping"/> to use to convert the resulting rows
+		/// into objects.
+		/// </param>
+		/// <param name="query">
+		/// The fully escaped SQL.
+		/// </param>
+		/// <param name="args">
+		/// Arguments to substitute for the occurences of '?' in the query.
+		/// </param>
+		/// <returns>
+		/// An enumerable with one result for each row returned by the query.
+		/// </returns>
+		public List<object> Query (TableMapping map, string query, params object[] args)
+		{
+			var cmd = CreateCommand (query, args);
+			return cmd.ExecuteQuery<object> (map);
+		}
+
+		/// <summary>
+		/// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
+		/// in the command text for each of the arguments and then executes that command.
+		/// It returns each row of the result using the specified mapping. This function is
+		/// only used by libraries in order to query the database via introspection. It is
+		/// normally not used.
+		/// </summary>
+		/// <param name="map">
+		/// A <see cref="TableMapping"/> to use to convert the resulting rows
+		/// into objects.
+		/// </param>
+		/// <param name="query">
+		/// The fully escaped SQL.
+		/// </param>
+		/// <param name="args">
+		/// Arguments to substitute for the occurences of '?' in the query.
+		/// </param>
+		/// <returns>
+		/// An enumerable with one result for each row returned by the query.
+		/// The enumerator will call sqlite3_step on each call to MoveNext, so the database
+		/// connection must remain open for the lifetime of the enumerator.
+		/// </returns>
+		public IEnumerable<object> DeferredQuery(TableMapping map, string query, params object[] args)
+		{
+			var cmd = CreateCommand(query, args);
+			return cmd.ExecuteDeferredQuery<object>(map);
+		}
+
+		/// <summary>
+		/// Returns a queryable interface to the table represented by the given type.
+		/// </summary>
+		/// <returns>
+		/// A queryable object that is able to translate Where, OrderBy, and Take
+		/// queries into native SQL.
+		/// </returns>
+		public TableQuery<T> Table<T> () where T : new()
+		{
+			return new TableQuery<T> (this);
+		}
+
+		/// <summary>
+		/// Attempts to retrieve an object with the given primary key from the table
+		/// associated with the specified type. Use of this method requires that
+		/// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
+		/// </summary>
+		/// <param name="pk">
+		/// The primary key.
+		/// </param>
+		/// <returns>
+		/// The object with the given primary key. Throws a not found exception
+		/// if the object is not found.
+		/// </returns>
+		public T Get<T> (object pk) where T : new()
+		{
+			var map = GetMapping (typeof(T));
+			return Query<T> (map.GetByPrimaryKeySql, pk).First ();
+		}
+
+		/// <summary>
+		/// Attempts to retrieve the first object that matches the predicate from the table
+		/// associated with the specified type. 
+		/// </summary>
+		/// <param name="predicate">
+		/// A predicate for which object to find.
+		/// </param>
+		/// <returns>
+		/// The object that matches the given predicate. Throws a not found exception
+		/// if the object is not found.
+		/// </returns>
+		public T Get<T> (Expression<Func<T, bool>> predicate) where T : new()
+		{
+			return Table<T> ().Where (predicate).First ();
+		}
+
+		/// <summary>
+		/// Attempts to retrieve an object with the given primary key from the table
+		/// associated with the specified type. Use of this method requires that
+		/// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
+		/// </summary>
+		/// <param name="pk">
+		/// The primary key.
+		/// </param>
+		/// <returns>
+		/// The object with the given primary key or null
+		/// if the object is not found.
+		/// </returns>
+		public T Find<T> (object pk) where T : new ()
+		{
+			var map = GetMapping (typeof (T));
+			return Query<T> (map.GetByPrimaryKeySql, pk).FirstOrDefault ();
+		}
+
+		/// <summary>
+		/// Attempts to retrieve an object with the given primary key from the table
+		/// associated with the specified type. Use of this method requires that
+		/// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
+		/// </summary>
+		/// <param name="pk">
+		/// The primary key.
+		/// </param>
+		/// <param name="map">
+		/// The TableMapping used to identify the object type.
+		/// </param>
+		/// <returns>
+		/// The object with the given primary key or null
+		/// if the object is not found.
+		/// </returns>
+		public object Find (object pk, TableMapping map)
+		{
+			return Query (map, map.GetByPrimaryKeySql, pk).FirstOrDefault ();
+		}
+		
+		/// <summary>
+		/// Attempts to retrieve the first object that matches the predicate from the table
+		/// associated with the specified type. 
+		/// </summary>
+		/// <param name="predicate">
+		/// A predicate for which object to find.
+		/// </param>
+		/// <returns>
+		/// The object that matches the given predicate or null
+		/// if the object is not found.
+		/// </returns>
+		public T Find<T> (Expression<Func<T, bool>> predicate) where T : new()
+		{
+			return Table<T> ().Where (predicate).FirstOrDefault ();
+		}
+
+		/// <summary>
+		/// Whether <see cref="BeginTransaction"/> has been called and the database is waiting for a <see cref="Commit"/>.
+		/// </summary>
+		public bool IsInTransaction {
+			get { return _transactionDepth > 0; }
+		}
+
+		/// <summary>
+		/// Begins a new transaction. Call <see cref="Commit"/> to end the transaction.
+		/// </summary>
+		/// <example cref="System.InvalidOperationException">Throws if a transaction has already begun.</example>
+		public void BeginTransaction ()
+		{
+			// The BEGIN command only works if the transaction stack is empty, 
+			//    or in other words if there are no pending transactions. 
+			// If the transaction stack is not empty when the BEGIN command is invoked, 
+			//    then the command fails with an error.
+			// Rather than crash with an error, we will just ignore calls to BeginTransaction
+			//    that would result in an error.
+			if (Interlocked.CompareExchange (ref _transactionDepth, 1, 0) == 0) {
+				try {
+					Execute ("begin transaction");
+				} catch (Exception ex) {
+					var sqlExp = ex as SQLiteException;
+					if (sqlExp != null) {
+						// It is recommended that applications respond to the errors listed below 
+						//    by explicitly issuing a ROLLBACK command.
+						// TODO: This rollback failsafe should be localized to all throw sites.
+						switch (sqlExp.Result) {
+						case SQLite3.Result.IOError:
+						case SQLite3.Result.Full:
+						case SQLite3.Result.Busy:
+						case SQLite3.Result.NoMem:
+						case SQLite3.Result.Interrupt:
+							RollbackTo (null, true);
+							break;
+						}
+					} else {
+						// Call decrement and not VolatileWrite in case we've already 
+						//    created a transaction point in SaveTransactionPoint since the catch.
+						Interlocked.Decrement (ref _transactionDepth);
+					}
+
+					throw;
+				}
+			} else { 
+				// Calling BeginTransaction on an already open transaction is invalid
+				throw new InvalidOperationException ("Cannot begin a transaction while already in a transaction.");
+			}
+		}
+
+		/// <summary>
+		/// Creates a savepoint in the database at the current point in the transaction timeline.
+		/// Begins a new transaction if one is not in progress.
+		/// 
+		/// Call <see cref="RollbackTo"/> to undo transactions since the returned savepoint.
+		/// Call <see cref="Release"/> to commit transactions after the savepoint returned here.
+		/// Call <see cref="Commit"/> to end the transaction, committing all changes.
+		/// </summary>
+		/// <returns>A string naming the savepoint.</returns>
+		public string SaveTransactionPoint ()
+		{
+			int depth = Interlocked.Increment (ref _transactionDepth) - 1;
+			string retVal = "S" + _rand.Next (short.MaxValue) + "D" + depth;
+
+			try {
+				Execute ("savepoint " + retVal);
+			} catch (Exception ex) {
+				var sqlExp = ex as SQLiteException;
+				if (sqlExp != null) {
+					// It is recommended that applications respond to the errors listed below 
+					//    by explicitly issuing a ROLLBACK command.
+					// TODO: This rollback failsafe should be localized to all throw sites.
+					switch (sqlExp.Result) {
+					case SQLite3.Result.IOError:
+					case SQLite3.Result.Full:
+					case SQLite3.Result.Busy:
+					case SQLite3.Result.NoMem:
+					case SQLite3.Result.Interrupt:
+						RollbackTo (null, true);
+						break;
+					}
+				} else {
+					Interlocked.Decrement (ref _transactionDepth);
+				}
+
+				throw;
+			}
+
+			return retVal;
+		}
+
+		/// <summary>
+		/// Rolls back the transaction that was begun by <see cref="BeginTransaction"/> or <see cref="SaveTransactionPoint"/>.
+		/// </summary>
+		public void Rollback ()
+		{
+			RollbackTo (null, false);
+		}
+
+		/// <summary>
+		/// Rolls back the savepoint created by <see cref="BeginTransaction"/> or SaveTransactionPoint.
+		/// </summary>
+		/// <param name="savepoint">The name of the savepoint to roll back to, as returned by <see cref="SaveTransactionPoint"/>.  If savepoint is null or empty, this method is equivalent to a call to <see cref="Rollback"/></param>
+		public void RollbackTo (string savepoint)
+		{
+			RollbackTo (savepoint, false);
+		}
+
+		/// <summary>
+		/// Rolls back the transaction that was begun by <see cref="BeginTransaction"/>.
+		/// </summary>
+		/// <param name="noThrow">true to avoid throwing exceptions, false otherwise</param>
+		void RollbackTo (string savepoint, bool noThrow)
+		{
+			// Rolling back without a TO clause rolls backs all transactions 
+			//    and leaves the transaction stack empty.   
+			try {
+				if (String.IsNullOrEmpty (savepoint)) {
+					if (Interlocked.Exchange (ref _transactionDepth, 0) > 0) {
+						Execute ("rollback");
+					}
+				} else {
+					DoSavePointExecute (savepoint, "rollback to ");
+				}   
+			} catch (SQLiteException) {
+				if (!noThrow)
+					throw;
+			
+			}
+			// No need to rollback if there are no transactions open.
+		}
+
+		/// <summary>
+		/// Releases a savepoint returned from <see cref="SaveTransactionPoint"/>.  Releasing a savepoint 
+		///    makes changes since that savepoint permanent if the savepoint began the transaction,
+		///    or otherwise the changes are permanent pending a call to <see cref="Commit"/>.
+		/// 
+		/// The RELEASE command is like a COMMIT for a SAVEPOINT.
+		/// </summary>
+		/// <param name="savepoint">The name of the savepoint to release.  The string should be the result of a call to <see cref="SaveTransactionPoint"/></param>
+		public void Release (string savepoint)
+		{
+			DoSavePointExecute (savepoint, "release ");
+		}
+
+		void DoSavePointExecute (string savepoint, string cmd)
+		{
+			// Validate the savepoint
+			int firstLen = savepoint.IndexOf ('D');
+			if (firstLen >= 2 && savepoint.Length > firstLen + 1) {
+				int depth;
+				if (Int32.TryParse (savepoint.Substring (firstLen + 1), out depth)) {
+					// TODO: Mild race here, but inescapable without locking almost everywhere.
+					if (0 <= depth && depth < _transactionDepth) {
+#if NETFX_CORE
+						Volatile.Write (ref _transactionDepth, depth);
+#elif SILVERLIGHT
+						_transactionDepth = depth;
+#else
+						Thread.VolatileWrite (ref _transactionDepth, depth);
+#endif
+						Execute (cmd + savepoint);
+						return;
+					}
+				}
+			}
+
+			throw new ArgumentException ("savePoint is not valid, and should be the result of a call to SaveTransactionPoint.", "savePoint");
+		}
+
+		/// <summary>
+		/// Commits the transaction that was begun by <see cref="BeginTransaction"/>.
+		/// </summary>
+		public void Commit ()
+		{
+			if (Interlocked.Exchange (ref _transactionDepth, 0) != 0) {
+				Execute ("commit");
+			}
+			// Do nothing on a commit with no open transaction
+		}
+
+		/// <summary>
+		/// Executes <param name="action"> within a (possibly nested) transaction by wrapping it in a SAVEPOINT. If an
+		/// exception occurs the whole transaction is rolled back, not just the current savepoint. The exception
+		/// is rethrown.
+		/// </summary>
+		/// <param name="action">
+		/// The <see cref="Action"/> to perform within a transaction. <param name="action"> can contain any number
+		/// of operations on the connection but should never call <see cref="BeginTransaction"/> or
+		/// <see cref="Commit"/>.
+		/// </param>
+		public void RunInTransaction (Action action)
+		{
+			try {
+				lock (syncObjects[DatabasePath]) {
+					var savePoint = SaveTransactionPoint ();
+					action ();
+					Release (savePoint);
+				}
+			} catch (Exception) {
+				Rollback ();
+				throw;
+			}
+		}
+
+		/// <summary>
+		/// Executes <param name="action"> while blocking other threads to access the same database.
+		/// </summary>
+		/// <param name="action">
+		/// The <see cref="Action"/> to perform within a lock.
+		/// </param>
+		public void RunInDatabaseLock (Action action)
+		{
+			lock (syncObjects[DatabasePath]) {
+				action ();
+			}
+		}
+
+		/// <summary>
+		/// Inserts all specified objects.
+		/// </summary>
+		/// <param name="objects">
+		/// An <see cref="IEnumerable"/> of the objects to insert.
+		/// </param>
+		/// <returns>
+		/// The number of rows added to the table.
+		/// </returns>
+		public int InsertAll (System.Collections.IEnumerable objects)
+		{
+			var c = 0;
+			RunInTransaction(() => {
+				foreach (var r in objects) {
+					c += Insert (r);
+				}
+			});
+			return c;
+		}
+
+		/// <summary>
+		/// Inserts all specified objects.
+		/// </summary>
+		/// <param name="objects">
+		/// An <see cref="IEnumerable"/> of the objects to insert.
+		/// </param>
+		/// <param name="extra">
+		/// Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
+		/// </param>
+		/// <returns>
+		/// The number of rows added to the table.
+		/// </returns>
+		public int InsertAll (System.Collections.IEnumerable objects, string extra)
+		{
+			var c = 0;
+			RunInTransaction (() => {
+				foreach (var r in objects) {
+					c += Insert (r, extra);
+				}
+			});
+			return c;
+		}
+
+		/// <summary>
+		/// Inserts all specified objects.
+		/// </summary>
+		/// <param name="objects">
+		/// An <see cref="IEnumerable"/> of the objects to insert.
+		/// </param>
+		/// <param name="objType">
+		/// The type of object to insert.
+		/// </param>
+		/// <returns>
+		/// The number of rows added to the table.
+		/// </returns>
+		public int InsertAll (System.Collections.IEnumerable objects, Type objType)
+		{
+			var c = 0;
+			RunInTransaction (() => {
+				foreach (var r in objects) {
+					c += Insert (r, objType);
+				}
+			});
+			return c;
+		}
+		
+		/// <summary>
+		/// Inserts the given object and retrieves its
+		/// auto incremented primary key if it has one.
+		/// </summary>
+		/// <param name="obj">
+		/// The object to insert.
+		/// </param>
+		/// <returns>
+		/// The number of rows added to the table.
+		/// </returns>
+		public int Insert (object obj)
+		{
+			if (obj == null) {
+				return 0;
+			}
+			return Insert (obj, "", obj.GetType ());
+		}
+
+		/// <summary>
+		/// Inserts the given object and retrieves its
+		/// auto incremented primary key if it has one.
+		/// If a UNIQUE constraint violation occurs with
+		/// some pre-existing object, this function deletes
+		/// the old object.
+		/// </summary>
+		/// <param name="obj">
+		/// The object to insert.
+		/// </param>
+		/// <returns>
+		/// The number of rows modified.
+		/// </returns>
+		public int InsertOrReplace (object obj)
+		{
+			if (obj == null) {
+				return 0;
+			}
+			return Insert (obj, "OR REPLACE", obj.GetType ());
+		}
+
+		/// <summary>
+		/// Inserts the given object and retrieves its
+		/// auto incremented primary key if it has one.
+		/// </summary>
+		/// <param name="obj">
+		/// The object to insert.
+		/// </param>
+		/// <param name="objType">
+		/// The type of object to insert.
+		/// </param>
+		/// <returns>
+		/// The number of rows added to the table.
+		/// </returns>
+		public int Insert (object obj, Type objType)
+		{
+			return Insert (obj, "", objType);
+		}
+
+		/// <summary>
+		/// Inserts the given object and retrieves its
+		/// auto incremented primary key if it has one.
+		/// If a UNIQUE constraint violation occurs with
+		/// some pre-existing object, this function deletes
+		/// the old object.
+		/// </summary>
+		/// <param name="obj">
+		/// The object to insert.
+		/// </param>
+		/// <param name="objType">
+		/// The type of object to insert.
+		/// </param>
+		/// <returns>
+		/// The number of rows modified.
+		/// </returns>
+		public int InsertOrReplace (object obj, Type objType)
+		{
+			return Insert (obj, "OR REPLACE", objType);
+		}
+		
+		/// <summary>
+		/// Inserts the given object and retrieves its
+		/// auto incremented primary key if it has one.
+		/// </summary>
+		/// <param name="obj">
+		/// The object to insert.
+		/// </param>
+		/// <param name="extra">
+		/// Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
+		/// </param>
+		/// <returns>
+		/// The number of rows added to the table.
+		/// </returns>
+		public int Insert (object obj, string extra)
+		{
+			if (obj == null) {
+				return 0;
+			}
+			return Insert (obj, extra, obj.GetType ());
+		}
+
+		/// <summary>
+		/// Inserts the given object and retrieves its
+		/// auto incremented primary key if it has one.
+		/// </summary>
+		/// <param name="obj">
+		/// The object to insert.
+		/// </param>
+		/// <param name="extra">
+		/// Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
+		/// </param>
+		/// <param name="objType">
+		/// The type of object to insert.
+		/// </param>
+		/// <returns>
+		/// The number of rows added to the table.
+		/// </returns>
+		public int Insert (object obj, string extra, Type objType)
+		{
+			if (obj == null || objType == null) {
+				return 0;
+			}
+			
+			
+			var map = GetMapping (objType);
+
+#if NETFX_CORE
+			if (map.PK != null && map.PK.IsAutoGuid)
+			{
+				// no GetProperty so search our way up the inheritance chain till we find it
+				PropertyInfo prop;
+				while (objType != null)
+				{
+					var info = objType.GetTypeInfo();
+					prop = info.GetDeclaredProperty(map.PK.PropertyName);
+					if (prop != null) 
+					{
+						if (prop.GetValue(obj, null).Equals(Guid.Empty))
+						{
+							prop.SetValue(obj, Guid.NewGuid(), null);
+						}
+						break; 
+					}
+
+					objType = info.BaseType;
+				}
+			}
+#else
+			if (map.PK != null && map.PK.IsAutoGuid) {
+				var prop = objType.GetProperty(map.PK.PropertyName);
+				if (prop != null) {
+					//if (prop.GetValue(obj, null).Equals(Guid.Empty)) { 
+					if (prop.GetGetMethod().Invoke(obj, null).Equals(Guid.Empty))
+					{
+						prop.SetValue(obj, Guid.NewGuid(), null);
+					}
+				}
+			}
+#endif
+
+
+			var replacing = string.Compare (extra, "OR REPLACE", StringComparison.OrdinalIgnoreCase) == 0;
+			
+			var cols = replacing ? map.InsertOrReplaceColumns : map.InsertColumns;
+			var vals = new object[cols.Length];
+			for (var i = 0; i < vals.Length; i++) {
+				vals [i] = cols [i].GetValue(obj);
+			}
+			
+			var insertCmd = map.GetInsertCommand (this, extra);
+			int count;
+
+			try {
+				count = insertCmd.ExecuteNonQuery (vals);
+			}
+			catch (SQLiteException ex) {
+
+				if (SQLite3.ExtendedErrCode (this.Handle) == SQLite3.ExtendedResult.ConstraintNotNull) {
+					throw NotNullConstraintViolationException.New (ex.Result, ex.Message, map, obj);
+				}
+				throw;
+			}
+
+			if (map.HasAutoIncPK)
+			{
+				var id = SQLite3.LastInsertRowid (Handle);
+				map.SetAutoIncPK (obj, id);
+			}
+			
+			return count;
+		}
+
+		/// <summary>
+		/// Updates all of the columns of a table using the specified object
+		/// except for its primary key.
+		/// The object is required to have a primary key.
+		/// </summary>
+		/// <param name="obj">
+		/// The object to update. It must have a primary key designated using the PrimaryKeyAttribute.
+		/// </param>
+		/// <returns>
+		/// The number of rows updated.
+		/// </returns>
+		public int Update (object obj)
+		{
+			if (obj == null) {
+				return 0;
+			}
+			return Update (obj, obj.GetType ());
+		}
+
+		/// <summary>
+		/// Updates all of the columns of a table using the specified object
+		/// except for its primary key.
+		/// The object is required to have a primary key.
+		/// </summary>
+		/// <param name="obj">
+		/// The object to update. It must have a primary key designated using the PrimaryKeyAttribute.
+		/// </param>
+		/// <param name="objType">
+		/// The type of object to insert.
+		/// </param>
+		/// <returns>
+		/// The number of rows updated.
+		/// </returns>
+		public int Update (object obj, Type objType)
+		{
+			int rowsAffected = 0;
+			if (obj == null || objType == null) {
+				return 0;
+			}
+			
+			var map = GetMapping (objType);
+			
+			var pk = map.PK;
+			
+			if (pk == null) {
+				throw new NotSupportedException ("Cannot update " + map.TableName + ": it has no PK");
+			}
+			
+			var cols = from p in map.Columns
+				where p != pk
+				select p;
+			var vals = from c in cols
+				select c.GetValue (obj);
+			var ps = new List<object> (vals);
+			ps.Add (pk.GetValue (obj));
+			var q = string.Format ("update \"{0}\" set {1} where {2} = ? ", map.TableName, string.Join (",", (from c in cols
+				select "\"" + c.Name + "\" = ? ").ToArray ()), pk.Name);
+
+			try {
+				rowsAffected = Execute (q, ps.ToArray ());
+			}
+			catch (SQLiteException ex) {
+
+				if (ex.Result == SQLite3.Result.Constraint && SQLite3.ExtendedErrCode (this.Handle) == SQLite3.ExtendedResult.ConstraintNotNull) {
+					throw NotNullConstraintViolationException.New (ex, map, obj);
+				}
+
+				throw ex;
+			}
+
+			return rowsAffected;
+		}
+
+		/// <summary>
+		/// Updates all specified objects.
+		/// </summary>
+		/// <param name="objects">
+		/// An <see cref="IEnumerable"/> of the objects to insert.
+		/// </param>
+		/// <returns>
+		/// The number of rows modified.
+		/// </returns>
+		public int UpdateAll (System.Collections.IEnumerable objects)
+		{
+			var c = 0;
+			RunInTransaction (() => {
+				foreach (var r in objects) {
+					c += Update (r);
+				}
+			});
+			return c;
+		}
+
+		/// <summary>
+		/// Deletes the given object from the database using its primary key.
+		/// </summary>
+		/// <param name="objectToDelete">
+		/// The object to delete. It must have a primary key designated using the PrimaryKeyAttribute.
+		/// </param>
+		/// <returns>
+		/// The number of rows deleted.
+		/// </returns>
+		public int Delete (object objectToDelete)
+		{
+			var map = GetMapping (objectToDelete.GetType ());
+			var pk = map.PK;
+			if (pk == null) {
+				throw new NotSupportedException ("Cannot delete " + map.TableName + ": it has no PK");
+			}
+			var q = string.Format ("delete from \"{0}\" where \"{1}\" = ?", map.TableName, pk.Name);
+			return Execute (q, pk.GetValue (objectToDelete));
+		}
+
+		/// <summary>
+		/// Deletes the object with the specified primary key.
+		/// </summary>
+		/// <param name="primaryKey">
+		/// The primary key of the object to delete.
+		/// </param>
+		/// <returns>
+		/// The number of objects deleted.
+		/// </returns>
+		/// <typeparam name='T'>
+		/// The type of object.
+		/// </typeparam>
+		public int Delete<T> (object primaryKey)
+		{
+			var map = GetMapping (typeof (T));
+			var pk = map.PK;
+			if (pk == null) {
+				throw new NotSupportedException ("Cannot delete " + map.TableName + ": it has no PK");
+			}
+			var q = string.Format ("delete from \"{0}\" where \"{1}\" = ?", map.TableName, pk.Name);
+			return Execute (q, primaryKey);
+		}
+
+		/// <summary>
+		/// Deletes all the objects from the specified table.
+		/// WARNING WARNING: Let me repeat. It deletes ALL the objects from the
+		/// specified table. Do you really want to do that?
+		/// </summary>
+		/// <returns>
+		/// The number of objects deleted.
+		/// </returns>
+		/// <typeparam name='T'>
+		/// The type of objects to delete.
+		/// </typeparam>
+		public int DeleteAll<T> ()
+		{
+			var map = GetMapping (typeof (T));
+			var query = string.Format("delete from \"{0}\"", map.TableName);
+			return Execute (query);
+		}
+
+		~SQLiteConnection ()
+		{
+			Dispose (false);
+		}
+
+		public void Dispose ()
+		{
+			Dispose (true);
+			GC.SuppressFinalize (this);
+		}
+
+		protected virtual void Dispose (bool disposing)
+		{
+			Close ();
+		}
+
+		public void Close ()
+		{
+			if (_open && Handle != NullHandle) {
+				try {
+					if (_mappings != null) {
+						foreach (var sqlInsertCommand in _mappings.Values) {
+							sqlInsertCommand.Dispose();
+						}
+					}
+					var r = SQLite3.Close (Handle);
+					if (r != SQLite3.Result.OK) {
+						string msg = SQLite3.GetErrmsg (Handle);
+						throw SQLiteException.New (r, msg);
+					}
+				}
+				finally {
+					Handle = NullHandle;
+					_open = false;
+				}
+			}
+		}
+	}
+
+	/// <summary>
+	/// Represents a parsed connection string.
+	/// </summary>
+	class SQLiteConnectionString
+	{
+		public string ConnectionString { get; private set; }
+		public string DatabasePath { get; private set; }
+		public bool StoreDateTimeAsTicks { get; private set; }
+
+#if NETFX_CORE
+		static readonly string MetroStyleDataPath = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
+#endif
+
+		public SQLiteConnectionString (string databasePath, bool storeDateTimeAsTicks)
+		{
+			ConnectionString = databasePath;
+			StoreDateTimeAsTicks = storeDateTimeAsTicks;
+
+#if NETFX_CORE
+			DatabasePath = System.IO.Path.Combine (MetroStyleDataPath, databasePath);
+#else
+			DatabasePath = databasePath;
+#endif
+		}
+	}
+
+	[AttributeUsage (AttributeTargets.Class)]
+	public class TableAttribute : Attribute
+	{
+		public string Name { get; set; }
+
+		public TableAttribute (string name)
+		{
+			Name = name;
+		}
+	}
+
+	[AttributeUsage (AttributeTargets.Property)]
+	public class ColumnAttribute : Attribute
+	{
+		public string Name { get; set; }
+
+		public ColumnAttribute (string name)
+		{
+			Name = name;
+		}
+	}
+
+	[AttributeUsage (AttributeTargets.Property)]
+	public class PrimaryKeyAttribute : Attribute
+	{
+	}
+
+	[AttributeUsage (AttributeTargets.Property)]
+	public class AutoIncrementAttribute : Attribute
+	{
+	}
+
+	[AttributeUsage (AttributeTargets.Property)]
+	public class IndexedAttribute : Attribute
+	{
+		public string Name { get; set; }
+		public int Order { get; set; }
+		public virtual bool Unique { get; set; }
+		
+		public IndexedAttribute()
+		{
+		}
+		
+		public IndexedAttribute(string name, int order)
+		{
+			Name = name;
+			Order = order;
+		}
+	}
+
+	[AttributeUsage (AttributeTargets.Property)]
+	public class IgnoreAttribute : Attribute
+	{
+	}
+
+	[AttributeUsage (AttributeTargets.Property)]
+	public class UniqueAttribute : IndexedAttribute
+	{
+		public override bool Unique {
+			get { return true; }
+			set { /* throw?  */ }
+		}
+
+		public UniqueAttribute() : base()
+		{
+		}
+
+		public UniqueAttribute(string name, int order) : base(name, order)
+		{
+		}
+	}
+
+	[AttributeUsage (AttributeTargets.Property)]
+	public class MaxLengthAttribute : Attribute
+	{
+		public int Value { get; private set; }
+
+		public MaxLengthAttribute (int length)
+		{
+			Value = length;
+		}
+	}
+
+	[AttributeUsage (AttributeTargets.Property)]
+	public class CollationAttribute: Attribute
+	{
+		public string Value { get; private set; }
+
+		public CollationAttribute (string collation)
+		{
+			Value = collation;
+		}
+	}
+
+	[AttributeUsage (AttributeTargets.Property)]
+	public class NotNullAttribute : Attribute
+	{
+	}
+
+	public class TableMapping
+	{
+		public Type MappedType { get; private set; }
+
+		public string TableName { get; private set; }
+
+		public Column[] Columns { get; private set; }
+
+		public Column PK { get; private set; }
+
+		public string GetByPrimaryKeySql { get; private set; }
+
+		Column _autoPk;
+		Column[] _insertColumns;
+		Column[] _insertOrReplaceColumns;
+
+		public TableMapping(Type type, CreateFlags createFlags = CreateFlags.None)
+		{
+			MappedType = type;
+
+#if NETFX_CORE
+			var tableAttr = (TableAttribute)System.Reflection.CustomAttributeExtensions
+				.GetCustomAttribute(type.GetTypeInfo(), typeof(TableAttribute), true);
+#else
+			var tableAttr = (TableAttribute)type.GetCustomAttributes (typeof (TableAttribute), true).FirstOrDefault ();
+#endif
+
+			TableName = tableAttr != null ? tableAttr.Name : MappedType.Name;
+
+#if !NETFX_CORE
+			var props = MappedType.GetProperties (BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty);
+#else
+			var props = from p in MappedType.GetRuntimeProperties()
+						where ((p.GetMethod != null && p.GetMethod.IsPublic) || (p.SetMethod != null && p.SetMethod.IsPublic) || (p.GetMethod != null && p.GetMethod.IsStatic) || (p.SetMethod != null && p.SetMethod.IsStatic))
+						select p;
+#endif
+			var cols = new List<Column> ();
+			foreach (var p in props) {
+#if !NETFX_CORE
+				var ignore = p.GetCustomAttributes (typeof(IgnoreAttribute), true).Length > 0;
+#else
+				var ignore = p.GetCustomAttributes (typeof(IgnoreAttribute), true).Count() > 0;
+#endif
+				if (p.CanWrite && !ignore) {
+					cols.Add (new Column (p, createFlags));
+				}
+			}
+			Columns = cols.ToArray ();
+			foreach (var c in Columns) {
+				if (c.IsAutoInc && c.IsPK) {
+					_autoPk = c;
+				}
+				if (c.IsPK) {
+					PK = c;
+				}
+			}
+			
+			HasAutoIncPK = _autoPk != null;
+
+			if (PK != null) {
+				GetByPrimaryKeySql = string.Format ("select * from \"{0}\" where \"{1}\" = ?", TableName, PK.Name);
+			}
+			else {
+				// People should not be calling Get/Find without a PK
+				GetByPrimaryKeySql = string.Format ("select * from \"{0}\" limit 1", TableName);
+			}
+		}
+
+		public bool HasAutoIncPK { get; private set; }
+
+		public void SetAutoIncPK (object obj, long id)
+		{
+			if (_autoPk != null) {
+				_autoPk.SetValue (obj, Convert.ChangeType (id, _autoPk.ColumnType, null));
+			}
+		}
+
+		public Column[] InsertColumns {
+			get {
+				if (_insertColumns == null) {
+					_insertColumns = Columns.Where (c => !c.IsAutoInc).ToArray ();
+				}
+				return _insertColumns;
+			}
+		}
+
+		public Column[] InsertOrReplaceColumns {
+			get {
+				if (_insertOrReplaceColumns == null) {
+					_insertOrReplaceColumns = Columns.ToArray ();
+				}
+				return _insertOrReplaceColumns;
+			}
+		}
+
+		public Column FindColumnWithPropertyName (string propertyName)
+		{
+			var exact = Columns.FirstOrDefault (c => c.PropertyName == propertyName);
+			return exact;
+		}
+
+		public Column FindColumn (string columnName)
+		{
+			var exact = Columns.FirstOrDefault (c => c.Name == columnName);
+			return exact;
+		}
+		
+		PreparedSqlLiteInsertCommand _insertCommand;
+		string _insertCommandExtra;
+
+		public PreparedSqlLiteInsertCommand GetInsertCommand(SQLiteConnection conn, string extra)
+		{
+			if (_insertCommand == null) {
+				_insertCommand = CreateInsertCommand(conn, extra);
+				_insertCommandExtra = extra;
+			}
+			else if (_insertCommandExtra != extra) {
+				_insertCommand.Dispose();
+				_insertCommand = CreateInsertCommand(conn, extra);
+				_insertCommandExtra = extra;
+			}
+			return _insertCommand;
+		}
+		
+		PreparedSqlLiteInsertCommand CreateInsertCommand(SQLiteConnection conn, string extra)
+		{
+			var cols = InsertColumns;
+			string insertSql;
+			if (!cols.Any() && Columns.Count() == 1 && Columns[0].IsAutoInc)
+			{
+				insertSql = string.Format("insert {1} into \"{0}\" default values", TableName, extra);
+			}
+			else
+			{
+				var replacing = string.Compare (extra, "OR REPLACE", StringComparison.OrdinalIgnoreCase) == 0;
+
+				if (replacing) {
+					cols = InsertOrReplaceColumns;
+				}
+
+				insertSql = string.Format("insert {3} into \"{0}\"({1}) values ({2})", TableName,
+								   string.Join(",", (from c in cols
+													 select "\"" + c.Name + "\"").ToArray()),
+								   string.Join(",", (from c in cols
+													 select "?").ToArray()), extra);
+				
+			}
+			
+			var insertCommand = new PreparedSqlLiteInsertCommand(conn);
+			insertCommand.CommandText = insertSql;
+			return insertCommand;
+		}
+		
+		protected internal void Dispose()
+		{
+			if (_insertCommand != null) {
+				_insertCommand.Dispose();
+				_insertCommand = null;
+			}
+		}
+
+		public class Column
+		{
+			PropertyInfo _prop;
+
+			public string Name { get; private set; }
+
+			public string PropertyName { get { return _prop.Name; } }
+
+			public Type ColumnType { get; private set; }
+
+			public string Collation { get; private set; }
+
+			public bool IsAutoInc { get; private set; }
+			public bool IsAutoGuid { get; private set; }
+
+			public bool IsPK { get; private set; }
+
+			public IEnumerable<IndexedAttribute> Indices { get; set; }
+
+			public bool IsNullable { get; private set; }
+
+			public int? MaxStringLength { get; private set; }
+
+			public Column(PropertyInfo prop, CreateFlags createFlags = CreateFlags.None)
+			{
+				var colAttr = (ColumnAttribute)prop.GetCustomAttributes(typeof(ColumnAttribute), true).FirstOrDefault();
+
+				_prop = prop;
+				Name = colAttr == null ? prop.Name : colAttr.Name;
+				//If this type is Nullable<T> then Nullable.GetUnderlyingType returns the T, otherwise it returns null, so get the actual type instead
+				ColumnType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
+				Collation = Orm.Collation(prop);
+
+				IsPK = Orm.IsPK(prop) ||
+					(((createFlags & CreateFlags.ImplicitPK) == CreateFlags.ImplicitPK) &&
+						string.Compare (prop.Name, Orm.ImplicitPkName, StringComparison.OrdinalIgnoreCase) == 0);
+
+				var isAuto = Orm.IsAutoInc(prop) || (IsPK && ((createFlags & CreateFlags.AutoIncPK) == CreateFlags.AutoIncPK));
+				IsAutoGuid = isAuto && ColumnType == typeof(Guid);
+				IsAutoInc = isAuto && !IsAutoGuid;
+
+				Indices = Orm.GetIndices(prop);
+				if (!Indices.Any()
+					&& !IsPK
+					&& ((createFlags & CreateFlags.ImplicitIndex) == CreateFlags.ImplicitIndex)
+					&& Name.EndsWith (Orm.ImplicitIndexSuffix, StringComparison.OrdinalIgnoreCase)
+					)
+				{
+					Indices = new IndexedAttribute[] { new IndexedAttribute() };
+				}
+				IsNullable = !(IsPK || Orm.IsMarkedNotNull(prop));
+				MaxStringLength = Orm.MaxStringLength(prop);
+			}
+
+			public void SetValue (object obj, object val)
+			{
+				_prop.SetValue (obj, val, null);
+			}
+
+			public object GetValue (object obj)
+			{
+				return _prop.GetGetMethod().Invoke(obj, null);
+			}
+		}
+	}
+
+	public static class Orm
+	{
+		public const int DefaultMaxStringLength = 140;
+		public const string ImplicitPkName = "Id";
+		public const string ImplicitIndexSuffix = "Id";
+
+		public static string SqlDecl (TableMapping.Column p, bool storeDateTimeAsTicks)
+		{
+			string decl = "\"" + p.Name + "\" " + SqlType (p, storeDateTimeAsTicks) + " ";
+			
+			if (p.IsPK) {
+				decl += "primary key ";
+			}
+			if (p.IsAutoInc) {
+				decl += "autoincrement ";
+			}
+			if (!p.IsNullable) {
+				decl += "not null ";
+			}
+			if (!string.IsNullOrEmpty (p.Collation)) {
+				decl += "collate " + p.Collation + " ";
+			}
+			
+			return decl;
+		}
+
+		public static string SqlType (TableMapping.Column p, bool storeDateTimeAsTicks)
+		{
+			var clrType = p.ColumnType;
+			if (clrType == typeof(Boolean) || clrType == typeof(Byte) || clrType == typeof(UInt16) || clrType == typeof(SByte) || clrType == typeof(Int16) || clrType == typeof(Int32)) {
+				return "integer";
+			} else if (clrType == typeof(UInt32) || clrType == typeof(Int64)) {
+				return "bigint";
+			} else if (clrType == typeof(Single) || clrType == typeof(Double) || clrType == typeof(Decimal)) {
+				return "float";
+			} else if (clrType == typeof(String)) {
+				int? len = p.MaxStringLength;
+
+				if (len.HasValue)
+					return "varchar(" + len.Value + ")";
+
+				return "varchar";
+			} else if (clrType == typeof(TimeSpan)) {
+				return "bigint";
+			} else if (clrType == typeof(DateTime)) {
+				return storeDateTimeAsTicks ? "bigint" : "datetime";
+			} else if (clrType == typeof(DateTimeOffset)) {
+				return "bigint";
+#if !NETFX_CORE
+			} else if (clrType.IsEnum) {
+#else
+			} else if (clrType.GetTypeInfo().IsEnum) {
+#endif
+				return "integer";
+			} else if (clrType == typeof(byte[])) {
+				return "blob";
+			} else if (clrType == typeof(Guid)) {
+				return "varchar(36)";
+			} else {
+				throw new NotSupportedException ("Don't know about " + clrType);
+			}
+		}
+
+		public static bool IsPK (MemberInfo p)
+		{
+			var attrs = p.GetCustomAttributes (typeof(PrimaryKeyAttribute), true);
+#if !NETFX_CORE
+			return attrs.Length > 0;
+#else
+			return attrs.Count() > 0;
+#endif
+		}
+
+		public static string Collation (MemberInfo p)
+		{
+			var attrs = p.GetCustomAttributes (typeof(CollationAttribute), true);
+#if !NETFX_CORE
+			if (attrs.Length > 0) {
+				return ((CollationAttribute)attrs [0]).Value;
+#else
+			if (attrs.Count() > 0) {
+				return ((CollationAttribute)attrs.First()).Value;
+#endif
+			} else {
+				return string.Empty;
+			}
+		}
+
+		public static bool IsAutoInc (MemberInfo p)
+		{
+			var attrs = p.GetCustomAttributes (typeof(AutoIncrementAttribute), true);
+#if !NETFX_CORE
+			return attrs.Length > 0;
+#else
+			return attrs.Count() > 0;
+#endif
+		}
+
+		public static IEnumerable<IndexedAttribute> GetIndices(MemberInfo p)
+		{
+			var attrs = p.GetCustomAttributes(typeof(IndexedAttribute), true);
+			return attrs.Cast<IndexedAttribute>();
+		}
+		
+		public static int? MaxStringLength(PropertyInfo p)
+		{
+			var attrs = p.GetCustomAttributes (typeof(MaxLengthAttribute), true);
+#if !NETFX_CORE
+			if (attrs.Length > 0)
+				return ((MaxLengthAttribute)attrs [0]).Value;
+#else
+			if (attrs.Count() > 0)
+				return ((MaxLengthAttribute)attrs.First()).Value;
+#endif
+
+			return null;
+		}
+
+		public static bool IsMarkedNotNull(MemberInfo p)
+		{
+			var attrs = p.GetCustomAttributes (typeof (NotNullAttribute), true);
+#if !NETFX_CORE
+			return attrs.Length > 0;
+#else
+	return attrs.Count() > 0;
+#endif
+		}
+	}
+
+	public partial class SQLiteCommand
+	{
+		SQLiteConnection _conn;
+		private List<Binding> _bindings;
+
+		public string CommandText { get; set; }
+
+		internal SQLiteCommand (SQLiteConnection conn)
+		{
+			_conn = conn;
+			_bindings = new List<Binding> ();
+			CommandText = "";
+		}
+
+		public int ExecuteNonQuery ()
+		{
+			if (_conn.Trace) {
+				_conn.InvokeTrace ("Executing: " + this);
+			}
+			
+			var r = SQLite3.Result.OK;
+			lock (_conn.SyncObject) {
+				var stmt = Prepare ();
+				r = SQLite3.Step (stmt);
+				Finalize(stmt);
+			}
+			if (r == SQLite3.Result.Done) {
+				int rowsAffected = SQLite3.Changes (_conn.Handle);
+				return rowsAffected;
+			} else if (r == SQLite3.Result.Error) {
+				string msg = SQLite3.GetErrmsg (_conn.Handle);
+				throw SQLiteException.New (r, msg);
+			}
+			else if (r == SQLite3.Result.Constraint) {
+				if (SQLite3.ExtendedErrCode (_conn.Handle) == SQLite3.ExtendedResult.ConstraintNotNull) {
+					throw NotNullConstraintViolationException.New (r, SQLite3.GetErrmsg (_conn.Handle));
+				}
+			}
+
+			throw SQLiteException.New(r, r.ToString());
+		}
+
+		public IEnumerable<T> ExecuteDeferredQuery<T> ()
+		{
+			return ExecuteDeferredQuery<T>(_conn.GetMapping(typeof(T)));
+		}
+
+		public List<T> ExecuteQuery<T> ()
+		{
+			return ExecuteDeferredQuery<T>(_conn.GetMapping(typeof(T))).ToList();
+		}
+
+		public List<T> ExecuteQuery<T> (TableMapping map)
+		{
+			return ExecuteDeferredQuery<T>(map).ToList();
+		}
+
+		/// <summary>
+		/// Invoked every time an instance is loaded from the database.
+		/// </summary>
+		/// <param name='obj'>
+		/// The newly created object.
+		/// </param>
+		/// <remarks>
+		/// This can be overridden in combination with the <see cref="SQLiteConnection.NewCommand"/>
+		/// method to hook into the life-cycle of objects.
+		///
+		/// Type safety is not possible because MonoTouch does not support virtual generic methods.
+		/// </remarks>
+		protected virtual void OnInstanceCreated (object obj)
+		{
+			// Can be overridden.
+		}
+
+		public IEnumerable<T> ExecuteDeferredQuery<T> (TableMapping map)
+		{
+			if (_conn.Trace) {
+				_conn.InvokeTrace ("Executing Query: " + this);
+			}
+
+			lock (_conn.SyncObject) {
+				var stmt = Prepare ();
+				try {
+					var cols = new TableMapping.Column[SQLite3.ColumnCount (stmt)];
+
+					for (int i = 0; i < cols.Length; i++) {
+						var name = SQLite3.ColumnName16 (stmt, i);
+						cols [i] = map.FindColumn (name);
+					}
+			
+					while (SQLite3.Step (stmt) == SQLite3.Result.Row) {
+						var obj = Activator.CreateInstance(map.MappedType);
+						for (int i = 0; i < cols.Length; i++) {
+							if (cols [i] == null)
+								continue;
+							var colType = SQLite3.ColumnType (stmt, i);
+							var val = ReadCol (stmt, i, colType, cols [i].ColumnType);
+							cols [i].SetValue (obj, val);
+						}
+						OnInstanceCreated (obj);
+						yield return (T)obj;
+					}
+				} finally {
+					SQLite3.Finalize(stmt);
+				}
+			}
+		}
+
+		public T ExecuteScalar<T> ()
+		{
+			if (_conn.Trace) {
+				_conn.InvokeTrace ("Executing Query: " + this);
+			}
+			
+			T val = default(T);
+			
+			lock (_conn.SyncObject) {
+				var stmt = Prepare();
+
+				try {
+					var r = SQLite3.Step (stmt);
+					if (r == SQLite3.Result.Row) {
+						var colType = SQLite3.ColumnType (stmt, 0);
+						val = (T)ReadCol (stmt, 0, colType, typeof(T));
+					}
+					else if (r == SQLite3.Result.Done) {
+					}
+					else
+					{
+						throw SQLiteException.New (r, SQLite3.GetErrmsg (_conn.Handle));
+					}
+				} finally {
+					Finalize (stmt);
+				}
+			}
+			
+			return val;
+		}
+
+		public void Bind (string name, object val)
+		{
+			_bindings.Add (new Binding {
+				Name = name,
+				Value = val
+			});
+		}
+
+		public void Bind (object val)
+		{
+			Bind (null, val);
+		}
+
+		public override string ToString ()
+		{
+			var parts = new string[1 + _bindings.Count];
+			parts [0] = CommandText;
+			var i = 1;
+			foreach (var b in _bindings) {
+				parts [i] = string.Format ("  {0}: {1}", i - 1, b.Value);
+				i++;
+			}
+			return string.Join (Environment.NewLine, parts);
+		}
+
+		Sqlite3Statement Prepare()
+		{
+			var stmt = SQLite3.Prepare2 (_conn.Handle, CommandText);
+			BindAll (stmt);
+			return stmt;
+		}
+
+		void Finalize (Sqlite3Statement stmt)
+		{
+			SQLite3.Finalize (stmt);
+		}
+
+		void BindAll (Sqlite3Statement stmt)
+		{
+			int nextIdx = 1;
+			foreach (var b in _bindings) {
+				if (b.Name != null) {
+					b.Index = SQLite3.BindParameterIndex (stmt, b.Name);
+				} else {
+					b.Index = nextIdx++;
+				}
+				
+				BindParameter (stmt, b.Index, b.Value, _conn.StoreDateTimeAsTicks);
+			}
+		}
+
+		internal static IntPtr NegativePointer = new IntPtr (-1);
+
+		internal static void BindParameter (Sqlite3Statement stmt, int index, object value, bool storeDateTimeAsTicks)
+		{
+			if (value == null) {
+				SQLite3.BindNull (stmt, index);
+			} else {
+				if (value is Int32) {
+					SQLite3.BindInt (stmt, index, (int)value);
+				} else if (value is String) {
+					SQLite3.BindText (stmt, index, (string)value, -1, NegativePointer);
+				} else if (value is Byte || value is UInt16 || value is SByte || value is Int16) {
+					SQLite3.BindInt (stmt, index, Convert.ToInt32 (value));
+				} else if (value is Boolean) {
+					SQLite3.BindInt (stmt, index, (bool)value ? 1 : 0);
+				} else if (value is UInt32 || value is Int64) {
+					SQLite3.BindInt64 (stmt, index, Convert.ToInt64 (value));
+				} else if (value is Single || value is Double || value is Decimal) {
+					SQLite3.BindDouble (stmt, index, Convert.ToDouble (value));
+				} else if (value is TimeSpan) {
+					SQLite3.BindInt64(stmt, index, ((TimeSpan)value).Ticks);
+				} else if (value is DateTime) {
+					if (storeDateTimeAsTicks) {
+						SQLite3.BindInt64 (stmt, index, ((DateTime)value).Ticks);
+					}
+					else {
+						SQLite3.BindText (stmt, index, ((DateTime)value).ToString ("yyyy-MM-dd HH:mm:ss"), -1, NegativePointer);
+					}
+				} else if (value is DateTimeOffset) {
+					SQLite3.BindInt64 (stmt, index, ((DateTimeOffset)value).UtcTicks);
+#if !NETFX_CORE
+				} else if (value.GetType().IsEnum) {
+#else
+				} else if (value.GetType().GetTypeInfo().IsEnum) {
+#endif
+					SQLite3.BindInt (stmt, index, Convert.ToInt32 (value));
+				} else if (value is byte[]){
+					SQLite3.BindBlob(stmt, index, (byte[]) value, ((byte[]) value).Length, NegativePointer);
+				} else if (value is Guid) {
+					SQLite3.BindText(stmt, index, ((Guid)value).ToString(), 72, NegativePointer);
+				} else {
+					throw new NotSupportedException("Cannot store type: " + value.GetType());
+				}
+			}
+		}
+
+		class Binding
+		{
+			public string Name { get; set; }
+
+			public object Value { get; set; }
+
+			public int Index { get; set; }
+		}
+
+		object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColType type, Type clrType)
+		{
+			if (type == SQLite3.ColType.Null) {
+				return null;
+			} else {
+				if (clrType == typeof(String)) {
+					return SQLite3.ColumnString (stmt, index);
+				} else if (clrType == typeof(Int32)) {
+					return (int)SQLite3.ColumnInt (stmt, index);
+				} else if (clrType == typeof(Boolean)) {
+					return SQLite3.ColumnInt (stmt, index) == 1;
+				} else if (clrType == typeof(double)) {
+					return SQLite3.ColumnDouble (stmt, index);
+				} else if (clrType == typeof(float)) {
+					return (float)SQLite3.ColumnDouble (stmt, index);
+				} else if (clrType == typeof(TimeSpan)) {
+					return new TimeSpan(SQLite3.ColumnInt64(stmt, index));
+				} else if (clrType == typeof(DateTime)) {
+					if (_conn.StoreDateTimeAsTicks) {
+						return new DateTime (SQLite3.ColumnInt64 (stmt, index));
+					}
+					else {
+						var text = SQLite3.ColumnString (stmt, index);
+						return DateTime.Parse (text);
+					}
+				} else if (clrType == typeof(DateTimeOffset)) {
+					return new DateTimeOffset(SQLite3.ColumnInt64 (stmt, index),TimeSpan.Zero);
+#if !NETFX_CORE
+				} else if (clrType.IsEnum) {
+#else
+				} else if (clrType.GetTypeInfo().IsEnum) {
+#endif
+					return SQLite3.ColumnInt (stmt, index);
+				} else if (clrType == typeof(Int64)) {
+					return SQLite3.ColumnInt64 (stmt, index);
+				} else if (clrType == typeof(UInt32)) {
+					return (uint)SQLite3.ColumnInt64 (stmt, index);
+				} else if (clrType == typeof(decimal)) {
+					return (decimal)SQLite3.ColumnDouble (stmt, index);
+				} else if (clrType == typeof(Byte)) {
+					return (byte)SQLite3.ColumnInt (stmt, index);
+				} else if (clrType == typeof(UInt16)) {
+					return (ushort)SQLite3.ColumnInt (stmt, index);
+				} else if (clrType == typeof(Int16)) {
+					return (short)SQLite3.ColumnInt (stmt, index);
+				} else if (clrType == typeof(sbyte)) {
+					return (sbyte)SQLite3.ColumnInt (stmt, index);
+				} else if (clrType == typeof(byte[])) {
+					return SQLite3.ColumnByteArray (stmt, index);
+				} else if (clrType == typeof(Guid)) {
+				  var text = SQLite3.ColumnString(stmt, index);
+				  return new Guid(text);
+				} else{
+					throw new NotSupportedException ("Don't know how to read " + clrType);
+				}
+			}
+		}
+	}
+
+	/// <summary>
+	/// Since the insert never changed, we only need to prepare once.
+	/// </summary>
+	public class PreparedSqlLiteInsertCommand : IDisposable
+	{
+		public bool Initialized { get; set; }
+
+		protected SQLiteConnection Connection { get; set; }
+
+		public string CommandText { get; set; }
+
+		protected Sqlite3Statement Statement { get; set; }
+		internal static readonly Sqlite3Statement NullStatement = default(Sqlite3Statement);
+
+		internal PreparedSqlLiteInsertCommand (SQLiteConnection conn)
+		{
+			Connection = conn;
+		}
+
+		public int ExecuteNonQuery (object[] source)
+		{
+			if (Connection.Trace) {
+				Connection.InvokeTrace ("Executing: " + CommandText);
+			}
+
+			var r = SQLite3.Result.OK;
+
+			if (!Initialized) {
+				Statement = Prepare ();
+				Initialized = true;
+			}
+
+			//bind the values.
+			if (source != null) {
+				for (int i = 0; i < source.Length; i++) {
+					SQLiteCommand.BindParameter (Statement, i + 1, source [i], Connection.StoreDateTimeAsTicks);
+				}
+			}
+			r = SQLite3.Step (Statement);
+
+			if (r == SQLite3.Result.Done) {
+				int rowsAffected = SQLite3.Changes (Connection.Handle);
+				SQLite3.Reset (Statement);
+				return rowsAffected;
+			} else if (r == SQLite3.Result.Error) {
+				string msg = SQLite3.GetErrmsg (Connection.Handle);
+				SQLite3.Reset (Statement);
+				throw SQLiteException.New (r, msg);
+			} else if (r == SQLite3.Result.Constraint && SQLite3.ExtendedErrCode (Connection.Handle) == SQLite3.ExtendedResult.ConstraintNotNull) {
+				SQLite3.Reset (Statement);
+				throw NotNullConstraintViolationException.New (r, SQLite3.GetErrmsg (Connection.Handle));
+			} else {
+				SQLite3.Reset (Statement);
+				throw SQLiteException.New (r, r.ToString ());
+			}
+		}
+
+		protected virtual Sqlite3Statement Prepare ()
+		{
+			var stmt = SQLite3.Prepare2 (Connection.Handle, CommandText);
+			return stmt;
+		}
+
+		public void Dispose ()
+		{
+			Dispose (true);
+			GC.SuppressFinalize (this);
+		}
+
+		private void Dispose (bool disposing)
+		{
+			if (Statement != NullStatement) {
+				try {
+					SQLite3.Finalize (Statement);
+				} finally {
+					Statement = NullStatement;
+					Connection = null;
+				}
+			}
+		}
+
+		~PreparedSqlLiteInsertCommand ()
+		{
+			Dispose (false);
+		}
+	}
+
+	public abstract class BaseTableQuery
+	{
+		protected class Ordering
+		{
+			public string ColumnName { get; set; }
+			public bool Ascending { get; set; }
+		}
+	}
+
+	public class TableQuery<T> : BaseTableQuery, IEnumerable<T>
+	{
+		public SQLiteConnection Connection { get; private set; }
+
+		public TableMapping Table { get; private set; }
+
+		Expression _where;
+		List<Ordering> _orderBys;
+		int? _limit;
+		int? _offset;
+
+		BaseTableQuery _joinInner;
+		Expression _joinInnerKeySelector;
+		BaseTableQuery _joinOuter;
+		Expression _joinOuterKeySelector;
+		Expression _joinSelector;
+				
+		Expression _selector;
+
+		TableQuery (SQLiteConnection conn, TableMapping table)
+		{
+			Connection = conn;
+			Table = table;
+		}
+
+		public TableQuery (SQLiteConnection conn)
+		{
+			Connection = conn;
+			Table = Connection.GetMapping (typeof(T));
+		}
+
+		public TableQuery<U> Clone<U> ()
+		{
+			var q = new TableQuery<U> (Connection, Table);
+			q._where = _where;
+			q._deferred = _deferred;
+			if (_orderBys != null) {
+				q._orderBys = new List<Ordering> (_orderBys);
+			}
+			q._limit = _limit;
+			q._offset = _offset;
+			q._joinInner = _joinInner;
+			q._joinInnerKeySelector = _joinInnerKeySelector;
+			q._joinOuter = _joinOuter;
+			q._joinOuterKeySelector = _joinOuterKeySelector;
+			q._joinSelector = _joinSelector;
+			q._selector = _selector;
+			return q;
+		}
+
+		public TableQuery<T> Where (Expression<Func<T, bool>> predExpr)
+		{
+			if (predExpr.NodeType == ExpressionType.Lambda) {
+				var lambda = (LambdaExpression)predExpr;
+				var pred = lambda.Body;
+				var q = Clone<T> ();
+				q.AddWhere (pred);
+				return q;
+			} else {
+				throw new NotSupportedException ("Must be a predicate");
+			}
+		}
+
+		public TableQuery<T> Take (int n)
+		{
+			var q = Clone<T> ();
+			q._limit = n;
+			return q;
+		}
+
+		public TableQuery<T> Skip (int n)
+		{
+			var q = Clone<T> ();
+			q._offset = n;
+			return q;
+		}
+
+		public T ElementAt (int index)
+		{
+			return Skip (index).Take (1).First ();
+		}
+
+		bool _deferred;
+		public TableQuery<T> Deferred ()
+		{
+			var q = Clone<T> ();
+			q._deferred = true;
+			return q;
+		}
+
+		public TableQuery<T> OrderBy<U> (Expression<Func<T, U>> orderExpr)
+		{
+			return AddOrderBy<U> (orderExpr, true);
+		}
+
+		public TableQuery<T> OrderByDescending<U> (Expression<Func<T, U>> orderExpr)
+		{
+			return AddOrderBy<U> (orderExpr, false);
+		}
+
+		public TableQuery<T> ThenBy<U>(Expression<Func<T, U>> orderExpr)
+		{
+			return AddOrderBy<U>(orderExpr, true);
+		}
+
+		public TableQuery<T> ThenByDescending<U>(Expression<Func<T, U>> orderExpr)
+		{
+			return AddOrderBy<U>(orderExpr, false);
+		}
+
+		private TableQuery<T> AddOrderBy<U> (Expression<Func<T, U>> orderExpr, bool asc)
+		{
+			if (orderExpr.NodeType == ExpressionType.Lambda) {
+				var lambda = (LambdaExpression)orderExpr;
+				
+				MemberExpression mem = null;
+				
+				var unary = lambda.Body as UnaryExpression;
+				if (unary != null && unary.NodeType == ExpressionType.Convert) {
+					mem = unary.Operand as MemberExpression;
+				}
+				else {
+					mem = lambda.Body as MemberExpression;
+				}
+				
+				if (mem != null && (mem.Expression.NodeType == ExpressionType.Parameter)) {
+					var q = Clone<T> ();
+					if (q._orderBys == null) {
+						q._orderBys = new List<Ordering> ();
+					}
+					q._orderBys.Add (new Ordering {
+						ColumnName = Table.FindColumnWithPropertyName(mem.Member.Name).Name,
+						Ascending = asc
+					});
+					return q;
+				} else {
+					throw new NotSupportedException ("Order By does not support: " + orderExpr);
+				}
+			} else {
+				throw new NotSupportedException ("Must be a predicate");
+			}
+		}
+
+		private void AddWhere (Expression pred)
+		{
+			if (_where == null) {
+				_where = pred;
+			} else {
+				_where = Expression.AndAlso (_where, pred);
+			}
+		}
+				
+		public TableQuery<TResult> Join<TInner, TKey, TResult> (
+			TableQuery<TInner> inner,
+			Expression<Func<T, TKey>> outerKeySelector,
+			Expression<Func<TInner, TKey>> innerKeySelector,
+			Expression<Func<T, TInner, TResult>> resultSelector)
+		{
+			var q = new TableQuery<TResult> (Connection, Connection.GetMapping (typeof (TResult))) {
+				_joinOuter = this,
+				_joinOuterKeySelector = outerKeySelector,
+				_joinInner = inner,
+				_joinInnerKeySelector = innerKeySelector,
+				_joinSelector = resultSelector,
+			};
+			return q;
+		}
+				
+		public TableQuery<TResult> Select<TResult> (Expression<Func<T, TResult>> selector)
+		{
+			var q = Clone<TResult> ();
+			q._selector = selector;
+			return q;
+		}
+
+		private SQLiteCommand GenerateCommand (string selectionList)
+		{
+			if (_joinInner != null && _joinOuter != null) {
+				throw new NotSupportedException ("Joins are not supported.");
+			}
+			else {
+				var cmdText = "select " + selectionList + " from \"" + Table.TableName + "\"";
+				var args = new List<object> ();
+				if (_where != null) {
+					var w = CompileExpr (_where, args);
+					cmdText += " where " + w.CommandText;
+				}
+				if ((_orderBys != null) && (_orderBys.Count > 0)) {
+					var t = string.Join (", ", _orderBys.Select (o => "\"" + o.ColumnName + "\"" + (o.Ascending ? "" : " desc")).ToArray ());
+					cmdText += " order by " + t;
+				}
+				if (_limit.HasValue) {
+					cmdText += " limit " + _limit.Value;
+				}
+				if (_offset.HasValue) {
+					if (!_limit.HasValue) {
+						cmdText += " limit -1 ";
+					}
+					cmdText += " offset " + _offset.Value;
+				}
+				return Connection.CreateCommand (cmdText, args.ToArray ());
+			}
+		}
+
+		class CompileResult
+		{
+			public string CommandText { get; set; }
+
+			public object Value { get; set; }
+		}
+
+		private CompileResult CompileExpr (Expression expr, List<object> queryArgs)
+		{
+			if (expr == null) {
+				throw new NotSupportedException ("Expression is NULL");
+			} else if (expr is BinaryExpression) {
+				var bin = (BinaryExpression)expr;
+				
+				var leftr = CompileExpr (bin.Left, queryArgs);
+				var rightr = CompileExpr (bin.Right, queryArgs);
+
+				//If either side is a parameter and is null, then handle the other side specially (for "is null"/"is not null")
+				string text;
+				if (leftr.CommandText == "?" && leftr.Value == null)
+					text = CompileNullBinaryExpression(bin, rightr);
+				else if (rightr.CommandText == "?" && rightr.Value == null)
+					text = CompileNullBinaryExpression(bin, leftr);
+				else
+					text = "(" + leftr.CommandText + " " + GetSqlName(bin) + " " + rightr.CommandText + ")";
+				return new CompileResult { CommandText = text };
+			} else if (expr.NodeType == ExpressionType.Call) {
+				
+				var call = (MethodCallExpression)expr;
+				var args = new CompileResult[call.Arguments.Count];
+				var obj = call.Object != null ? CompileExpr (call.Object, queryArgs) : null;
+				
+				for (var i = 0; i < args.Length; i++) {
+					args [i] = CompileExpr (call.Arguments [i], queryArgs);
+				}
+				
+				var sqlCall = "";
+				
+				if (call.Method.Name == "Like" && args.Length == 2) {
+					sqlCall = "(" + args [0].CommandText + " like " + args [1].CommandText + ")";
+				}
+				else if (call.Method.Name == "Contains" && args.Length == 2) {
+					sqlCall = "(" + args [1].CommandText + " in " + args [0].CommandText + ")";
+				}
+				else if (call.Method.Name == "Contains" && args.Length == 1) {
+					if (call.Object != null && call.Object.Type == typeof(string)) {
+						sqlCall = "(" + obj.CommandText + " like ('%' || " + args [0].CommandText + " || '%'))";
+					}
+					else {
+						sqlCall = "(" + args [0].CommandText + " in " + obj.CommandText + ")";
+					}
+				}
+				else if (call.Method.Name == "StartsWith" && args.Length == 1) {
+					sqlCall = "(" + obj.CommandText + " like (" + args [0].CommandText + " || '%'))";
+				}
+				else if (call.Method.Name == "EndsWith" && args.Length == 1) {
+					sqlCall = "(" + obj.CommandText + " like ('%' || " + args [0].CommandText + "))";
+				}
+				else if (call.Method.Name == "Equals" && args.Length == 1) {
+					sqlCall = "(" + obj.CommandText + " = (" + args[0].CommandText + "))";
+				} else if (call.Method.Name == "ToLower") {
+					sqlCall = "(lower(" + obj.CommandText + "))"; 
+				} else if (call.Method.Name == "ToUpper") {
+					sqlCall = "(upper(" + obj.CommandText + "))"; 
+				} else {
+					sqlCall = call.Method.Name.ToLower () + "(" + string.Join (",", args.Select (a => a.CommandText).ToArray ()) + ")";
+				}
+				return new CompileResult { CommandText = sqlCall };
+				
+			} else if (expr.NodeType == ExpressionType.Constant) {
+				var c = (ConstantExpression)expr;
+				queryArgs.Add (c.Value);
+				return new CompileResult {
+					CommandText = "?",
+					Value = c.Value
+				};
+			} else if (expr.NodeType == ExpressionType.Convert) {
+				var u = (UnaryExpression)expr;
+				var ty = u.Type;
+				var valr = CompileExpr (u.Operand, queryArgs);
+				return new CompileResult {
+					CommandText = valr.CommandText,
+					Value = valr.Value != null ? ConvertTo (valr.Value, ty) : null
+				};
+			} else if (expr.NodeType == ExpressionType.Not) {
+				var u = (UnaryExpression)expr;
+				var ty = u.Type;
+				var valr = CompileExpr (u.Operand, queryArgs);
+
+				return new CompileResult {
+					CommandText = "NOT " + valr.CommandText,
+					Value = valr.Value != null ? valr.Value : null
+				};
+			} else if (expr.NodeType == ExpressionType.MemberAccess) {
+				var mem = (MemberExpression)expr;
+				
+				if (mem.Expression!=null && mem.Expression.NodeType == ExpressionType.Parameter) {
+					//
+					// This is a column of our table, output just the column name
+					// Need to translate it if that column name is mapped
+					//
+					var columnName = Table.FindColumnWithPropertyName (mem.Member.Name).Name;
+					return new CompileResult { CommandText = "\"" + columnName + "\"" };
+				} else {
+					object obj = null;
+					if (mem.Expression != null) {
+						var r = CompileExpr (mem.Expression, queryArgs);
+						if (r.Value == null) {
+							throw new NotSupportedException ("Member access failed to compile expression");
+						}
+						if (r.CommandText == "?") {
+							queryArgs.RemoveAt (queryArgs.Count - 1);
+						}
+						obj = r.Value;
+					}
+					
+					//
+					// Get the member value
+					//
+					object val = null;
+					
+#if !NETFX_CORE
+					if (mem.Member.MemberType == MemberTypes.Property) {
+#else
+					if (mem.Member is PropertyInfo) {
+#endif
+						var m = (PropertyInfo)mem.Member;
+						//val = m.GetValue (obj, null);
+						val = m.GetGetMethod().Invoke(obj, null);
+#if !NETFX_CORE
+					} else if (mem.Member.MemberType == MemberTypes.Field) {
+#else
+					} else if (mem.Member is FieldInfo) {
+#endif
+#if SILVERLIGHT
+						val = Expression.Lambda (expr).Compile ().DynamicInvoke ();
+#else
+						var m = (FieldInfo)mem.Member;
+						val = m.GetValue (obj);
+#endif
+					} else {
+#if !NETFX_CORE
+						throw new NotSupportedException ("MemberExpr: " + mem.Member.MemberType);
+#else
+						throw new NotSupportedException ("MemberExpr: " + mem.Member.DeclaringType);
+#endif
+					}
+					
+					//
+					// Work special magic for enumerables
+					//
+					if (val != null && val is System.Collections.IEnumerable && !(val is string) && !(val is System.Collections.Generic.IEnumerable<byte>)) {
+						var sb = new System.Text.StringBuilder();
+						sb.Append("(");
+						var head = "";
+						foreach (var a in (System.Collections.IEnumerable)val) {
+							queryArgs.Add(a);
+							sb.Append(head);
+							sb.Append("?");
+							head = ",";
+						}
+						sb.Append(")");
+						return new CompileResult {
+							CommandText = sb.ToString(),
+							Value = val
+						};
+					}
+					else {
+						queryArgs.Add (val);
+						return new CompileResult {
+							CommandText = "?",
+							Value = val
+						};
+					}
+				}
+			}
+			throw new NotSupportedException ("Cannot compile: " + expr.NodeType.ToString ());
+		}
+
+		static object ConvertTo (object obj, Type t)
+		{
+			Type nut = Nullable.GetUnderlyingType(t);
+			
+			if (nut != null) {
+				if (obj == null) return null;				
+				return Convert.ChangeType (obj, nut);
+			} else {
+				return Convert.ChangeType (obj, t);
+			}
+		}
+
+		/// <summary>
+		/// Compiles a BinaryExpression where one of the parameters is null.
+		/// </summary>
+		/// <param name="parameter">The non-null parameter</param>
+		private string CompileNullBinaryExpression(BinaryExpression expression, CompileResult parameter)
+		{
+			if (expression.NodeType == ExpressionType.Equal)
+				return "(" + parameter.CommandText + " is ?)";
+			else if (expression.NodeType == ExpressionType.NotEqual)
+				return "(" + parameter.CommandText + " is not ?)";
+			else
+				throw new NotSupportedException("Cannot compile Null-BinaryExpression with type " + expression.NodeType.ToString());
+		}
+
+		string GetSqlName (Expression expr)
+		{
+			var n = expr.NodeType;
+			if (n == ExpressionType.GreaterThan)
+				return ">"; else if (n == ExpressionType.GreaterThanOrEqual) {
+				return ">=";
+			} else if (n == ExpressionType.LessThan) {
+				return "<";
+			} else if (n == ExpressionType.LessThanOrEqual) {
+				return "<=";
+			} else if (n == ExpressionType.And) {
+				return "&";
+			} else if (n == ExpressionType.AndAlso) {
+				return "and";
+			} else if (n == ExpressionType.Or) {
+				return "|";
+			} else if (n == ExpressionType.OrElse) {
+				return "or";
+			} else if (n == ExpressionType.Equal) {
+				return "=";
+			} else if (n == ExpressionType.NotEqual) {
+				return "!=";
+			} else {
+				throw new NotSupportedException ("Cannot get SQL for: " + n);
+			}
+		}
+		
+		public int Count ()
+		{
+			return GenerateCommand("count(*)").ExecuteScalar<int> ();			
+		}
+
+		public int Count (Expression<Func<T, bool>> predExpr)
+		{
+			return Where (predExpr).Count ();
+		}
+
+		public IEnumerator<T> GetEnumerator ()
+		{
+			if (!_deferred)
+				return GenerateCommand("*").ExecuteQuery<T>().GetEnumerator();
+
+			return GenerateCommand("*").ExecuteDeferredQuery<T>().GetEnumerator();
+		}
+
+		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
+		{
+			return GetEnumerator ();
+		}
+
+		public T First ()
+		{
+			var query = Take (1);
+			return query.ToList<T>().First ();
+		}
+
+		public T FirstOrDefault ()
+		{
+			var query = Take (1);
+			return query.ToList<T>().FirstOrDefault ();
+		}
+	}
+
+	public static class SQLite3
+	{
+		public enum Result : int
+		{
+			OK = 0,
+			Error = 1,
+			Internal = 2,
+			Perm = 3,
+			Abort = 4,
+			Busy = 5,
+			Locked = 6,
+			NoMem = 7,
+			ReadOnly = 8,
+			Interrupt = 9,
+			IOError = 10,
+			Corrupt = 11,
+			NotFound = 12,
+			Full = 13,
+			CannotOpen = 14,
+			LockErr = 15,
+			Empty = 16,
+			SchemaChngd = 17,
+			TooBig = 18,
+			Constraint = 19,
+			Mismatch = 20,
+			Misuse = 21,
+			NotImplementedLFS = 22,
+			AccessDenied = 23,
+			Format = 24,
+			Range = 25,
+			NonDBFile = 26,
+			Notice = 27,
+			Warning = 28,
+			Row = 100,
+			Done = 101
+		}
+
+		public enum ExtendedResult : int
+		{
+			IOErrorRead = (Result.IOError | (1 << 8)),
+			IOErrorShortRead = (Result.IOError | (2 << 8)),
+			IOErrorWrite = (Result.IOError | (3 << 8)),
+			IOErrorFsync = (Result.IOError | (4 << 8)),
+			IOErrorDirFSync = (Result.IOError | (5 << 8)),
+			IOErrorTruncate = (Result.IOError | (6 << 8)),
+			IOErrorFStat = (Result.IOError | (7 << 8)),
+			IOErrorUnlock = (Result.IOError | (8 << 8)),
+			IOErrorRdlock = (Result.IOError | (9 << 8)),
+			IOErrorDelete = (Result.IOError | (10 << 8)),
+			IOErrorBlocked = (Result.IOError | (11 << 8)),
+			IOErrorNoMem = (Result.IOError | (12 << 8)),
+			IOErrorAccess = (Result.IOError | (13 << 8)),
+			IOErrorCheckReservedLock = (Result.IOError | (14 << 8)),
+			IOErrorLock = (Result.IOError | (15 << 8)),
+			IOErrorClose = (Result.IOError | (16 << 8)),
+			IOErrorDirClose = (Result.IOError | (17 << 8)),
+			IOErrorSHMOpen = (Result.IOError | (18 << 8)),
+			IOErrorSHMSize = (Result.IOError | (19 << 8)),
+			IOErrorSHMLock = (Result.IOError | (20 << 8)),
+			IOErrorSHMMap = (Result.IOError | (21 << 8)),
+			IOErrorSeek = (Result.IOError | (22 << 8)),
+			IOErrorDeleteNoEnt = (Result.IOError | (23 << 8)),
+			IOErrorMMap = (Result.IOError | (24 << 8)),
+			LockedSharedcache = (Result.Locked | (1 << 8)),
+			BusyRecovery = (Result.Busy | (1 << 8)),
+			CannottOpenNoTempDir = (Result.CannotOpen | (1 << 8)),
+			CannotOpenIsDir = (Result.CannotOpen | (2 << 8)),
+			CannotOpenFullPath = (Result.CannotOpen | (3 << 8)),
+			CorruptVTab = (Result.Corrupt | (1 << 8)),
+			ReadonlyRecovery = (Result.ReadOnly | (1 << 8)),
+			ReadonlyCannotLock = (Result.ReadOnly | (2 << 8)),
+			ReadonlyRollback = (Result.ReadOnly | (3 << 8)),
+			AbortRollback = (Result.Abort | (2 << 8)),
+			ConstraintCheck = (Result.Constraint | (1 << 8)),
+			ConstraintCommitHook = (Result.Constraint | (2 << 8)),
+			ConstraintForeignKey = (Result.Constraint | (3 << 8)),
+			ConstraintFunction = (Result.Constraint | (4 << 8)),
+			ConstraintNotNull = (Result.Constraint | (5 << 8)),
+			ConstraintPrimaryKey = (Result.Constraint | (6 << 8)),
+			ConstraintTrigger = (Result.Constraint | (7 << 8)),
+			ConstraintUnique = (Result.Constraint | (8 << 8)),
+			ConstraintVTab = (Result.Constraint | (9 << 8)),
+			NoticeRecoverWAL = (Result.Notice | (1 << 8)),
+			NoticeRecoverRollback = (Result.Notice | (2 << 8))
+		}
+		
+
+		public enum ConfigOption : int
+		{
+			SingleThread = 1,
+			MultiThread = 2,
+			Serialized = 3
+		}
+
+#if !USE_CSHARP_SQLITE && !USE_WP8_NATIVE_SQLITE
+		[DllImport("sqlite3", EntryPoint = "sqlite3_open", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result Open ([MarshalAs(UnmanagedType.LPStr)] string filename, out IntPtr db);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_open_v2", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result Open ([MarshalAs(UnmanagedType.LPStr)] string filename, out IntPtr db, int flags, IntPtr zvfs);
+		
+		[DllImport("sqlite3", EntryPoint = "sqlite3_open_v2", CallingConvention = CallingConvention.Cdecl)]
+		public static extern Result Open(byte[] filename, out IntPtr db, int flags, IntPtr zvfs);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_open16", CallingConvention = CallingConvention.Cdecl)]
+		public static extern Result Open16([MarshalAs(UnmanagedType.LPWStr)] string filename, out IntPtr db);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_enable_load_extension", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result EnableLoadExtension (IntPtr db, int onoff);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_close", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result Close (IntPtr db);
+		
+		[DllImport("sqlite3", EntryPoint = "sqlite3_initialize", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result Initialize();
+						
+		[DllImport("sqlite3", EntryPoint = "sqlite3_shutdown", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result Shutdown();
+		
+		[DllImport("sqlite3", EntryPoint = "sqlite3_config", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result Config (ConfigOption option);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_win32_set_directory", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Unicode)]
+		public static extern int SetDirectory (uint directoryType, string directoryPath);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_busy_timeout", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result BusyTimeout (IntPtr db, int milliseconds);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_changes", CallingConvention=CallingConvention.Cdecl)]
+		public static extern int Changes (IntPtr db);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_prepare_v2", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result Prepare2 (IntPtr db, [MarshalAs(UnmanagedType.LPStr)] string sql, int numBytes, out IntPtr stmt, IntPtr pzTail);
+
+#if NETFX_CORE
+		[DllImport ("sqlite3", EntryPoint = "sqlite3_prepare_v2", CallingConvention = CallingConvention.Cdecl)]
+		public static extern Result Prepare2 (IntPtr db, byte[] queryBytes, int numBytes, out IntPtr stmt, IntPtr pzTail);
+#endif
+
+		public static IntPtr Prepare2 (IntPtr db, string query)
+		{
+			IntPtr stmt;
+#if NETFX_CORE
+			byte[] queryBytes = System.Text.UTF8Encoding.UTF8.GetBytes (query);
+			var r = Prepare2 (db, queryBytes, queryBytes.Length, out stmt, IntPtr.Zero);
+#else
+			var r = Prepare2 (db, query, System.Text.UTF8Encoding.UTF8.GetByteCount (query), out stmt, IntPtr.Zero);
+#endif
+			if (r != Result.OK) {
+				throw SQLiteException.New (r, GetErrmsg (db));
+			}
+			return stmt;
+		}
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_step", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result Step (IntPtr stmt);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_reset", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result Reset (IntPtr stmt);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_finalize", CallingConvention=CallingConvention.Cdecl)]
+		public static extern Result Finalize (IntPtr stmt);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_last_insert_rowid", CallingConvention=CallingConvention.Cdecl)]
+		public static extern long LastInsertRowid (IntPtr db);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_errmsg16", CallingConvention=CallingConvention.Cdecl)]
+		public static extern IntPtr Errmsg (IntPtr db);
+
+		public static string GetErrmsg (IntPtr db)
+		{
+			return Marshal.PtrToStringUni (Errmsg (db));
+		}
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_bind_parameter_index", CallingConvention=CallingConvention.Cdecl)]
+		public static extern int BindParameterIndex (IntPtr stmt, [MarshalAs(UnmanagedType.LPStr)] string name);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_bind_null", CallingConvention=CallingConvention.Cdecl)]
+		public static extern int BindNull (IntPtr stmt, int index);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_bind_int", CallingConvention=CallingConvention.Cdecl)]
+		public static extern int BindInt (IntPtr stmt, int index, int val);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_bind_int64", CallingConvention=CallingConvention.Cdecl)]
+		public static extern int BindInt64 (IntPtr stmt, int index, long val);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_bind_double", CallingConvention=CallingConvention.Cdecl)]
+		public static extern int BindDouble (IntPtr stmt, int index, double val);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_bind_text16", CallingConvention=CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
+		public static extern int BindText (IntPtr stmt, int index, [MarshalAs(UnmanagedType.LPWStr)] string val, int n, IntPtr free);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_bind_blob", CallingConvention=CallingConvention.Cdecl)]
+		public static extern int BindBlob (IntPtr stmt, int index, byte[] val, int n, IntPtr free);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_column_count", CallingConvention=CallingConvention.Cdecl)]
+		public static extern int ColumnCount (IntPtr stmt);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_column_name", CallingConvention=CallingConvention.Cdecl)]
+		public static extern IntPtr ColumnName (IntPtr stmt, int index);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_column_name16", CallingConvention=CallingConvention.Cdecl)]
+		static extern IntPtr ColumnName16Internal (IntPtr stmt, int index);
+		public static string ColumnName16(IntPtr stmt, int index)
+		{
+			return Marshal.PtrToStringUni(ColumnName16Internal(stmt, index));
+		}
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_column_type", CallingConvention=CallingConvention.Cdecl)]
+		public static extern ColType ColumnType (IntPtr stmt, int index);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_column_int", CallingConvention=CallingConvention.Cdecl)]
+		public static extern int ColumnInt (IntPtr stmt, int index);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_column_int64", CallingConvention=CallingConvention.Cdecl)]
+		public static extern long ColumnInt64 (IntPtr stmt, int index);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_column_double", CallingConvention=CallingConvention.Cdecl)]
+		public static extern double ColumnDouble (IntPtr stmt, int index);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_column_text", CallingConvention=CallingConvention.Cdecl)]
+		public static extern IntPtr ColumnText (IntPtr stmt, int index);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_column_text16", CallingConvention=CallingConvention.Cdecl)]
+		public static extern IntPtr ColumnText16 (IntPtr stmt, int index);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_column_blob", CallingConvention=CallingConvention.Cdecl)]
+		public static extern IntPtr ColumnBlob (IntPtr stmt, int index);
+
+		[DllImport("sqlite3", EntryPoint = "sqlite3_column_bytes", CallingConvention=CallingConvention.Cdecl)]
+		public static extern int ColumnBytes (IntPtr stmt, int index);
+
+		public static string ColumnString (IntPtr stmt, int index)
+		{
+			return Marshal.PtrToStringUni (SQLite3.ColumnText16 (stmt, index));
+		}
+
+		public static byte[] ColumnByteArray (IntPtr stmt, int index)
+		{
+			int length = ColumnBytes (stmt, index);
+			var result = new byte[length];
+			if (length > 0)
+				Marshal.Copy (ColumnBlob (stmt, index), result, 0, length);
+			return result;
+		}
+
+		[DllImport ("sqlite3", EntryPoint = "sqlite3_extended_errcode", CallingConvention = CallingConvention.Cdecl)]
+		public static extern ExtendedResult ExtendedErrCode (IntPtr db);
+
+		[DllImport ("sqlite3", EntryPoint = "sqlite3_libversion_number", CallingConvention = CallingConvention.Cdecl)]
+		public static extern int LibVersionNumber ();
+#else
+		public static Result Open(string filename, out Sqlite3DatabaseHandle db)
+		{
+			return (Result) Sqlite3.sqlite3_open(filename, out db);
+		}
+
+		public static Result Open(string filename, out Sqlite3DatabaseHandle db, int flags, IntPtr zVfs)
+		{
+#if USE_WP8_NATIVE_SQLITE
+			return (Result)Sqlite3.sqlite3_open_v2(filename, out db, flags, "");
+#else
+			return (Result)Sqlite3.sqlite3_open_v2(filename, out db, flags, null);
+#endif
+		}
+
+		public static Result Close(Sqlite3DatabaseHandle db)
+		{
+			return (Result)Sqlite3.sqlite3_close(db);
+		}
+
+		public static Result BusyTimeout(Sqlite3DatabaseHandle db, int milliseconds)
+		{
+			return (Result)Sqlite3.sqlite3_busy_timeout(db, milliseconds);
+		}
+
+		public static int Changes(Sqlite3DatabaseHandle db)
+		{
+			return Sqlite3.sqlite3_changes(db);
+		}
+
+		public static Sqlite3Statement Prepare2(Sqlite3DatabaseHandle db, string query)
+		{
+			Sqlite3Statement stmt = default(Sqlite3Statement);
+#if USE_WP8_NATIVE_SQLITE
+			var r = Sqlite3.sqlite3_prepare_v2(db, query, out stmt);
+#else
+			stmt = new Sqlite3Statement();
+			var r = Sqlite3.sqlite3_prepare_v2(db, query, -1, ref stmt, 0);
+#endif
+			if (r != 0)
+			{
+				throw SQLiteException.New((Result)r, GetErrmsg(db));
+			}
+			return stmt;
+		}
+
+		public static Result Step(Sqlite3Statement stmt)
+		{
+			return (Result)Sqlite3.sqlite3_step(stmt);
+		}
+
+		public static Result Reset(Sqlite3Statement stmt)
+		{
+			return (Result)Sqlite3.sqlite3_reset(stmt);
+		}
+
+		public static Result Finalize(Sqlite3Statement stmt)
+		{
+			return (Result)Sqlite3.sqlite3_finalize(stmt);
+		}
+
+		public static long LastInsertRowid(Sqlite3DatabaseHandle db)
+		{
+			return Sqlite3.sqlite3_last_insert_rowid(db);
+		}
+
+		public static string GetErrmsg(Sqlite3DatabaseHandle db)
+		{
+			return Sqlite3.sqlite3_errmsg(db);
+		}
+
+		public static int BindParameterIndex(Sqlite3Statement stmt, string name)
+		{
+			return Sqlite3.sqlite3_bind_parameter_index(stmt, name);
+		}
+
+		public static int BindNull(Sqlite3Statement stmt, int index)
+		{
+			return Sqlite3.sqlite3_bind_null(stmt, index);
+		}
+
+		public static int BindInt(Sqlite3Statement stmt, int index, int val)
+		{
+			return Sqlite3.sqlite3_bind_int(stmt, index, val);
+		}
+
+		public static int BindInt64(Sqlite3Statement stmt, int index, long val)
+		{
+			return Sqlite3.sqlite3_bind_int64(stmt, index, val);
+		}
+
+		public static int BindDouble(Sqlite3Statement stmt, int index, double val)
+		{
+			return Sqlite3.sqlite3_bind_double(stmt, index, val);
+		}
+
+		public static int BindText(Sqlite3Statement stmt, int index, string val, int n, IntPtr free)
+		{
+#if USE_WP8_NATIVE_SQLITE
+			return Sqlite3.sqlite3_bind_text(stmt, index, val, n);
+#else
+			return Sqlite3.sqlite3_bind_text(stmt, index, val, n, null);
+#endif
+		}
+
+		public static int BindBlob(Sqlite3Statement stmt, int index, byte[] val, int n, IntPtr free)
+		{
+#if USE_WP8_NATIVE_SQLITE
+			return Sqlite3.sqlite3_bind_blob(stmt, index, val, n);
+#else
+			return Sqlite3.sqlite3_bind_blob(stmt, index, val, n, null);
+#endif
+		}
+
+		public static int ColumnCount(Sqlite3Statement stmt)
+		{
+			return Sqlite3.sqlite3_column_count(stmt);
+		}
+
+		public static string ColumnName(Sqlite3Statement stmt, int index)
+		{
+			return Sqlite3.sqlite3_column_name(stmt, index);
+		}
+
+		public static string ColumnName16(Sqlite3Statement stmt, int index)
+		{
+			return Sqlite3.sqlite3_column_name(stmt, index);
+		}
+
+		public static ColType ColumnType(Sqlite3Statement stmt, int index)
+		{
+			return (ColType)Sqlite3.sqlite3_column_type(stmt, index);
+		}
+
+		public static int ColumnInt(Sqlite3Statement stmt, int index)
+		{
+			return Sqlite3.sqlite3_column_int(stmt, index);
+		}
+
+		public static long ColumnInt64(Sqlite3Statement stmt, int index)
+		{
+			return Sqlite3.sqlite3_column_int64(stmt, index);
+		}
+
+		public static double ColumnDouble(Sqlite3Statement stmt, int index)
+		{
+			return Sqlite3.sqlite3_column_double(stmt, index);
+		}
+
+		public static string ColumnText(Sqlite3Statement stmt, int index)
+		{
+			return Sqlite3.sqlite3_column_text(stmt, index);
+		}
+
+		public static string ColumnText16(Sqlite3Statement stmt, int index)
+		{
+			return Sqlite3.sqlite3_column_text(stmt, index);
+		}
+
+		public static byte[] ColumnBlob(Sqlite3Statement stmt, int index)
+		{
+			return Sqlite3.sqlite3_column_blob(stmt, index);
+		}
+
+		public static int ColumnBytes(Sqlite3Statement stmt, int index)
+		{
+			return Sqlite3.sqlite3_column_bytes(stmt, index);
+		}
+
+		public static string ColumnString(Sqlite3Statement stmt, int index)
+		{
+			return Sqlite3.sqlite3_column_text(stmt, index);
+		}
+
+		public static byte[] ColumnByteArray(Sqlite3Statement stmt, int index)
+		{
+			return ColumnBlob(stmt, index);
+		}
+
+		public static Result EnableLoadExtension(Sqlite3DatabaseHandle db, int onoff)
+		{
+			return (Result)Sqlite3.sqlite3_enable_load_extension(db, onoff);
+		}
+
+		public static ExtendedResult ExtendedErrCode(Sqlite3DatabaseHandle db)
+		{
+			return (ExtendedResult)Sqlite3.sqlite3_extended_errcode(db);
+		}
+#endif
+
+		public enum ColType : int
+		{
+			Integer = 1,
+			Float = 2,
+			Text = 3,
+			Blob = 4,
+			Null = 5
+		}
+	}
+}

+ 11 - 0
Assets/RankDemo/SQLite4Unity3d/SQLite.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0f1ac4ecf992e9e46834681f22f1ba60
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Script.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5c46ca83cdaabc749b364588b1e999c7
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 210 - 0
Assets/RankDemo/Script/RankItemUI.cs

@@ -0,0 +1,210 @@
+using System.Collections;
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace LocalRank
+{
+    [System.Serializable]
+    public class RankSpriteInfo
+    {
+        public Sprite sprite;
+        public Vector2 size; // 显示尺寸
+        public string bowTextKey;// 翻译的key
+        public string gunTextKey;
+    }
+    public class RankItemUI : MonoBehaviour
+    {
+        public Text rankIndexText;
+        public Text infoText;
+        public Image avatarImage;
+        public Transform iconTransform;
+        public Image iconImage;
+        public Text iconText;
+        public Outline outline;
+
+        // 图标资源(可选,也可以从外部注入)
+        public RankSpriteInfo firstPlaceSprite;
+        public RankSpriteInfo secondPlaceSprite;
+        public RankSpriteInfo thirdPlaceSprite;
+
+        // 称谓
+        public Text titleText;
+
+        public Sprite selfSprite; // 自己的背景
+        public Sprite otherSprite; // 其他人的背景
+        public Sprite otherTopSprite;   // 其他人的背景(前3名)
+        private RankItemData rankItemData;
+
+        private Coroutine fakeRankCoroutine;
+        private int realRank = 0;
+
+        public void SetData(RankItemData data)
+        {
+            // 设置数据
+            if (data == null) return;
+            rankItemData = data;
+
+            realRank = data.Rank;
+
+            rankIndexText.text = $"#{data.RankIndex}";
+            infoText.text = $"{data.Score}"; //{data.UserName}  
+
+            // 设置名次文本或前三图标
+            ApplyRankDisplay(data.Rank);
+            // if (iconTransform != null && iconImage != null && iconText != null)
+            // {
+            //     if (data.Rank == 1 || data.Rank == 2 || data.Rank == 3)
+            //     {
+            //         iconImage.enabled = true;
+            //         iconText.gameObject.SetActive(false);
+            //         RankSpriteInfo info = null;
+            //         switch (data.Rank)
+            //         {
+            //             case 1:
+            //                 info = firstPlaceSprite;
+            //                 break;
+            //             case 2:
+            //                 info = secondPlaceSprite;
+            //                 break;
+            //             case 3:
+            //                 info = thirdPlaceSprite;
+            //                 break;
+            //         }
+            //         if (info != null && info.sprite != null)
+            //         {
+            //             iconImage.sprite = info.sprite;
+            //             iconImage.rectTransform.sizeDelta = info.size;
+            //         }
+            //     }
+            //     else
+            //     {
+            //         iconImage.enabled = false;
+            //         iconText.gameObject.SetActive(true);
+            //         iconText.text = $"{data.Rank}";
+            //     }
+            // }
+
+            Sprite topSprite = data.Rank <= 3 ? otherTopSprite : otherSprite;
+            GetComponent<Image>().sprite = data.IsSelf ? selfSprite : topSprite;
+            // Outline
+            // if (outline != null)
+            //     outline.enabled = data.IsSelf;
+        }
+
+        public void SetAvatar(Sprite avatarSprite)
+        {
+            if (avatarImage != null)
+                avatarImage.sprite = avatarSprite;
+        }
+        public void SetOtherSprite()
+        {
+            GetComponent<Image>().sprite = otherSprite;
+        }
+        public void HideIconAndText()
+        {
+            if (iconImage != null) iconImage.enabled = false;
+            if (iconText != null) iconText.gameObject.SetActive(false);
+        }
+        public void HideIcon()
+        {
+            if (iconImage != null) iconImage.enabled = false;
+            if (titleText != null) titleText.gameObject.SetActive(false);
+
+        }
+        public void ShowIconAndText()
+        {
+            if (rankItemData.Rank == 1 || rankItemData.Rank == 2 || rankItemData.Rank == 3)
+            {
+                iconImage.enabled = true;
+                iconText.gameObject.SetActive(false);
+            }
+            else
+            {
+                iconImage.enabled = false;
+                iconText.gameObject.SetActive(true);
+            }
+            if (titleText != null) titleText.gameObject.SetActive(true);
+        }
+
+        public void StartRunUI()
+        {
+
+            StartFakeRankAnimation(1.5f, 0.1f);
+            HideIcon();
+        }
+        public void StopRunUI()
+        {
+            RestoreRealRank();
+            ShowIconAndText();
+        }
+
+        // 设置排名展示(图标或文本)
+        private void ApplyRankDisplay(int rank)
+        {
+            if (iconTransform != null && iconImage != null && iconText != null)
+            {
+                if (rank <= 3 && rank >= 1 )
+                {
+                    iconImage.enabled = true;
+                    iconText.gameObject.SetActive(false);
+                    RankSpriteInfo info = rank == 1 ? firstPlaceSprite : rank == 2 ? secondPlaceSprite : thirdPlaceSprite;
+                    if (info != null && info.sprite != null)
+                    {
+                        iconImage.sprite = info.sprite;
+                        iconImage.rectTransform.sizeDelta = info.size;
+                        //根据设备区分
+                        titleText.text =  TextAutoLanguage2.GetTextByKey(GlobalData.MyDeviceMode == DeviceMode.Archery ? info.bowTextKey:info.gunTextKey);
+                    }
+                }
+                else
+                {
+                    iconImage.enabled = false;
+                    iconText.gameObject.SetActive(true);
+                    iconText.text = $"{rank}";
+                }
+            }
+            rankIndexText.text = $"#{rank}";
+        }
+
+        // 自动开始假排名跳动
+        public void StartFakeRankAnimation(float duration = 1.5f, float interval = 0.1f)
+        {
+            if (fakeRankCoroutine != null)
+                StopCoroutine(fakeRankCoroutine);
+
+            fakeRankCoroutine = StartCoroutine(FakeRankRoutine(duration, interval));
+        }
+
+        // 恢复真实排名
+        public void RestoreRealRank()
+        {
+            if (fakeRankCoroutine != null)
+            {
+                StopCoroutine(fakeRankCoroutine);
+                fakeRankCoroutine = null;
+            }
+            ApplyRankDisplay(realRank);
+        }
+
+        // 协程:随机数字跳变动画
+        private IEnumerator FakeRankRoutine(float duration, float interval)
+        {
+            float elapsed = 0f;
+            while (elapsed < duration)
+            {
+                int fakeRank = Random.Range(100, 1001);
+                ApplyRankDisplay(fakeRank);
+                yield return new WaitForSeconds(interval);
+                elapsed += interval;
+            }
+
+            // 恢复真实排名
+            ApplyRankDisplay(realRank);
+            fakeRankCoroutine = null;
+        }
+
+    }
+
+
+}
+

+ 11 - 0
Assets/RankDemo/Script/RankItemUI.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 47285bf021b82ab4aa3af99b40c042c4
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 578 - 0
Assets/RankDemo/Script/RankManager.cs

@@ -0,0 +1,578 @@
+using UnityEngine;
+using UnityEngine.UI;
+using System.Collections.Generic;
+using System.Collections;
+using UnityEngine.Networking;
+using Newtonsoft.Json.Linq;
+using System;
+
+namespace LocalRank
+{
+    [RequireComponent(typeof(RankUpAnimator))]
+    public class RankManager : MonoBehaviour
+    {
+        public Transform Panel; //是否显示
+
+        public Transform content;         // Content节点
+
+        public GameObject itemPrefab;     // 排行榜Item预制体
+
+        public InputField inputField;
+
+        private RankUpAnimator rankUpAnimator; // RankUpAnimator脚本引用
+
+        private List<RankItemData> rankDataList = new List<RankItemData>();
+
+        /// <summary>
+        /// 当前的排名分数
+        /// </summary>
+        public static int CurrentScore = 0;
+        /// <summary>
+        /// 维护一个全局的userId
+        /// </summary>
+        public static int userId { get; private set; }
+        /// <summary>
+        /// 是否创建userId
+        /// </summary>
+        private static bool userIdCreated = false;
+        public static bool HasUserId => userIdCreated;
+
+        /// <summary>
+        /// 是否在滚动
+        /// </summary>
+        private bool isRuning = false;
+
+        //退出
+        public Action OnBackClicked;
+
+        // 你可以在这里定义游戏 ID 或者动态获取
+        private int gameId = 1;
+
+        /// <summary>
+        /// 创建一个排行榜
+        /// </summary>
+        /// <param name="gameType"></param>
+        public static void CreateRankView(int gameType,Action callback) {
+            Debug.Log("当前上传的本地排行榜ID:"+ gameType);
+            //b端时候处理一个结束排行榜
+            GameObject rankObj = ViewManager2.getGameObjectAndShowView(ViewManager2.Path_GameRankView);
+            RankManager gameRankView = rankObj.GetComponent<RankManager>();
+            gameRankView.OnBackClicked += ()=> {
+                ViewManager2.HideView(ViewManager2.Path_GameRankView);
+                callback?.Invoke();
+            };
+            gameRankView.CreateRankGameInfo(gameType);
+            gameRankView.UploadCurrentScoreToNewId();
+        }
+
+        private void Awake()
+        {
+            rankUpAnimator = GetComponent<RankUpAnimator>();
+            if (rankUpAnimator == null)
+            {
+                Debug.LogError("RankUpAnimator 组件未找到!");
+            }
+
+            if (inputField != null)
+            {
+                inputField.onEndEdit.AddListener(InputScore);
+            }
+        }
+        private void Start()
+        {
+            rankUpAnimator.onAnimationStart = () =>
+            {
+                isRuning = true;
+                HideAllRankIcons(); // 滚动前隐藏图标和名次数字
+
+            };
+
+            rankUpAnimator.onAnimationComplete = () =>
+            {
+                isRuning = false;
+                RefreshRankIcons(); // 滚动后恢复图标或数字
+            };
+            //CreateRankGameInfo();
+            //CreateUserId();
+        }
+
+        /// <summary>
+        /// 设置分数。用于后续上传排行榜显示
+        /// </summary>
+        /// <param name="score"></param>
+        public static void SetCurrentScore(int score = 0) {
+            if (score > 0) {
+                CurrentScore = score;
+            }
+        }
+  
+        /// <summary>
+        /// 创建本地排行榜,进入场景时候直接创建。比如游戏场景
+        /// 不同的游戏ID对应不同的排行榜
+        /// </summary>
+        public void CreateRankGameInfo(int CurrentGameId = 1)
+        {
+            gameId = CurrentGameId;
+            // 判断是否已创建表
+            if (RankService.IsTableExists(gameId))
+            {
+                Debug.Log($"rank_game_{gameId} 表已存在!");
+            }
+            else
+            {
+                Debug.Log($"rank_game_{gameId} 表不存在,正在创建...");
+                RankService.CreateTableIfNotExists(gameId);
+            }
+
+
+        }
+        /// <summary>
+        /// 如果需要维护一个常用id的话
+        /// 调用这里创建userId,每个userId都是单独记录排行榜数据。
+        /// </summary>
+        public void CreateUserId()
+        {
+            //获取一个时间戳值
+            userId = RankService.GenerateLocalUserId();
+            //记录一个标识
+            userIdCreated = true;
+        }
+        
+        /// <summary>
+        /// 直接上传分数到当前用户信息
+        /// </summary>
+        public void UploadCurrentScoreToUserId()
+        {
+            if (!HasUserId)
+            {
+                Debug.LogError("无效的本地用户id!");
+                return;
+            }
+            if (CurrentScore != 0) 
+            {
+                if (isRuning) 
+                {
+                    Debug.LogError("操作频繁!等排行榜停止在操作!");
+                    return;
+                }
+                RankService.UploadScore(gameId, userId, "Player_" + userId, "", CurrentScore);
+                Debug.Log($"UploadScoreToUserId rank_game_{gameId} 上传 Id:{userId}分数:{CurrentScore}!");
+                GetLocalRankList();
+                CurrentScore = 0;
+            }
+        }
+        
+        /// <summary>
+        /// 上传当前操作分数到新用户
+        /// </summary>
+        public void UploadCurrentScoreToNewId() {
+            if (CurrentScore != 0)
+            {
+                if (isRuning)
+                {
+                    Debug.LogError("操作频繁!等排行榜停止在操作!");
+                    return;
+                }
+                Panel.gameObject.SetActive(true);
+                UploadNewIdScore(CurrentScore);
+                CurrentScore = 0;
+            }
+            else 
+            {
+                //分数是0直接进行下一步
+                OnBackClicked?.Invoke();
+            }
+        }
+        /// <summary>
+        /// 直接上传一个新用户id分数
+        /// </summary>
+        private void UploadNewIdScore(int score = 0)
+        {
+            int newUserId = RankService.GenerateLocalUserId();
+            RankService.UploadScore(gameId, newUserId, "Player_" + newUserId, "", score);
+            Debug.Log($"UploadNewIdScore rank_game_{gameId} 上传 新Id:{newUserId}分数:{score}!");
+            //更新当前用户信息
+            userId = newUserId;
+            userIdCreated = true;
+
+            GetLocalRankList();
+        }
+        #region 测试数据操作
+        /// <summary>
+        /// 通过Input End 上传分数
+        /// </summary>
+        /// <param name="score"></param>
+        void InputScore(string score)
+        {
+            if (!HasUserId)
+            {
+                Debug.LogError("无效的本地用户id!");
+                return;
+            }
+            int parsedScore;
+            if (!int.TryParse(score, out parsedScore))
+            {
+                Debug.LogError("输入的分数无效!");
+                return;
+            }
+            if (isRuning)
+            {
+                Debug.LogError("操作频繁!等排行榜停止在操作!");
+                return;
+            }
+            RankService.UploadScore(gameId, userId, "Player_" + userId, "", parsedScore);
+            Debug.Log($"InputScore rank_game_{gameId} 上传 Id:{userId}分数:{parsedScore}");
+            GetLocalRankList();
+        }
+        /// <summary>
+        /// 上传测试分数
+        /// </summary>
+        /// <param name="score"></param>
+        public void UploadTestRandomScoreToUserId()
+        {
+            if (!HasUserId)
+            {
+                Debug.LogError("无效的本地用户id!");
+                return;
+            }
+            if (isRuning)
+            {
+                Debug.LogError("操作频繁!等排行榜停止在操作!");
+                return;
+            }
+            int seed = 0;
+            var random = seed == 0 ? new System.Random() : new System.Random(seed);
+            int _score = random.Next(0, 1000); // 随机的分数 0~999 分之间
+            RankService.UploadScore(gameId, userId, "Player_" + userId, "", _score);
+            Debug.Log($"UploadTestRandomScoreToUserId rank_game_{gameId} 上传 Id:{userId}分数:{_score}!");
+            GetLocalRankList();
+        }
+        /// <summary>
+        /// 上传随机分数到新用户
+        /// </summary>
+        public void UploadTestRandomScoreToNewId()
+        {
+            if (isRuning)
+            {
+                Debug.LogError("操作频繁!等排行榜停止在操作!");
+                return;
+            }
+            int seed = 0;
+            var random = seed == 0 ? new System.Random() : new System.Random(seed);
+            int _score = random.Next(1, 1000); // 随机的分数是 1~999 分之间
+            UploadNewIdScore(_score);
+        }
+        /// <summary>
+        /// 测试数据调用
+        /// </summary>
+        public void TestData()
+        {
+            InsertTestData();
+        }
+        /// <summary>
+        /// 按钮调用,重新填充排行榜数据
+        /// </summary>
+        // public void AnimatorRunButton()
+        // {
+        //     PopulateRankList(true); // 重新填充排行榜数据
+        // }
+        /// <summary>
+        /// 插入测试数据
+        /// </summary>
+        /// <param name="seed"></param>
+        private void InsertTestData(int seed = 0)
+        {
+            var random = seed == 0 ? new System.Random() : new System.Random(seed);
+
+            for (int i = 1; i <= 20; i++)
+            {
+                int userId = 1000 + i;
+                string nickname = $"玩家{i:D2}";
+                string avatarUrl = ""; // 可以填测试图片链接或留空
+                int score = random.Next(0, 10000); // 0~9999 分之间
+
+                RankService.UploadScore(gameId, userId, nickname, avatarUrl, score);
+            }
+
+            Debug.Log($"已为 gameId={gameId} 插入 20 条测试数据");
+        }
+        #endregion
+        /// <summary>
+        /// 获取本地排行榜
+        /// </summary>
+        void GetLocalRankList()
+        {
+            if (!HasUserId)
+            {
+                Debug.LogError("先创建用户id再获取排行榜!");
+                return;
+            }
+            rankDataList.Clear();
+            RankItemData selfItem = null;
+
+            const int MaxRankDisplayCount = 9; // 展示排行榜上限,最后一位预留给自己
+            int maxRank = 0;//记录最大的max
+            int index = 0;//当前下标
+
+            var (ranks, selfRank, total) = RankService.GetRankList(gameId: gameId, userId: userId);
+            foreach (var r in ranks)
+            {
+               // Debug.Log($"[{r.Rank}] {r.Nickname} - {r.Score} {(r.IsSelf ? "(你)" : "")}");
+
+                var data = new RankItemData
+                {
+                    Rank = r.Rank,
+                    UserName = r.Nickname,
+                    Score = r.Score,
+                    AvatarUrl = r.AvatarUrl,
+                    IsSelf = r.IsSelf,
+                    RankIndex = index++
+                };
+                // Debug.Log($"成功解析data {data} 排行榜数据");
+                if (data.IsSelf)
+                    selfItem = data;
+                else
+                    rankDataList.Add(data);
+
+                maxRank = Mathf.Max(maxRank, r.Rank);//记录最大值
+            }
+            //Debug.Log($"成功解析 {rankDataList.Count} 条排行榜数据");
+
+            // 如果总数量不足 MaxRankDisplayCount,补充假数据
+            int currentCount = rankDataList.Count;
+            int otherIndex = 0;
+            for (int i = currentCount; i < MaxRankDisplayCount; i++)
+            {
+                ++otherIndex;
+                var fakeData = new RankItemData
+                {
+                    Rank = maxRank + otherIndex,
+                    UserName = $"游客玩家 {i + 1}",
+                    Score = 0,
+                    AvatarUrl = "", // 可替换为默认头像路径
+                    IsSelf = false,
+                    RankIndex = index++
+                };
+                rankDataList.Add(fakeData);
+            }
+            // 最后添加自己(先放在最后一位)
+            if (selfItem != null)
+            {
+                rankDataList.Add(selfItem);
+            }
+            // Debug.Log($"最终排行榜数据条数: {rankDataList.Count}");
+            PopulateRankList(true);
+        }
+        /// <summary>
+        /// 获取远程排行榜数据
+        /// 暂时不使用
+        /// </summary>
+        /// <returns></returns>
+        private IEnumerator FetchRankDataFromServer()
+        {
+            string url = "http://192.168.0.108:11432/SmartBowBusinessServer/SmartBowSDK/UploadScoreAndGetSeasonCenterRankList" +
+                         "?token=3421-1746758375311-5786b88c34343d142bea1dd31a1cb315" +
+                         "&rankArea=2&rankGameType=1001&score=9937" +
+                         "&countryCode=中国&stateCode=广东省&cityCode=清远市";
+
+            UnityWebRequest request = UnityWebRequest.Post(url, "");
+            yield return request.SendWebRequest();
+
+            if (request.result != UnityWebRequest.Result.Success)
+            {
+                Debug.LogError("Request Failed: " + request.error);
+                yield break;
+            }
+
+            string json = request.downloadHandler.text;
+            ParseRankJson(json);
+        }
+        /// <summary>
+        /// 解析远程排行榜数据
+        /// </summary>
+        /// <param name="json"></param>
+        private void ParseRankJson(string json)
+        {
+            rankDataList.Clear();
+
+            JObject root = JObject.Parse(json);
+            JArray rankArray = (JArray)root["data"][0];
+
+            RankItemData selfItem = null;
+            int index = 0;
+
+            foreach (JObject item in rankArray)
+            {
+                var data = new RankItemData
+                {
+                    Rank = item["rankNum"] != null ? (int)item["rankNum"] : 0,
+                    UserName = item["nickname"]?.ToString() ?? "Unknown",
+                    Score = item["score"] != null ? (int)item["score"] : 0,
+                    AvatarUrl = item["avatarUrl"]?.ToString() ?? "",
+                    IsSelf = item["isSelf"]?.ToObject<bool>() ?? false,
+                    RankIndex = index++
+                };
+                Debug.Log($"成功解析data {data} 排行榜数据");
+                if (data.IsSelf)
+                    selfItem = data;
+                else
+                    rankDataList.Add(data);
+            }
+
+            // 最后添加自己(先放在最后一位)
+            if (selfItem != null)
+            {
+                rankDataList.Add(selfItem);
+            }
+
+            Debug.Log($"成功解析 {rankDataList.Count} 条排行榜数据");
+            PopulateRankList();
+        }
+
+        /// <summary>
+        /// 开始跑循环分数时候调用
+        /// </summary>
+        public void HideAllRankIcons()
+        {
+            for (int i = 0; i < content.childCount; i++)
+            {
+                var item = content.GetChild(i);
+                var itemUI = item.GetComponent<RankItemUI>();
+                if (itemUI != null)
+                {
+                    //itemUI.HideIconAndText();
+                    itemUI.StartRunUI();
+                }
+            }
+        }
+        /// <summary>
+        /// 结束循环分数时候调用
+        /// </summary>
+        public void RefreshRankIcons()
+        {
+            for (int i = 0; i < content.childCount; i++)
+            {
+                var item = content.GetChild(i);
+                var itemUI = item.GetComponent<RankItemUI>();
+                if (itemUI != null)
+                {
+                    itemUI.StopRunUI();
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// 填充排行榜列表,生成排行榜预制item
+        /// </summary>
+        /// <param name="isStartup"></param>
+        private void PopulateRankList(bool isStartup = false)
+        {
+            foreach (Transform child in content)
+                Destroy(child.gameObject);
+
+            for (int i = 0; i < rankDataList.Count; i++)
+            {
+                var data = rankDataList[i];
+                GameObject itemObj = Instantiate(itemPrefab, content);
+                itemObj.name = $"RankItem_{data.Rank}";
+
+                RankItemUI itemUI = itemObj.GetComponent<RankItemUI>();
+                if (itemUI != null)
+                {
+                    itemUI.SetData(data);
+                    if (!string.IsNullOrEmpty(data.AvatarUrl))
+                        StartCoroutine(LoadAvatarImage(data.AvatarUrl, itemUI.avatarImage));
+                }
+                else
+                {
+                    Debug.LogWarning("预制体上缺少 RankItemUI 脚本");
+                }
+            }
+
+            if (isStartup)
+                StartCoroutine(DelayedStartAnimation());
+        }
+
+        /// <summary>
+        /// 加载头像图片
+        /// </summary>
+        /// <param name="url"></param>
+        /// <param name="targetImage"></param>
+        /// <returns></returns>
+        private IEnumerator LoadAvatarImage(string url, Image targetImage)
+        {
+            UnityWebRequest request = UnityWebRequestTexture.GetTexture(url);
+            yield return request.SendWebRequest();
+
+            if (request.result != UnityWebRequest.Result.Success)
+            {
+                Debug.LogWarning("头像加载失败: " + request.error);
+                yield break;
+            }
+
+            Texture2D texture = DownloadHandlerTexture.GetContent(request);
+            Sprite avatarSprite = Sprite.Create(texture,
+                new Rect(0, 0, texture.width, texture.height),
+                new Vector2(0.5f, 0.5f));
+            targetImage.sprite = avatarSprite;
+        }
+        /// <summary>
+        /// 延迟开始动画
+        /// </summary>
+        /// <returns></returns>
+        IEnumerator DelayedStartAnimation()
+        {
+            yield return null;
+            // TestRankUpFromTo(10, 1);
+            //查找“自己”的索引和目标真实排名索引
+            int startIndex = rankDataList.Count;
+            RankItemData selfData = rankDataList.Find(d => d.IsSelf);
+            int targetIndex = selfData.RankIndex + 1; // 目标名次是自己在列表中的索引 + 1
+            // for (int i = 0; i < rankDataList.Count; i++)
+            // {
+            //     var data = rankDataList[i];
+            //     Debug.Log($"[{data.Rank}] {data.UserName} - {data.Score} {(data.IsSelf ? "(你)" : "")} ,RankIndex: {data.RankIndex}");
+            // }
+            // Debug.Log($"startIndex:{startIndex} targetIndex:{targetIndex}");
+            if (startIndex != targetIndex)
+            {
+                RankUpFromTo(startIndex, targetIndex);
+            }
+        }
+        /// <summary>
+        /// 测试冲榜动画:从 startIndex 冲到 targetRankIndex
+        /// </summary>
+        void RankUpFromTo(int startIndex, int targetRankIndex)
+        {
+            if (startIndex <= 0 || startIndex > content.childCount)
+            {
+                Debug.LogError("无效的起始排名!");
+                return;
+            }
+
+            if (targetRankIndex <= 0 || targetRankIndex > content.childCount)
+            {
+                Debug.LogError("无效的目标排名!");
+                return;
+            }
+
+            // 获取起始 item
+            Transform startItem = content.GetChild(startIndex - 1);
+
+            // 设置 animator 的目标元素和目标名次
+            rankUpAnimator.targetItem = startItem.GetComponent<RectTransform>();
+            rankUpAnimator.targetRankIndex = targetRankIndex;
+
+            // 调用冲榜动画
+            rankUpAnimator.StartRankUpAnimation(startIndex, targetRankIndex);
+        }
+
+        public void OnClick_Back()
+        {
+            if (isRuning) return;
+            //AudioMgr.ins.PlayBtn();
+            OnBackClicked?.Invoke();
+        }
+    }
+}

+ 11 - 0
Assets/RankDemo/Script/RankManager.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3920a0111cbfc2041b34acfa68d1c9bd
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 279 - 0
Assets/RankDemo/Script/RankUpAnimator.cs

@@ -0,0 +1,279 @@
+using UnityEngine;
+using UnityEngine.UI;
+using DG.Tweening;
+using System.Collections;
+using TMPro;
+
+namespace LocalRank
+{
+    public class RankItemData
+    {
+        public int Rank;
+        public string UserName;
+        public int Score;
+        public string AvatarUrl;
+        public bool IsSelf;
+        public int RankIndex; // 用于存储当前Item的索引
+        public override string ToString()
+        {
+            return $"Rank: {Rank}, UserName: {UserName}, Score: {Score}, AvatarUrl: {AvatarUrl}, IsSelf: {IsSelf}, RankIndex: {RankIndex}";
+        }
+    }
+
+    public class RankUpAnimator : MonoBehaviour
+    {
+        public ScrollRect scrollRect;           // 排行榜 ScrollRect
+        public RectTransform content;               // 排行榜内容区域 (Item们的父节点)
+        public RectTransform viewport;          // ScrollRect的可视区域
+        public RectTransform viewportParent;          // targetItem的父节点
+        public RectTransform targetItem;        // 要冲榜的Item
+        public int targetRankIndex;              // 目标名次(比如第3名)
+
+        [Header("滚动速度")]
+        public float scrollSpeed = 2000f;
+        [Header("滚动时间")]
+        public float scrollDuration = 1.5f;
+        [Header("冲榜上升缩放曲线 (时间轴: 0 ~ scrollDuration)")]
+        public AnimationCurve scaleCurve = AnimationCurve.EaseInOut(0, 1.2f, 1.5f, 1.5f);
+        [Header("冲榜结束时候滞空时间")]
+        public float hangTime = 0.5f;          // 滞空时间
+        [Header("位移动画 Ease 类型")]
+        public Ease moveEase = Ease.Linear;
+
+        [Header("重置频率")]
+        public float contentResetThreshold = 100f;
+
+        public float stopDelay = 0.5f;
+
+
+        private Transform originalParent;       // 保存初始Parent
+        private Vector3 originalPosition;       // 保存初始局部位置
+        private Vector3 originalScale;           // 保存初始缩放
+
+        private Sequence animationSequence;     // DOTween动画序列
+
+        private bool isAnimating = false;        // 动画状态
+
+        public System.Action onAnimationStart; // 动画开始回调
+
+        public System.Action onAnimationComplete; // 动画结束回调
+
+        public void StartRankUpAnimation(int fromRank, int toRank)
+        {
+            if (isAnimating) return;
+            isAnimating = true;
+
+            // 触发动画开始回调
+            onAnimationStart?.Invoke();
+
+            // 保存原始状态
+            originalParent = targetItem.parent;
+            originalPosition = targetItem.localPosition;
+            //用于计算缩放曲线的初始值
+            // 这里的 scaleCurve.Evaluate(0f) 是为了获取曲线在 t=0 时的值,通常是 1.0f
+            // 设置统一缩放起始值(来自曲线)
+            float startScale = scaleCurve.Evaluate(0f);
+            originalScale = targetItem.localScale = Vector3.one * startScale;
+
+            // 使用clone对象来避免原始对象被修改
+            targetClone = Instantiate(targetItem.gameObject, targetItem.parent, true);
+            targetClone.name = targetItem.name + "_Clone";
+            targetClone.transform.localScale = originalScale;
+            targetClone.GetComponent<CanvasGroup>().blocksRaycasts = false;
+            targetClone.transform.SetSiblingIndex(targetItem.GetSiblingIndex()); // 确保在原始Item上面
+            RankItemUI rankItemUI = targetClone.GetComponent<RankItemUI>();
+            rankItemUI.SetOtherSprite(); // 设置为其他人的图标
+
+            // Step 1. 脱离LayoutGroup控制,移动到Viewport上
+            targetItem.SetParent(viewportParent, true);  // true保持世界位置不变
+
+            //targetItem.gameObject.GetComponent<Outline>().enabled = true; // 激活轮廓
+
+            // Step 2. 准备目标位置(计算目标Item应该停在哪)
+            Vector3 targetLocalPosition = CalculateTargetLocalPosition(targetRankIndex);
+
+            // Step 3. 开始上升动画 + 底部滚动动画
+            animationSequence = DOTween.Sequence();
+
+            animationSequence.SetTarget(targetItem);
+
+            animationSequence.SetUpdate(true); //整个序列使用 UnscaledTime
+
+            // --- Animation Step 1: 快速循环滚动阶段 ---
+            animationSequence.AppendCallback(() =>
+            {
+                StartCoroutine(ScrollAndStop(targetLocalPosition));
+            });
+
+            // --- Animation Step 2: 自身向上冲动画 ---
+            float totalMoveDuration = scrollDuration - hangTime;
+            float fastUpDuration = totalMoveDuration * 0.2f;   // 前段快速线性
+            float floatUpDuration = totalMoveDuration * 0.8f;  // 后段缓慢升空
+
+            Vector3 startPos = targetItem.localPosition;
+            Vector3 endPos = new Vector3(startPos.x, targetLocalPosition.y, startPos.z);
+            Vector3 midPos = Vector3.Lerp(startPos, endPos, 0.4f); // 中间位置点(快速上升到一半)
+
+            // 快速线性上升阶段
+            animationSequence.Append(DOTween.To(() => 0f, t =>
+            {
+                float progress = t / fastUpDuration;
+                targetItem.localPosition = Vector3.Lerp(startPos, midPos, progress);
+            }, fastUpDuration, fastUpDuration).SetEase(Ease.Linear));
+
+            // 缓慢升空 + 缩放曲线阶段
+            animationSequence.Append(DOTween.To(() => 0f, t =>
+            {
+                float progress = t / floatUpDuration;
+                float easedT = moveEase != Ease.Unset ? DOVirtual.EasedValue(0, 1, progress, moveEase) : progress;
+
+                targetItem.localPosition = Vector3.Lerp(midPos, endPos, easedT);
+                //但要确保 t + fastUpDuration <= scrollDuration,否则 Evaluate 超出曲线长度可能导致异常值
+                float curveTime = Mathf.Clamp(t + fastUpDuration, 0f, scrollDuration);
+                float scaleFactor = scaleCurve.Evaluate(t + fastUpDuration); // 补正时间轴
+                targetItem.localScale = originalScale * scaleFactor;
+
+            }, floatUpDuration, floatUpDuration));
+
+            // --- Animation Step 3: 滞空阶段 ---
+            // 滞空 -> 落地缓冲效果
+            animationSequence.AppendInterval(hangTime); // 滞空 x 秒
+                                                        // 落地阶段(快速砸下来)
+            animationSequence.Append(targetItem.DOLocalMove(targetLocalPosition, 0.25f)
+                .SetEase(Ease.InQuad)); // 快速落地
+                                        // 缩放恢复阶段
+                                        // 能避免 DOTween 残留的内部插值。
+            animationSequence.Join(DOTween.To(() => targetItem.localScale, s => targetItem.localScale = s, originalScale, 0.25f)
+                .SetEase(Ease.OutQuad));
+
+            // --- Animation Step 4: 滚动到目标名次 ---
+            // AnimateRankChange(
+            //     targetItem.gameObject,
+            //     fromRank,
+            //     toRank,
+            //     scrollDuration
+            // );
+
+            // Step 4. 动画完成,归位
+            animationSequence.OnComplete(() =>
+            {
+                //targetItem.gameObject.GetComponent<Outline>().enabled = false; // 关闭轮廓
+                ResetItem();
+                isAnimating = false;
+                onAnimationComplete?.Invoke();
+            });
+        }
+        /**
+            * 无限滚动逻辑
+            * 1. 先让Content向上滚动
+            * 2. 当Content滚动到一定高度时,重置Content位置
+            * 3. 等待一段时间后,停止滚动
+            */
+        IEnumerator ScrollAndStop(Vector3 targetPos)
+        {
+            float elapsed = 0f;
+
+            while (elapsed < scrollDuration)
+            {
+                content.anchoredPosition += Vector2.up * scrollSpeed * Time.unscaledDeltaTime;//* Time.deltaTime;
+
+                // 无限滚动逻辑
+                if (content.anchoredPosition.y >= contentResetThreshold)
+                {
+                    content.anchoredPosition -= Vector2.up * contentResetThreshold;
+                }
+
+                elapsed += Time.unscaledDeltaTime;//Time.deltaTime;
+                yield return null;
+            }
+
+            yield return new WaitForSecondsRealtime(stopDelay);
+
+        }
+        private Vector3 CalculateTargetLocalPosition(int targetRank)
+        {
+            float itemHeight = targetItem.rect.height;
+
+            VerticalLayoutGroup layoutGroup = content.GetComponent<VerticalLayoutGroup>();
+            float spacing = layoutGroup != null ? layoutGroup.spacing : 0f;
+            float topPadding = layoutGroup != null ? layoutGroup.padding.top : 0f;
+
+            float totalHeightPerItem = itemHeight + spacing;
+            float contentY = -(targetRank - 1) * totalHeightPerItem - topPadding;
+
+            float viewportHeight = viewport.rect.height;
+            float contentHeight = content.rect.height;
+
+            float offsetY = 0f; // 你可以自定义偏移
+
+            float viewportY = contentY + contentHeight - viewportHeight + offsetY;
+
+            return new Vector3(targetItem.localPosition.x, viewportY, 0f);
+        }
+
+
+        private GameObject targetClone;
+        private void ResetItem()
+        {
+            if (targetClone != null)
+            {
+                Destroy(targetClone); // 删除动画用副本
+                targetClone = null;
+            }
+
+            if (targetItem != null)
+            {
+                // 把item归回原来的Content下
+                targetItem.SetParent(content, false);
+
+                // 移动到正确的位置
+                targetItem.SetSiblingIndex(targetRankIndex - 1);
+
+                // 恢复初始缩放
+                targetItem.localScale = originalScale;
+
+                // 保证在Layout下重新排列
+                LayoutRebuilder.ForceRebuildLayoutImmediate(content.GetComponent<RectTransform>());
+            }
+        }
+
+        public void StopAnimation()
+        {
+            if (animationSequence != null && animationSequence.IsPlaying())
+            {
+                animationSequence.Kill();
+                ResetItem();
+                isAnimating = false;
+            }
+        }
+
+
+        /// <summary>
+        /// 平滑地将排名数字从旧值变更为新值
+        /// </summary>
+        /// <param name="targetGO">包含 Text 或 TMP_Text 的 GameObject</param>
+        /// <param name="fromRank">起始名次(通常是旧排名 +1)</param>
+        /// <param name="toRank">目标名次(通常是当前排名 +1)</param>
+        /// <param name="duration">变化时间</param>
+        /// <param name="ease">插值曲线,默认线性</param>
+        public void AnimateRankChange(GameObject targetGO, int fromRank, int toRank, float duration, Ease ease = Ease.Linear)
+        {
+            var tmp = targetGO.GetComponentInChildren<TMP_Text>();
+            var text = targetGO.GetComponentInChildren<Text>();
+
+            if (tmp == null && text == null)
+            {
+                Debug.LogWarning("未找到 TMP_Text 或 Text 组件!");
+                return;
+            }
+
+            DOTween.To(() => fromRank, value =>
+            {
+                if (tmp != null)
+                    tmp.text = value.ToString();
+                else if (text != null)
+                    text.text = value.ToString();
+            }, toRank, duration).SetEase(ease);
+        }
+    }
+}

+ 11 - 0
Assets/RankDemo/Script/RankUpAnimator.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 63bc5ec02b5696847aaeca582ea6894a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 197 - 0
Assets/RankDemo/Script/RankUpLooper.cs

@@ -0,0 +1,197 @@
+using UnityEngine;
+using UnityEngine.UI;
+using DG.Tweening;
+using System.Collections.Generic;
+using System.Collections;
+
+public class RankUpLooper : MonoBehaviour
+{
+    public ScrollRect scrollRect;
+    public RectTransform content;
+    public RectTransform viewport;
+
+    public GameObject itemPrefab;
+    public int itemCount = 20;
+
+    public int targetRankIndex = 2;
+    public float scrollSpeed = 2000f;
+    public float scrollDuration = 1.5f;
+    public float stopDelay = 0.5f;
+
+    private RectTransform highlightItem;
+    private float itemHeight;
+    private bool isAnimating = false;
+    private float contentResetThreshold;
+
+    private List<GameObject> allItems = new List<GameObject>();
+    public void OnClickRankUp()
+    {
+        PlayRankUp(currentRankIndex: 10, targetRankIndex: 2);// 从第10名冲到第2名(模拟)
+    }
+    void Start()
+    {
+        InitRankList();
+    }
+
+    void InitRankList()
+    {
+        allItems.Clear();
+        foreach (Transform child in content) Destroy(child.gameObject);
+
+        // 创建原始项
+        for (int i = 0; i < itemCount; i++)
+        {
+            var item = Instantiate(itemPrefab, content);
+            item.GetComponentInChildren<Text>().text = $"#{i + 1}";
+            allItems.Add(item);
+        }
+
+        // 复制一轮,实现循环
+        for (int i = 0; i < itemCount; i++)
+        {
+            var clone = Instantiate(itemPrefab, content);
+            clone.GetComponentInChildren<Text>().text = $"#{i + 1} (copy)";
+            allItems.Add(clone);
+        }
+
+        LayoutRebuilder.ForceRebuildLayoutImmediate(content);
+
+        // 获取 item 高度
+        itemHeight = allItems[0].GetComponent<RectTransform>().rect.height;
+
+        contentResetThreshold = itemHeight * itemCount;
+    }
+
+    public void PlayRankUp(int currentRankIndex, int targetRankIndex)
+    {
+        if (isAnimating) return;
+
+        this.targetRankIndex = targetRankIndex;
+
+        var original = allItems[currentRankIndex - 1];
+        highlightItem = Instantiate(original, viewport).GetComponent<RectTransform>();
+        highlightItem.name = "HighlightItem";
+        highlightItem.SetAsLastSibling();
+
+        if (!highlightItem.TryGetComponent(out CanvasGroup group))
+            group = highlightItem.gameObject.AddComponent<CanvasGroup>();
+        group.alpha = 1f;
+
+        highlightItem.localScale = Vector3.one * 1.2f;
+
+        isAnimating = true;
+        scrollRect.enabled = false;
+
+        // 🔄 强制刷新布局
+        LayoutRebuilder.ForceRebuildLayoutImmediate(content);
+
+        itemHeight = allItems[0].GetComponent<RectTransform>().rect.height;
+        contentResetThreshold = itemHeight * itemCount;
+
+        // 🎯 提前计算目标位置
+        Vector3 targetPosition = CalculateTargetLocalPosition(targetRankIndex);
+
+        // 启动滚动协程(传入目标位置)
+        StartCoroutine(ScrollAndStop(targetPosition));
+    }
+
+
+    // IEnumerator DelayedScroll()
+    // {
+    //     // 🔄 强制更新布局
+    //     LayoutRebuilder.ForceRebuildLayoutImmediate(content);
+
+    //     // ⏳ 等待一帧,确保布局完成
+    //     yield return new WaitForEndOfFrame();
+
+    //     // 再次确认布局高度等
+    //     itemHeight = allItems[0].GetComponent<RectTransform>().rect.height;
+    //     contentResetThreshold = itemHeight * itemCount;
+
+    //     // 🔥 启动滚动
+    //     StartCoroutine(ScrollAndStop());
+    // }
+
+
+    IEnumerator ScrollAndStop(Vector3 targetPos)
+    {
+        float elapsed = 0f;
+
+        while (elapsed < scrollDuration)
+        {
+            content.anchoredPosition += Vector2.up * scrollSpeed * Time.deltaTime;
+
+            // 无限滚动逻辑
+            if (content.anchoredPosition.y >= contentResetThreshold)
+            {
+                content.anchoredPosition -= Vector2.up * contentResetThreshold;
+            }
+
+            elapsed += Time.deltaTime;
+            yield return null;
+        }
+
+        yield return new WaitForSeconds(stopDelay);
+
+        SnapToTarget(targetPos);
+    }
+
+
+    void SnapToTarget(Vector3 targetPos)
+    {
+        content.DOAnchorPos(targetPos, 0.6f).SetEase(Ease.OutCubic);
+
+        highlightItem.DOScale(Vector3.one, 0.3f).SetEase(Ease.OutBack);
+        highlightItem.DOAnchorPosY(0, 0.4f).SetEase(Ease.OutSine).OnComplete(() =>
+        {
+            isAnimating = false;
+        });
+    }
+    private Vector3 CalculateTargetLocalPosition(int targetRank)
+    {
+        float spacing = 0f;
+        float totalItemHeight = itemHeight + spacing;
+        float contentY = (targetRank - 1) * totalItemHeight;
+        float centeredOffset = contentY - (viewport.rect.height - totalItemHeight) / 2f;
+
+        // 限制 offset 范围
+        centeredOffset = Mathf.Clamp(centeredOffset, 0, content.rect.height - viewport.rect.height);
+
+        return new Vector3(0f, centeredOffset, 0f);
+    }
+    void UpdateHighlightPosition()
+    {
+        RectTransform targetItem = allItems[targetRankIndex - 1].GetComponent<RectTransform>();
+        Vector3 worldPos = targetItem.position;
+        Vector2 localPoint;
+        RectTransformUtility.ScreenPointToLocalPointInRectangle(viewport, worldPos, null, out localPoint);
+        highlightItem.anchoredPosition = localPoint;
+    }
+
+
+    // void SnapToTarget()
+    // {
+    //     // 停止后直接对 content 归位
+    //     float targetY = itemHeight * (targetRankIndex - 1);
+    //     float totalContentHeight = content.rect.height;
+    //     float viewHeight = viewport.rect.height;
+    //     float offset = Mathf.Clamp(targetY - (viewHeight - itemHeight) / 2f, 0, totalContentHeight - viewHeight);
+    //     content.anchoredPosition = new Vector2(0, offset);
+
+    //     // 获取目标 item 的本地位置(在 content 中的位置)
+    //     RectTransform targetItem = allItems[targetRankIndex - 1].GetComponent<RectTransform>();
+
+    //     // 计算目标位置相对 viewport 的 localPosition
+    //     Vector3 worldPos = targetItem.position;
+    //     Vector2 localPoint;
+    //     RectTransformUtility.ScreenPointToLocalPointInRectangle(viewport, worldPos, null, out localPoint);
+
+    //     // Animate highlightItem 到目标位置
+    //     highlightItem.DOAnchorPos(localPoint, 0.4f).SetEase(Ease.OutSine);
+    //     highlightItem.DOScale(Vector3.one, 0.3f).SetEase(Ease.OutBack).OnComplete(() =>
+    //     {
+    //         isAnimating = false;
+    //     });
+    // }
+
+}

+ 11 - 0
Assets/RankDemo/Script/RankUpLooper.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d559c7dc3278bca4f918789be6d519b1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/RankDemo/Texture.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 6b95ff2e648fe4f49b0bbc0daa107d8f
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Texture/rank.png


+ 135 - 0
Assets/RankDemo/Texture/rank.png.meta

@@ -0,0 +1,135 @@
+fileFormatVersion: 2
+guid: bbc4285e9a9222c4eae77795cb862390
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 12
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    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: 1
+    wrapV: 1
+    wrapW: 0
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  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: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  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: iPhone
+    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
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    nameFileIdTable: {}
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Texture/rank__01.png


+ 135 - 0
Assets/RankDemo/Texture/rank__01.png.meta

@@ -0,0 +1,135 @@
+fileFormatVersion: 2
+guid: 57a60eccffe60214c8ab5a3df9459659
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 12
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    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: 1
+    wrapV: 1
+    wrapW: 0
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  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: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  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: iPhone
+    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
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    nameFileIdTable: {}
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Texture/rank__02.png


+ 135 - 0
Assets/RankDemo/Texture/rank__02.png.meta

@@ -0,0 +1,135 @@
+fileFormatVersion: 2
+guid: 85a2a6d848aa741458e09f4ae3101774
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 12
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    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: 1
+    wrapV: 1
+    wrapW: 0
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  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: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  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: iPhone
+    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
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    nameFileIdTable: {}
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Texture/rank__03.png


+ 135 - 0
Assets/RankDemo/Texture/rank__03.png.meta

@@ -0,0 +1,135 @@
+fileFormatVersion: 2
+guid: a4118a0f7030fcc4ca88fff25884e504
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 12
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    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: 1
+    wrapV: 1
+    wrapW: 0
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  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: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  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: iPhone
+    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
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    nameFileIdTable: {}
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Texture/rank__04.png


+ 135 - 0
Assets/RankDemo/Texture/rank__04.png.meta

@@ -0,0 +1,135 @@
+fileFormatVersion: 2
+guid: cd169d64f12d9d147bea319978a5ea4f
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 12
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    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: 1
+    wrapV: 1
+    wrapW: 0
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  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: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  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: iPhone
+    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
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    nameFileIdTable: {}
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Texture/rank__04_1.png


+ 135 - 0
Assets/RankDemo/Texture/rank__04_1.png.meta

@@ -0,0 +1,135 @@
+fileFormatVersion: 2
+guid: acf4bfc90969db545b51e2bdb508143c
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 12
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    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: 1
+    wrapV: 1
+    wrapW: 0
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 130, y: 60, z: 130, w: 60}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  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: iPhone
+    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
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 1537655665
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    nameFileIdTable: {}
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/RankDemo/Texture/rank__05.png


+ 135 - 0
Assets/RankDemo/Texture/rank__05.png.meta

@@ -0,0 +1,135 @@
+fileFormatVersion: 2
+guid: 07c163659ccbe054bbe34e9487d085ac
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 12
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    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: 1
+    wrapV: 1
+    wrapW: 0
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  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: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  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: iPhone
+    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
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    nameFileIdTable: {}
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 818 - 96
Assets/SmartBow/Resources/SmartBow/Prefabs/Views/Home/SettingsView.prefab


+ 84 - 0
Assets/SmartBow/Scripts/Views/SettingsViewParts/BoxBackStageManagement.cs

@@ -1,5 +1,6 @@
 using System.Collections;
 using System.Collections.Generic;
+using LocalRank;
 using UnityEngine;
 using UnityEngine.Events;
 using UnityEngine.UI;
@@ -12,6 +13,13 @@ public class BoxBackStageManagement : MonoBehaviour
     [SerializeField] InputField inputSeconds;
     int CoinMaxLimit = 10;// 个
     int SecondsMaxLimit = 1200;// 秒
+
+    [Header("清空排行榜")]
+    [SerializeField] Dropdown dropdown;
+    List<int> dropdownGameIds = new List<int>(); // 用于映射 index -> gameId
+    public Button clearSelectedButton;
+    public Button clearAllButton;
+    private int selectedGameId = -1;
     // Start is called before the first frame update
     void Start()
     {
@@ -19,6 +27,8 @@ public class BoxBackStageManagement : MonoBehaviour
         InitInputSeconds();
 
         TextAutoLanguage2.OnLanguageChanged += HandleLanguageChange;
+
+        InitDropdown();
     }
     void OnDestroy()
     {
@@ -92,4 +102,78 @@ public class BoxBackStageManagement : MonoBehaviour
         inputSeconds.text = vStr; //+ TextAutoLanguage2.GetTextByKey("UnitSeconds")
         SerialPortHelper.ins.GetPort(4)?.ReqSavingSettingData();
     }
+
+
+
+    #region 本地排行榜
+    /// <summary>
+    /// 初始化清空列表部分
+    /// </summary>
+    void InitDropdown()
+    {
+        clearSelectedButton.onClick.AddListener(ClearSelectedRankTable);
+        clearAllButton.onClick.AddListener(ClearAllRankTables);
+        dropdown.ClearOptions();
+        List<string> options = new List<string>();
+        dropdownGameIds = RankService.GetAllGameIds(); // 保存 gameId 列表
+
+        foreach (var gameId in dropdownGameIds)
+        {
+            //获取名字
+            GameInfo gameInfo = TextureMgr.ins.GetGameInfos(gameId);
+            if (gameInfo == null)
+            {
+                Debug.LogError($"本地数据记录了不存在gameId:{gameId}");
+            }
+            else { options.Add($"{gameInfo.name}"); }
+          
+        }
+
+        dropdown.AddOptions(options);
+        dropdown.onValueChanged.AddListener(OnDropdownValueChanged);
+
+        // 默认选中第一个
+        if (dropdownGameIds.Count > 0)
+        {
+            selectedGameId = dropdownGameIds[0];
+        }
+    }
+
+    void OnDropdownValueChanged(int index)
+    {
+        if (index >= 0 && index < dropdownGameIds.Count)
+        {
+            selectedGameId = dropdownGameIds[index];
+            Debug.Log($"选择了 GameID:{selectedGameId}");
+        }
+        else
+        {
+            Debug.LogWarning("Dropdown 选择索引超出范围");
+        }
+    }
+    //清空选择的
+    void ClearSelectedRankTable()
+    {
+        if (selectedGameId >= 0)
+        {
+            RankService.ClearTable(selectedGameId);
+            Debug.Log($"清空表 rank_game_{selectedGameId}");
+        }
+        else
+        {
+            Debug.LogWarning("尚未选择有效的 GameID");
+        }
+    }
+    /// <summary>
+    /// 清空全部
+    /// </summary>
+    void ClearAllRankTables()
+    {
+        foreach (var gameId in dropdownGameIds)
+        {
+            RankService.ClearTable(gameId);
+            Debug.Log($"已清空表 rank_game_{gameId}");
+        }
+    }
+    #endregion
 }

+ 3 - 1
Assets/SmartBow/Scripts/Views/ViewManager2.cs

@@ -40,7 +40,7 @@ public class ViewManager2
         _DestroyExistViews(fullPath);
         GameObject o = Object.Instantiate(Resources.Load<GameObject>(fullPath), currentViewParent.transform);
         // 根据条件是否设置原来的sorting
-        if (path == Path_GameResultView)
+        if (path == Path_GameResultView || path == Path_GameRankView)
         {
             o.GetComponent<Canvas>().overrideSorting = true;
         }
@@ -198,4 +198,6 @@ public class ViewManager2
     public const string Path_HomeViewTip = "Home/HomeView_Tip";
     public const string Path_GameResultView = "GameResultView";
 
+    //Rank排行榜
+    public const string Path_GameRankView = "GameRankView";
 }

BIN
Assets/StreamingAssets/rank.db


+ 7 - 0
Assets/StreamingAssets/rank.db.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 75810ef813665dc43a52c3ea8cd3cdde
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 7 - 0
Assets/WildAttack/Scripts/Manager/GameMananger.cs

@@ -176,6 +176,13 @@ namespace WildAttack
                 if (UserSettings.ins.openEffect) ads.Play();
             }
 
+            if (CommonConfig.StandaloneModeOrPlatformB)
+            {
+                // uploadScore = 299;
+                //设置一下需要上传排行榜的分数
+                LocalRank.RankManager.SetCurrentScore((int)uploadScore);
+                LocalRank.RankManager.CreateRankView(GlobalData.singlePlayerGameType, null);
+            }
             //关卡结束时候触发
             OnUploadScore();
 

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است