using System; using System.Collections.Generic; using System.Threading.Tasks; using Newtonsoft.Json; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; using System.Net; using System.Net.Sockets; public class DBmanager : MonoBehaviour { public static string phpRoot = "http://vps.playpoolstudios.com/upf/"; public static string username = null; private static float level = 0; private static int xp = 0; private static int coins = 0; private static int gems = 0; private static int metal = 0; private static int oxygen = 0; private static List inventory; private static List expPassCollected = new List(); private static List skinsPurchased = new List(); public static List buildingStates = new List(); public static UnityEvent OnStateChanged = new UnityEvent(); public static int Xp => xp; public static int Coins => coins; public static int Gems => gems; public static int Metal => metal; public static int Oxygen => oxygen; public static float Level => level; public static int LevelInt => Mathf.CeilToInt(level); public static List ExpPassCollected => expPassCollected; public static List Inventory => inventory; public static List SkinsPurchased => skinsPurchased; public static bool LoggedIn { get { return username != null; } } public static void LogOut() { username = null; } public static async Task GetNetworkTime() { int unixTime = 0; using (UnityWebRequest www = UnityWebRequest.Get(phpRoot + "get_time.php")) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Yield(); } try { unixTime = int.Parse(www.downloadHandler.text); } catch { Debug.Log("Invalid response from server : " + www.downloadHandler.text); } } if (unixTime > 0) { return DateTimeOffset.FromUnixTimeSeconds(unixTime).UtcDateTime; } //default Windows time server const string ntpServer = "time.windows.com"; // NTP message size - 16 bytes of the digest (RFC 2030) var ntpData = new byte[48]; //Setting the Leap Indicator, Version Number and Mode values ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode) var addresses = Dns.GetHostEntry(ntpServer).AddressList; //The UDP port number assigned to NTP is 123 var ipEndPoint = new IPEndPoint(addresses[0], 123); //NTP uses UDP using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { socket.Connect(ipEndPoint); //Stops code hang if NTP is blocked socket.ReceiveTimeout = 3000; socket.Send(ntpData); socket.Receive(ntpData); socket.Close(); } //Offset to get to the "Transmit Timestamp" field (time at which the reply //departed the server for the client, in 64-bit timestamp format." const byte serverReplyTime = 40; //Get the seconds part ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime); //Get the seconds fraction ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4); //Convert From big-endian to little-endian intPart = SwapEndianness(intPart); fractPart = SwapEndianness(fractPart); var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L); //**UTC** time var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds); return networkDateTime.ToLocalTime(); } static uint SwapEndianness(ulong x) { return (uint)(((x & 0x000000ff) << 24) + ((x & 0x0000ff00) << 8) + ((x & 0x00ff0000) >> 8) + ((x & 0xff000000) >> 24)); } public async static Task SetXp(int newValue, bool justOffline = false) { WWWForm form = new WWWForm(); form.AddField("name", username); form.AddField("xp", newValue); if (justOffline) { xp = newValue; } else { using (UnityWebRequest www = UnityWebRequest.Post(phpRoot + "set_xp.php", form)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Yield(); } if (www.downloadHandler.text == "0") { xp = newValue; // Debug } else { Debug.Log("Response : " + www.downloadHandler.text); Debug.LogWarning("Failed to set xp to " + newValue); } } } // for(int i =0; i < xp / 100; i++){ // i // } level = (Mathf.Sqrt((float)Mathf.Clamp(xp, 100, float.PositiveInfinity) / 100f)); if (level == LevelInt) { level -= 0.1f; } Debug.Log("Level : " + (float)xp / 100f + " : " + level + " : " + LevelInt); GameManager.Refresh(); OnStateChanged.Invoke(); } public static int XpForNextLevel(){ int nextLevel = Mathf.CeilToInt(level); return (nextLevel*nextLevel) * 100; } public async static Task SetCoins(int newValue, bool justOffline = false) { WWWForm form = new WWWForm(); form.AddField("name", username); form.AddField("coins", newValue); coins = newValue; if (justOffline) { return; } using (UnityWebRequest www = UnityWebRequest.Post(phpRoot + "set_coins.php", form)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Yield(); } if (www.downloadHandler.text == "0") { coins = newValue; } else { Debug.Log("Response : " + www.downloadHandler.text); Debug.LogWarning("Failed to set coins to " + newValue); } } GameManager.Refresh(); OnStateChanged.Invoke(); } public async static void SetGems(int newValue, bool justOffline = false) { WWWForm form = new WWWForm(); form.AddField("name", username); form.AddField("gems", newValue); if (justOffline) { gems = newValue; return; } using (UnityWebRequest www = UnityWebRequest.Post(phpRoot + "set_gems.php", form)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Yield(); } if (www.downloadHandler.text == "0") { gems = newValue; } else { Debug.Log("Response : " + www.downloadHandler.text); Debug.LogWarning("Failed to set gems to " + newValue); } } GameManager.Refresh(); OnStateChanged.Invoke(); } public async static void SetMetal(int newValue, bool justOffline = false) { WWWForm form = new WWWForm(); form.AddField("name", username); form.AddField("metal", newValue); if (justOffline) { metal = newValue; return; } using (UnityWebRequest www = UnityWebRequest.Post(phpRoot + "set_metal.php", form)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Yield(); } if (www.downloadHandler.text == "0") { metal = newValue; Debug.Log("Metal updated on "+ username); } else { Debug.Log("Response : " + www.downloadHandler.text); Debug.LogWarning("Failed to set metal to " + newValue); } } GameManager.Refresh(); OnStateChanged.Invoke(); } public async static void SetOxygen(int newValue, bool justOffline = false) { WWWForm form = new WWWForm(); form.AddField("name", username); form.AddField("oxygen", newValue); if (justOffline) { oxygen = newValue; return; } using (UnityWebRequest www = UnityWebRequest.Post(phpRoot + "set_oxygen.php", form)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Yield(); } if (www.downloadHandler.text == "0") { oxygen = newValue; } else { Debug.Log("Response : " + www.downloadHandler.text); Debug.LogWarning("Failed to set oxygen to " + newValue); } } GameManager.Refresh(); OnStateChanged.Invoke(); } public static void SetExpPassCollected(string rawData, bool justOffline = false) { try { string[] data = rawData.Split(','); expPassCollected = new List(); foreach (string item in data) { try { int itemVal = int.Parse(item); expPassCollected.Add(itemVal); } catch { } } GameManager.Refresh(); OnStateChanged.Invoke(); } catch { } } public static void SetPurchasedSkins(string data){ skinsPurchased= new List(); string[] skins = data.Split(','); foreach(string skin in skins){ skinsPurchased.Add(skin); } } public static void PurchaseSkin(SkinShopItemData data){ if(metal < data.price){ return; } SetMetal(metal-data.price); skinsPurchased.Add(data.name); UpdatePurchasedSkins(); } public async static void UpdatePurchasedSkins(){ string output =""; foreach(string skin in skinsPurchased){ if(skin.Length==0){continue;} output += skin +","; } if(output.Length>0){output = output.Substring(0,output.Length-1);} // <-- Removes the last ',' WWWForm form = new WWWForm(); form.AddField("name", username); form.AddField("skins", output); using (UnityWebRequest www = UnityWebRequest.Post(phpRoot + "set_skins_purchased.php", form)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Yield(); } if (www.downloadHandler.text == "0") { Debug.Log("Success updating PurchasedSkins"); } else { Debug.Log("Response : " + www.downloadHandler.text); Debug.LogWarning("Failed to set PurchasedSkins to " + output); } } GameManager.Refresh(); OnStateChanged.Invoke(); } public async static void AddCollectedExpPass(int newPassLevel) { expPassCollected.Add(newPassLevel); string output = ""; for (int i = 0; i < expPassCollected.Count; i++) { output += expPassCollected[i].ToString(); if (i < expPassCollected.Count - 1) { output += ","; } } WWWForm form = new WWWForm(); form.AddField("name", username); form.AddField("expPass", output); using (UnityWebRequest www = UnityWebRequest.Post(phpRoot + "set_expPassCollected.php", form)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Yield(); } if (www.downloadHandler.text == "0") { Debug.Log("Success updating ExpPassCollected"); } else { Debug.Log("Response : " + www.downloadHandler.text); Debug.LogWarning("Failed to set exp_pass_collected to " + output); } } GameManager.Refresh(); OnStateChanged.Invoke(); } public static bool GetBuildingStates(string rawData) { bool success = false; //try{ buildingStates = JsonConvert.DeserializeObject>(rawData); Debug.Log("Updating buildings data, isNull: " + (buildingStates == null).ToString()); if (buildingStates == null) { buildingStates = new List(); } success = true; // }catch(Exception e){ // Debug.LogError(e.Message+'\n' + e.StackTrace); // // Debug.LogError("Error updating buildings from server, Response:" + rawData); // success=false; // } OnStateChanged.Invoke(); return success; } public async static Task AddBuilding(BuildingData buildingData) { foreach (BuildingState buildingState in buildingStates) { if (buildingState.id == buildingData.buildingName) { Debug.LogError("Building already exists. Cannot add " + buildingState.id); return; } } Debug.Log("adding new building " + buildingData.buildingName); buildingStates.Add(new BuildingState(buildingData.buildingName, 0, Vector3.zero, await GetNetworkTime())); Debug.Log("Added new building " + buildingData.buildingName); await UpdateBuildingsToServer(); OnStateChanged.Invoke(); SetXp(xp + buildingData.levels[0].xpGain); } public async static Task UpgradeBuilding(string id, int newLevel) { for (int i = 0; i < buildingStates.Count; i++) { if (buildingStates[i].id == id) { buildingStates[i].level = newLevel; Debug.Log("Upgrading " + id + " to " + newLevel); break; } } await UpdateBuildingsToServer(); OnStateChanged.Invoke(); } public async static Task CollectBuilding(string id) { for (int i = 0; i < buildingStates.Count; i++) { if (buildingStates[i].id == id) { buildingStates[i].lastCollectedTimestamp = await GetNetworkTime(); Debug.Log("Setting " + id + " last collected to " + buildingStates[i].lastCollectedTimestamp); break; } } await UpdateBuildingsToServer(); OnStateChanged.Invoke(); } public async static Task RelocateBuilding(string id, Vector3 newPosition) { for (int i = 0; i < buildingStates.Count; i++) { if (buildingStates[i].id == id) { buildingStates[i].position = newPosition; Debug.Log("Relocating " + id + " to " + newPosition); // break; } } Debug.Log("Going to update to server" + JsonConvert.SerializeObject(buildingStates)); await UpdateBuildingsToServer(); OnStateChanged.Invoke(); } public async static Task UpdateBuildingsToServer() { string buildingsJson = JsonConvert.SerializeObject(buildingStates); Debug.Log(buildingsJson); WWWForm form = new WWWForm(); form.AddField("name", username); form.AddField("buildings", buildingsJson); using (UnityWebRequest www = UnityWebRequest.Post(phpRoot + "set_buildings.php", form)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Yield(); } if (www.downloadHandler.text == "0") { } else { Debug.Log("Response : " + www.downloadHandler.text); Debug.LogWarning("Failed to set buildings to " + buildingsJson); } } } public static bool GetInventoryFromServer(string rawJson) { // try{ inventory = JsonConvert.DeserializeObject>(rawJson); // }catch{ // inventory = null; // } if(inventory==null){ Debug.Log("Failed to set inventory, server said : " + rawJson); inventory= new List(); } return true; } public async static void AddInventoryItem(InventoryItem item) { bool exists = false; if(inventory==null){inventory = new List();} foreach(InventoryEntry entry in inventory){ if(entry.Item == item.itemName){ entry.Count++; exists=true; break; } } if(!exists){ inventory.Add(new InventoryEntry(item.itemName,1)); } await UpdateInventoryToServer(); OnStateChanged.Invoke(); } public async static void RemoveInventoryItem(string item) { List temp_inventory = inventory; inventory = new List(); foreach(InventoryEntry entry in temp_inventory){ if(entry.Item == item){continue;} inventory.Add(entry); } if(inventory.Count == temp_inventory.Count){Debug.LogError("No item was removed from inventory");} await UpdateInventoryToServer(); OnStateChanged.Invoke(); } public async static Task UpdateInventoryToServer() { string inventoryJson = JsonConvert.SerializeObject(inventory); Debug.Log(inventoryJson); WWWForm form = new WWWForm(); form.AddField("name", username); form.AddField("inventory", inventoryJson); using (UnityWebRequest www = UnityWebRequest.Post(phpRoot + "set_inventory.php", form)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Yield(); } if (www.downloadHandler.text == "0") { } else { Debug.Log("Response : " + www.downloadHandler.text); Debug.LogWarning("Failed to set inventory to " + inventoryJson); } } } public async static Task SellItem(string item, int coins_amount, int gems_amount, int metals_amount, int oxygen_amount){ //Insert new trade entry to server WWWForm form = new WWWForm(); form.AddField("name", username); form.AddField("item", item); form.AddField("coins", coins_amount); form.AddField("gems", gems_amount); form.AddField("metals", metals_amount); form.AddField("oxygen", oxygen_amount); using (UnityWebRequest www = UnityWebRequest.Post(phpRoot + "add_trade.php", form)) { var operation = www.SendWebRequest(); while (!operation.isDone) { await Task.Yield(); } if (www.downloadHandler.text == "0") { RemoveInventoryItem(item); } else { Debug.Log("Response : " + www.downloadHandler.text); Debug.LogWarning("Failed to add trade entry"); } } OnStateChanged.Invoke(); } }