using System; using System.Collections.Generic; namespace UnityEngine.SocialPlatforms.Impl { public class LocalUser : UserProfile, ILocalUser { private IUserProfile[] m_Friends; private bool m_Authenticated; private bool m_Underage; public LocalUser() { m_Friends = new UserProfile[0]; m_Authenticated = false; m_Underage = false; } public void Authenticate (Action callback) { ActivePlatform.Instance.Authenticate((ILocalUser)this, callback); } public void LoadFriends (Action callback) { ActivePlatform.Instance.LoadFriends((ILocalUser)this, callback); } // Setters for implementors public void SetFriends(IUserProfile[] friends) { m_Friends = friends; } public void SetAuthenticated(bool value) { m_Authenticated = value; } public void SetUnderage(bool value) { m_Underage = value; } public IUserProfile[] friends { get { return m_Friends; } } public bool authenticated { get { return m_Authenticated; } } public bool underage { get { return m_Underage; } } } public class UserProfile : IUserProfile { protected string m_UserName; protected string m_ID; protected bool m_IsFriend; protected UserState m_State; protected Texture2D m_Image; public UserProfile() { m_UserName = "Uninitialized"; m_ID = "0"; m_IsFriend = false; m_State = UserState.Offline; m_Image = new Texture2D(32, 32); } public UserProfile(string name, string id, bool friend) : this (name, id, friend, UserState.Offline, new Texture2D(0, 0)) { } public UserProfile(string name, string id, bool friend, UserState state, Texture2D image) { m_UserName = name; m_ID = id; m_IsFriend = friend; m_State = state; m_Image = image; } public override string ToString() { return id + " - " + userName + " - " + isFriend + " - " + state; } public void SetUserName(string name) { m_UserName = name; } public void SetUserID(string id) { m_ID = id; } public void SetImage(Texture2D image) { m_Image = image; } public void SetIsFriend(bool value) { m_IsFriend = value; } public void SetState(UserState state) { m_State = state; } public string userName { get { return m_UserName; } } public string id { get { return m_ID; } } public bool isFriend { get { return m_IsFriend; } } public UserState state { get { return m_State; } } public Texture2D image { get { return m_Image; } } } public class Achievement : IAchievement { private bool m_Completed; private bool m_Hidden; private DateTime m_LastReportedDate; public Achievement(string id, double percentCompleted, bool completed, bool hidden, DateTime lastReportedDate) { this.id = id; this.percentCompleted = percentCompleted; m_Completed = completed; m_Hidden = hidden; m_LastReportedDate = lastReportedDate; } public Achievement(string id, double percent) { this.id = id; percentCompleted = percent; m_Hidden = false; m_Completed = false; m_LastReportedDate = DateTime.MinValue; } public Achievement() : this("unknown", 0.0) { } public override string ToString() { return id + " - " + percentCompleted + " - " + completed + " - " + hidden + " - " + lastReportedDate; } public void ReportProgress(Action callback) { ActivePlatform.Instance.ReportProgress(id, percentCompleted, callback); } // Setters for implementors public void SetCompleted(bool value) { m_Completed = value; } public void SetHidden(bool value) { m_Hidden = value; } public void SetLastReportedDate(DateTime date) { m_LastReportedDate = date; } public string id { get; set; } public double percentCompleted { get; set; } public bool completed { get { return m_Completed; } } public bool hidden { get { return m_Hidden; } } public DateTime lastReportedDate { get { return m_LastReportedDate; } } // TODO: How to have a static method for resetting all achivements? //public abstract void ResetAllAchievements(); } public class AchievementDescription : IAchievementDescription { private string m_Title; private Texture2D m_Image; private string m_AchievedDescription; private string m_UnachievedDescription; private bool m_Hidden; private int m_Points; public AchievementDescription(string id, string title, Texture2D image, string achievedDescription, string unachievedDescription, bool hidden, int points) { this.id = id; m_Title = title; m_Image = image; m_AchievedDescription = achievedDescription; m_UnachievedDescription = unachievedDescription; m_Hidden = hidden; m_Points = points; } public override string ToString() { return id + " - " + title + " - " + achievedDescription + " - " + unachievedDescription + " - " + points + " - " + hidden; } public void SetImage(Texture2D image) { m_Image = image; } public string id { get; set; } public string title { get { return m_Title; } } public Texture2D image { get { return m_Image; } } public string achievedDescription { get { return m_AchievedDescription; } } public string unachievedDescription { get { return m_UnachievedDescription; } } public bool hidden { get { return m_Hidden; } } public int points { get { return m_Points; } } } public class Score : IScore { private DateTime m_Date; private string m_FormattedValue; private string m_UserID; private int m_Rank; public Score() : this("unkown", -1) { } public Score(string leaderboardID, Int64 value) : this(leaderboardID, value, "0", DateTime.Now, "", -1) { } public Score(string leaderboardID, Int64 value, string userID, DateTime date, string formattedValue, int rank) { this.leaderboardID = leaderboardID; this.value = value; m_UserID = userID; m_Date = date; m_FormattedValue = formattedValue; m_Rank = rank; } public override string ToString() { return "Rank: '" + m_Rank + "' Value: '" + value + "' Category: '" + leaderboardID + "' PlayerID: '" + m_UserID + "' Date: '" + m_Date; } public void ReportScore(Action callback) { ActivePlatform.Instance.ReportScore(value, leaderboardID, callback); } public void SetDate(DateTime date) { m_Date = date; } public void SetFormattedValue(string value) { m_FormattedValue = value; } public void SetUserID(string userID) { m_UserID = userID; } public void SetRank(int rank) { m_Rank = rank; } public string leaderboardID { get; set; } // TODO: This is just an int64 here, but should be able to represent all supported formats, except for float type scores ... public Int64 value { get; set; } public DateTime date { get { return m_Date; } } public string formattedValue { get { return m_FormattedValue; } } public string userID { get { return m_UserID; } } public int rank { get { return m_Rank; } } } public class Leaderboard : ILeaderboard { private bool m_Loading; private IScore m_LocalUserScore; private uint m_MaxRange; private IScore[] m_Scores; private string m_Title; private string[] m_UserIDs; public Leaderboard() { id = "Invalid"; range = new Range(1, 10); userScope = UserScope.Global; timeScope = TimeScope.AllTime; m_Loading = false; m_LocalUserScore = new Score("Invalid", 0); m_MaxRange = 0; m_Scores = new Score[0]; m_Title = "Invalid"; m_UserIDs = new string[0]; } // TODO: Implement different behaviour when this is populated /*public Leaderboard(string[] userIDs): this() { m_UserIDs = userIDs; }*/ public void SetUserFilter(string[] userIDs) { m_UserIDs = userIDs; } public override string ToString() { return "ID: '" + id + "' Title: '" + m_Title + "' Loading: '" + m_Loading + "' Range: [" + range.from + "," + range.count + "] MaxRange: '" + m_MaxRange + "' Scores: '" + m_Scores.Length + "' UserScope: '" + userScope + "' TimeScope: '" + timeScope + "' UserFilter: '" + m_UserIDs.Length; } public void LoadScores(Action callback) { ActivePlatform.Instance.LoadScores(this, callback); } public bool loading { get { return ActivePlatform.Instance.GetLoading(this); } } // Setters for implementors public void SetLocalUserScore(IScore score) { m_LocalUserScore = score; } public void SetMaxRange(uint maxRange) { m_MaxRange = maxRange; } public void SetScores(IScore[] scores) { m_Scores = scores; } public void SetTitle(string title) { m_Title = title; } public string[] GetUserFilter() { return m_UserIDs; } public string id { get; set; } public UserScope userScope { get; set; } public Range range { get; set; } public TimeScope timeScope { get; set; } public IScore localUserScore { get { return m_LocalUserScore; } } public uint maxRange { get { return m_MaxRange; } } public IScore[] scores { get { return m_Scores; } } public string title { get { return m_Title; } } } } namespace UnityEngine.SocialPlatforms { using UnityEngine.SocialPlatforms.Impl; public class Local : ISocialPlatform { static LocalUser m_LocalUser = null; List m_Friends = new List(); List m_Users = new List(); List m_AchievementDescriptions = new List(); List m_Achievements = new List(); List m_Leaderboards = new List(); Texture2D m_DefaultTexture; public ILocalUser localUser { get { if (m_LocalUser == null) m_LocalUser = new LocalUser(); return m_LocalUser; } } void ISocialPlatform.Authenticate(ILocalUser user, System.Action callback) { LocalUser thisUser = (LocalUser)user; m_DefaultTexture = CreateDummyTexture(32, 32); PopulateStaticData(); thisUser.SetAuthenticated(true); thisUser.SetUnderage(false); thisUser.SetUserID("1000"); thisUser.SetUserName("Lerpz"); thisUser.SetImage(m_DefaultTexture); if (callback != null) callback(true); } void ISocialPlatform.LoadFriends(ILocalUser user, System.Action callback) { if (!VerifyUser()) return; ((LocalUser)user).SetFriends(m_Friends.ToArray()); if (callback != null) callback(true); } public void LoadUsers(string[] userIDs, Action callback) { List matches = new List(); if (!VerifyUser()) return; foreach (string userId in userIDs) { foreach(UserProfile user in m_Users) if (user.id == userId) matches.Add(user); foreach(UserProfile user in m_Friends) if (user.id == userId) matches.Add(user); } callback(matches.ToArray()); } public void ReportProgress(string id, double progress, System.Action callback) { if (!VerifyUser()) return; // Update achievement if it's already been reported foreach (Achievement achoo in m_Achievements) { // TODO: Only allow increase in progress, figure out if xbox/gc report errors when lower progress is reported if (achoo.id == id && achoo.percentCompleted <= progress) { if (progress >= 100.0) achoo.SetCompleted(true); achoo.SetHidden(false); achoo.SetLastReportedDate(DateTime.Now); achoo.percentCompleted = progress; if (callback != null) callback(true); // No need to process this report any more return; } } // If it's not been reported already check if it's a valid achievement description ID and add it, else it's an error foreach (AchievementDescription achoo in m_AchievementDescriptions) { // TODO: Only allow increase in progress, figure out if xbox/gc report errors when lower progress is reported if (achoo.id == id) { bool completed = (progress >= 100.0 ? true : false); Achievement newAchievement = new Achievement(id, progress, completed, false, DateTime.Now); m_Achievements.Add(newAchievement); if (callback != null) callback(true); return; } } Debug.LogError("Achievement ID not found"); if (callback != null) callback(false); } public void LoadAchievementDescriptions(System.Action callback) { if (!VerifyUser()) return; if (callback != null) callback(m_AchievementDescriptions.ToArray()); } public void LoadAchievements(System.Action callback) { if (!VerifyUser()) return; if (callback != null) callback(m_Achievements.ToArray()); } public void ReportScore(Int64 score, string board, System.Action callback) { if (!VerifyUser()) return; foreach (Leaderboard current in m_Leaderboards) { if (current.id == board) { // TODO: IIRC GameCenter only adds scores if they are higher than the users previous score, maybe mirror this here. List scores = new List((Score[])current.scores); scores.Add(new Score(board, score, localUser.id, DateTime.Now, score + " points", 0)); current.SetScores(scores.ToArray()); if (callback != null) callback(true); return; } } Debug.LogError("Leaderboard not found"); if (callback != null) callback(false); } public void LoadScores(string leaderboardID, Action callback) { if (!VerifyUser()) return; foreach (Leaderboard current in m_Leaderboards) { if (current.id == leaderboardID) { SortScores(current); if (callback != null) callback(current.scores); return; } } Debug.LogError("Leaderboard not found"); if (callback != null) callback(new Score[0]); } void ISocialPlatform.LoadScores(ILeaderboard board, System.Action callback) { if (!VerifyUser()) return; // Fill in fake server side data on leaderboard Leaderboard thisBoard = (Leaderboard)board; foreach (Leaderboard lb in m_Leaderboards) { // TODO: In the real world the board might have thousands of scores but only 100 // are returned, for now we can assume they are less than 100 here // TODO: Apply the filters which the leaderboard has, right now it always returns everything found if (lb.id == thisBoard.id) { thisBoard.SetTitle(lb.title); thisBoard.SetScores(lb.scores); thisBoard.SetMaxRange((uint)lb.scores.Length); } } SortScores(thisBoard); SetLocalPlayerScore(thisBoard); if (callback != null) callback(true); } bool ISocialPlatform.GetLoading(ILeaderboard board) { if (!VerifyUser()) return false; return ((Leaderboard)board).loading; } // TODO: Sorting seems to be broken... private void SortScores(Leaderboard board) { List scores = new List((Score[])board.scores); scores.Sort(delegate(Score s1, Score s2) { return s2.value.CompareTo(s1.value); }); for (int i = 0; i < scores.Count; i++) scores[i].SetRank(i+1); } private void SetLocalPlayerScore(Leaderboard board) { foreach (Score score in board.scores) { if (score.userID == localUser.id) { board.SetLocalUserScore(score); break; } } } public void ShowAchievementsUI() { Debug.Log("ShowAchievementsUI not implemented"); } public void ShowLeaderboardUI() { Debug.Log("ShowLeaderboardUI not implemented"); } public ILeaderboard CreateLeaderboard() { Leaderboard lb = new Leaderboard(); return (ILeaderboard)lb; } public IAchievement CreateAchievement() { Achievement achoo = new Achievement(); return (IAchievement)achoo; } private bool VerifyUser() { if (!localUser.authenticated) { Debug.LogError("Must authenticate first"); return false; } return true; } private void PopulateStaticData() { m_Friends.Add(new UserProfile("Fred", "1001", true, UserState.Online, m_DefaultTexture)); m_Friends.Add(new UserProfile("Julia", "1002", true, UserState.Online, m_DefaultTexture)); m_Friends.Add(new UserProfile("Jeff", "1003", true, UserState.Online, m_DefaultTexture)); m_Users.Add(new UserProfile("Sam", "1004", false, UserState.Offline, m_DefaultTexture)); m_Users.Add(new UserProfile("Max", "1005", false, UserState.Offline, m_DefaultTexture)); m_AchievementDescriptions.Add (new AchievementDescription("Achievement01", "First achievement", m_DefaultTexture, "Get first achievement", "Received first achievement", false, 10)); m_AchievementDescriptions.Add (new AchievementDescription("Achievement02", "Second achievement", m_DefaultTexture, "Get second achievement", "Received second achievement", false, 20)); m_AchievementDescriptions.Add (new AchievementDescription("Achievement03", "Third achievement", m_DefaultTexture, "Get third achievement", "Received third achievement", false, 15)); Leaderboard board = new Leaderboard(); board.SetTitle("High Scores"); board.id = "Leaderboard01"; List scores = new List(); scores.Add(new Score("Leaderboard01", 300, "1001", DateTime.Now.AddDays(-1), "300 points", 1)); scores.Add(new Score("Leaderboard01", 255, "1002", DateTime.Now.AddDays(-1), "255 points", 2)); scores.Add(new Score("Leaderboard01", 55, "1003", DateTime.Now.AddDays(-1), "55 points", 3)); scores.Add(new Score("Leaderboard01", 10, "1004", DateTime.Now.AddDays(-1), "10 points", 4)); board.SetScores(scores.ToArray()); m_Leaderboards.Add(board); } private Texture2D CreateDummyTexture(int width, int height) { Texture2D texture = new Texture2D(width, height); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { Color color = (x&y) > 0 ? Color.white : Color.gray; texture.SetPixel (x, y, color); } } texture.Apply(); return texture; } } }