public async Task Shoot(ApiResponse response, ApiData data) { #if DEBUG // HACK: Force game update so older tests still function UpdateGameState(); #endif LocalSpaceship ship = await IntersectionParamCheck(response, data, true); if (ship == null) { return; } double widthDeg = (double)data.Json["width"]; double directionDeg = (double)data.Json["direction"]; double damageScaling = (double)data.Json["damage"]; int energy = (int)Math.Min((int)data.Json["energy"], Math.Floor(ship.Energy / damageScaling)); ship.Energy -= energy * damageScaling; //remove energy for the shot Console.WriteLine($"Shot by {ship.PublicId}, pos={ship.Pos}, dir={directionDeg}°, width={widthDeg}°, energy spent={energy}, scaling={damageScaling}"); // 1) Broadcast the "need to shoot this" message var shootMsg = new SShared.Messages.ScanShoot() { Originator = ship.Token, Origin = ship.Pos, Direction = MathUtils.Deg2Rad(directionDeg), ScaledShotEnergy = energy * damageScaling, Width = MathUtils.Deg2Rad(widthDeg), Radius = MathUtils.ScanShootRadius(MathUtils.Deg2Rad(widthDeg), energy), }; // Construct waiters BEFORE we potentially get a reply so that we know for sure it will reach us var resultWaiters = Bus.Host.ConnectedPeerList .Where(peer => peer != ArbiterPeer) .Select(peer => new MessageWaiter <Messages.Struck>(Bus, peer, struck => struck.Originator == shootMsg.Originator).Wait) .ToArray(); Bus.BroadcastMessage(shootMsg, excludedPeer: ArbiterPeer); // 2) Shoot locally and broadcast the results of the local shoot Messages.Struck results = HandleLocalScanShoot(shootMsg); // 3) Wait for the scanning results of all other nodes Task.WaitAll(resultWaiters, ScanShootTimeout); // 4) Combine the results that arrived with our local ones to find the complete list of all victims foreach (var waiter in resultWaiters) { if (waiter.Status != TaskStatus.RanToCompletion) { continue; } lock (results) { results.ShipsInfo.AddRange(waiter.Result.ShipsInfo); results.OriginatorAreaGain += waiter.Result.OriginatorAreaGain; } } // 5) Apply area gain to the local shooter ship (if any) ship.Area += results.OriginatorAreaGain; JArray respDict = new JArray(); foreach (var struckShip in results.ShipsInfo) { // ignore our ship if (struckShip.Ship.Token == ship.Token) { continue; } double preShotArea = struckShip.Ship.Area + Math.Abs(struckShip.Damage); //The api doesnt have a return value for shooting, but ive left this in for now for testing purposes. JToken struckShipInfo = new JObject(); struckShipInfo["id"] = struckShip.Ship.PublicId; struckShipInfo["area"] = preShotArea; struckShipInfo["posX"] = struckShip.Ship.Pos.X; struckShipInfo["posY"] = struckShip.Ship.Pos.Y; respDict.Add(struckShipInfo); } //Ship performed combat action, lock kill reward if not in combat from before if (ship.LastUpdate - ship.LastCombat > LocalSpaceship.COMBAT_COOLDOWN) { ship.KillReward = ship.Area; } ship.LastCombat = ship.LastUpdate; response.Data["struck"] = respDict; await response.Send(); }
public async Task Scan(ApiResponse response, ApiData data) { var ship = await IntersectionParamCheck(response, data); if (ship == null) { return; } int energy = (int)data.Json["energy"]; double directionDeg = (double)data.Json["direction"]; double widthDeg = (double)data.Json["width"]; energy = (int)Math.Min(energy, Math.Floor(ship.Energy)); ship.Energy -= energy; Console.WriteLine($"Scan by {ship.PublicId}, pos={ship.Pos}, dir={directionDeg}°, width={widthDeg}°, energy spent={energy}"); // 1) Broadcast the "need to scan this" message var scanMsg = new SShared.Messages.ScanShoot() { Originator = ship.Token, Origin = ship.Pos, Direction = MathUtils.Deg2Rad(directionDeg), ScaledShotEnergy = 0, Width = MathUtils.Deg2Rad(widthDeg), Radius = MathUtils.ScanShootRadius(MathUtils.Deg2Rad(widthDeg), energy), }; // Construct waiters BEFORE we potentially get a reply so that we know for sure it will reach us var resultWaiters = Bus.Host.ConnectedPeerList .Where(peer => peer != ArbiterPeer) .Select(peer => new MessageWaiter <Messages.Struck>(Bus, peer, struck => struck.Originator == scanMsg.Originator).Wait) .ToArray(); Bus.BroadcastMessage(scanMsg, excludedPeer: ArbiterPeer); // 2) Scan locally and broadcast the results of the local scan Messages.Struck results = HandleLocalScanShoot(scanMsg); // 3) Wait for the scanning results of all other nodes Task.WaitAll(resultWaiters, ScanShootTimeout); // 4) Combine the results that arrived with our local ones to find the whole list of scanned ships foreach (var waiter in resultWaiters) { if (waiter.Status != TaskStatus.RanToCompletion) { continue; } results.ShipsInfo.AddRange(waiter.Result.ShipsInfo); } JArray respDict = new JArray(); foreach (var scanned in results.ShipsInfo) { if (scanned.Ship.Token == ship.Token) { continue; } //The api doesnt have a return value for shooting, but ive left this in for now for testing purposes. JToken struckShipInfo = new JObject(); struckShipInfo["id"] = scanned.Ship.PublicId; struckShipInfo["area"] = scanned.Ship.Area; struckShipInfo["posX"] = scanned.Ship.Pos.X; struckShipInfo["posY"] = scanned.Ship.Pos.Y; respDict.Add(struckShipInfo); } response.Data["scanned"] = respDict; await response.Send(); }