public IEnumerator StopHeat(string hash, HeatModel heat) { if (pendingRequest) { Debug.Log("[BDAScoreClient] Request already pending"); yield break; } pendingRequest = true; this.activeHeat = null; string uri = string.Format("{0}/competitions/{1}/heats/{2}/stop", baseUrl, hash, heat.id); using (UnityWebRequest webRequest = new UnityWebRequest(uri)) { yield return(webRequest.SendWebRequest()); if (!webRequest.isHttpError) { Debug.Log(string.Format("[BDAScoreClient] Stopped heat {1} in {0}", hash, heat.order)); } else { Debug.Log(string.Format("[BDAScoreClient] Failed to stop heat {1} in {0}: {2}", hash, heat.order, webRequest.error)); } } pendingRequest = false; }
public IEnumerator StartHeat(string hash, HeatModel heat) { if (pendingRequest) { Debug.Log("[BDArmory.BDAScoreClient] Request already pending"); yield break; } pendingRequest = true; this.activeHeat = heat; UI.RemoteOrchestrationWindow.Instance.UpdateClientStatus(); string uri = string.Format("{0}/competitions/{1}/heats/{2}/start", baseUrl, hash, heat.id); using (UnityWebRequest webRequest = new UnityWebRequest(uri)) { yield return(webRequest.SendWebRequest()); if (!webRequest.isHttpError) { Debug.Log(string.Format("[BDArmory.BDAScoreClient] Started heat {1} in {0}", hash, heat.order)); } else { Debug.Log(string.Format("[BDArmory.BDAScoreClient] Failed to start heat {1} in {0}: {2}", hash, heat.order, webRequest.error)); } } pendingRequest = false; }
public IEnumerator GetVessels(string hash, HeatModel heat) { if (pendingRequest) { Debug.Log("[BDAScoreClient] Request already pending"); yield break; } pendingRequest = true; string uri = string.Format("{0}/competitions/{1}/heats/{2}/vessels.csv", baseUrl, hash, heat.id); Debug.Log(string.Format("[BDAScoreClient] GET {0}", uri)); using (UnityWebRequest webRequest = UnityWebRequest.Get(uri)) { yield return(webRequest.SendWebRequest()); if (!webRequest.isHttpError) { ReceiveVessels(webRequest.downloadHandler.text); } else { Debug.Log(string.Format("[BDAScoreClient] Failed to get vessels {0}/{1}: {2}", hash, heat, webRequest.error)); } } pendingRequest = false; }
private IEnumerator FetchAndExecuteHeat(string hash, HeatModel model) { status = StatusType.FetchingVessels; // fetch vessel metadata for heat yield return(client.GetVessels(hash, model)); status = StatusType.DownloadingCraftFiles; // fetch craft files for vessels yield return(client.GetCraftFiles(hash, model)); status = StatusType.StartingHeat; // notify web service to start heat yield return(client.StartHeat(hash, model)); // execute heat int attempts = 0; competitionStarted = false; while (!competitionStarted && attempts++ < 3) // 3 attempts is plenty { yield return(ExecuteHeat(hash, model)); if (!competitionStarted) { switch (Control.VesselSpawner.Instance.spawnFailureReason) { case Control.VesselSpawner.SpawnFailureReason.None: // Successful spawning, but competition failed to start for some reason. BDACompetitionMode.Instance.competitionStatus.Add("Failed to start heat due to " + BDACompetitionMode.Instance.competitionStartFailureReason + ", trying again."); break; case Control.VesselSpawner.SpawnFailureReason.VesselLostParts: // Recoverable spawning failure. case Control.VesselSpawner.SpawnFailureReason.TimedOut: // Recoverable spawning failure. BDACompetitionMode.Instance.competitionStatus.Add("Failed to start heat due to " + Control.VesselSpawner.Instance.spawnFailureReason + ", trying again."); break; default: // Spawning is unrecoverable. BDACompetitionMode.Instance.competitionStatus.Add("Failed to start heat due to " + Control.VesselSpawner.Instance.spawnFailureReason + ", aborting."); attempts = 3; break; } } } status = StatusType.ReportingResults; // report scores yield return(SendScores(hash, model)); status = StatusType.StoppingHeat; // notify web service to stop heat yield return(client.StopHeat(hash, model)); status = StatusType.Waiting; yield return(RetryFind(hash)); }
public IEnumerator GetCraftFiles(string hash, HeatModel model) { pendingRequest = true; // DO NOT DELETE THE DIRECTORY. Delete the craft files inside it. // This is much safer. if (Directory.Exists(vesselPath)) { Debug.Log("[BDArmory.BDAScoreClient] Deleting existing craft in spawn directory " + vesselPath); DirectoryInfo info = new DirectoryInfo(vesselPath); FileInfo[] craftFiles = info.GetFiles("*.craft") .Where(e => e.Extension == ".craft") .ToArray(); foreach (FileInfo file in craftFiles) { File.Delete(file.FullName); } } else { Directory.CreateDirectory(vesselPath); } playerVessels.Clear(); // already have the vessels in memory; just need to fetch the files foreach (VesselModel v in vessels.Values) { Debug.Log(string.Format("[BDArmory.BDAScoreClient] GET {0}", v.craft_url)); using (UnityWebRequest webRequest = UnityWebRequest.Get(v.craft_url)) { yield return(webRequest.SendWebRequest()); if (!webRequest.isHttpError) { byte[] rawBytes = webRequest.downloadHandler.data; SaveCraftFile(v, rawBytes); } else { Debug.Log(string.Format("[BDArmory.BDAScoreClient] Failed to get craft for {0}: {1}", v.id, webRequest.error)); } } } pendingRequest = false; }
private void ReceiveHeats(string response) { if (response == null || "".Equals(response)) { Debug.Log(string.Format("[BDAScoreClient] Received empty heat collection response")); return; } List <HeatModel> collection = HeatModel.FromCsv(response); heats.Clear(); if (collection == null) { Debug.Log(string.Format("[BDAScoreClient] Failed to parse heat collection: {0}", response)); return; } foreach (HeatModel heatModel in collection) { Debug.Log(string.Format("[BDAScoreClient] Heat: {0}", heatModel.ToString())); heats.Add(heatModel.id, heatModel); } Debug.Log(string.Format("[BDAScoreClient] Heats: {0}", heats.Count)); }
private IEnumerator FindNextHeat(string hash) { Debug.Log(string.Format("[BDAScoreService] Find next heat for {0}", hash)); status = StatusType.FetchingHeat; // fetch heat metadata yield return(client.GetHeats(hash)); // find an unstarted heat HeatModel model = client.heats.Values.FirstOrDefault(e => e.Available()); if (model == null) { status = StatusType.StalledNoPendingHeats; Debug.Log(string.Format("[BDAScoreService] No inactive heat found {0}", hash)); yield return(RetryFind(hash)); } else { Debug.Log(string.Format("[BDAScoreService] Found heat {1} in {0}", hash, model.order)); yield return(FetchAndExecuteHeat(hash, model)); } }
public static List <HeatModel> FromCsv(string csv) { List <HeatModel> results = new List <HeatModel>(); string[] lines = csv.Split('\n'); if (lines.Length > 0) { for (var k = 1; k < lines.Length; k++) { // Debug.Log(string.Format("[BDArmory.BDAScoreModels]: HeatModel.FromCsv line {0}", lines[k])); if (!lines[k].Contains(",")) { continue; } try { string[] values = lines[k].Split(','); if (values.Length > 0) { HeatModel model = new HeatModel(); model.id = int.Parse(values[0]); model.competition_id = int.Parse(values[1]); model.stage = int.Parse(values[2]); model.order = int.Parse(values[3]); model.started_at = values[4]; model.ended_at = values[5]; results.Add(model); } } catch (Exception e) { Debug.Log("[BDArmory.BDAScoreModels]: HeatModel.FromCsv error: " + e); } } } return(results); }
private List <RecordModel> BuildRecords(string hash, HeatModel heat) { List <RecordModel> results = new List <RecordModel>(); var playerNames = activePlayers; Debug.Log(string.Format("[BDAScoreService] Building records for {0} players", playerNames.Count)); foreach (string playerName in playerNames) { var separatorIndex = playerName.IndexOf('_'); if (separatorIndex < 0) { Debug.Log(string.Format("[BDAScoreService] Unmatched player {0}", playerName)); Debug.Log("DEBUG players were " + string.Join(", ", client.players.Values)); continue; } var playerNamePart = playerName.Substring(0, separatorIndex); PlayerModel player = client.players.Values.FirstOrDefault(e => e.name == playerNamePart); if (player == null) { Debug.Log(string.Format("[BDAScoreService] Unmatched player {0}", playerNamePart)); Debug.Log("DEBUG players were " + string.Join(", ", client.players.Values)); continue; } var vesselNamePart = playerName.Substring(separatorIndex + 1); VesselModel vessel = client.vessels.Values.FirstOrDefault(e => e.player_id == player.id && e.name == vesselNamePart); if (vessel == null) { Debug.Log(string.Format("[BDAScoreService] Unmatched vessel for playerId {0}", player.id)); Debug.Log("DEBUG vessels were " + string.Join(", ", client.vessels.Values.Select(p => p.id))); continue; } RecordModel record = new RecordModel(); record.vessel_id = vessel.id; record.competition_id = int.Parse(hash); record.heat_id = heat.id; record.hits_out = ComputeTotalHitsOut(playerName); record.hits_in = ComputeTotalHitsIn(playerName); record.dmg_out = ComputeTotalDamageOut(playerName); record.dmg_in = ComputeTotalDamageIn(playerName); record.ram_parts_out = ComputeTotalRammedPartsOut(playerName); record.ram_parts_in = ComputeTotalRammedPartsIn(playerName); record.mis_parts_out = ComputeTotalMissilePartsOut(playerName); record.mis_parts_in = ComputeTotalMissilePartsIn(playerName); record.mis_dmg_out = ComputeTotalMissileDamageOut(playerName); record.mis_dmg_in = ComputeTotalMissileDamageIn(playerName); record.wins = ComputeWins(playerName); record.kills = ComputeTotalKills(playerName); record.deaths = ComputeTotalDeaths(playerName); record.assists = ComputeTotalAssists(playerName); record.death_order = ComputeDeathOrder(playerName); record.death_time = ComputeDeathTime(playerName); if (longestHitDistance.ContainsKey(playerName) && longestHitWeapon.ContainsKey(playerName)) { record.distance = (float)longestHitDistance[playerName]; record.weapon = longestHitWeapon[playerName]; } results.Add(record); } Debug.Log(string.Format("[BDAScoreService] Built records for {0} players", results.Count)); return(results); }
private IEnumerator SendScores(string hash, HeatModel heat) { var records = BuildRecords(hash, heat); yield return(client.PostRecords(hash, heat.id, records.ToList())); }
private IEnumerator ExecuteHeat(string hash, HeatModel model) { Debug.Log(string.Format("[BDAScoreService] Running heat {0}/{1}", hash, model.order)); Control.VesselSpawner spawner = Control.VesselSpawner.Instance; // orchestrate the match activePlayers.Clear(); assists.Clear(); damageIn.Clear(); damageOut.Clear(); deaths.Clear(); hitsIn.Clear(); hitsOnTarget.Clear(); hitsOut.Clear(); killsOnTarget.Clear(); longestHitDistance.Clear(); longestHitWeapon.Clear(); missileDamageIn.Clear(); missileDamageOut.Clear(); missilePartsIn.Clear(); missilePartsOut.Clear(); rammedPartsIn.Clear(); rammedPartsOut.Clear(); status = StatusType.SpawningVessels; spawner.SpawnAllVesselsOnce(BDArmorySettings.VESSEL_SPAWN_GEOCOORDS.x, BDArmorySettings.VESSEL_SPAWN_GEOCOORDS.y, BDArmorySettings.VESSEL_SPAWN_ALTITUDE, BDArmorySettings.VESSEL_SPAWN_DISTANCE_TOGGLE ? BDArmorySettings.VESSEL_SPAWN_DISTANCE : BDArmorySettings.VESSEL_SPAWN_DISTANCE_FACTOR, BDArmorySettings.VESSEL_SPAWN_DISTANCE_TOGGLE, BDArmorySettings.VESSEL_SPAWN_EASE_IN_SPEED, true, true, 0, null, null, hash); while (spawner.vesselsSpawning) { yield return(new WaitForFixedUpdate()); } if (!spawner.vesselSpawnSuccess) { Debug.Log("[BDAScoreService] Vessel spawning failed."); yield break; } yield return(new WaitForFixedUpdate()); status = StatusType.RunningHeat; // NOTE: runs in separate coroutine BDACompetitionMode.Instance.StartCompetitionMode(BDArmorySettings.COMPETITION_DISTANCE); yield return(new WaitForFixedUpdate()); // Give the competition start a frame to get going. // start timer coroutine for the duration specified in settings UI var duration = Core.BDArmorySettings.COMPETITION_DURATION * 60d; var message = "Starting " + (duration > 0 ? "a " + duration.ToString("F0") + "s" : "an unlimited") + " duration competition."; Debug.Log("[BDAScoreService]: " + message); BDACompetitionMode.Instance.competitionStatus.Add(message); while (BDACompetitionMode.Instance.competitionStarting) { yield return(new WaitForFixedUpdate()); // Wait for the competition to actually start. } if (!BDACompetitionMode.Instance.competitionIsActive) { message = "Competition failed to start for heat " + hash + "."; BDACompetitionMode.Instance.competitionStatus.Add(message); Debug.Log("[BDAScoreService]: " + message); yield break; } competitionStarted = true; while (BDACompetitionMode.Instance.competitionIsActive) // Wait for the competition to finish (limited duration and log dumping is handled directly by the competition now). { yield return(new WaitForSeconds(1)); } }