/// <summary> /// Handles a "ship connected" bus message. /// </summary> public void OnShipConnected(NetPeer sender, Messages.ShipConnected msg) { LocalSpaceship ship = null; if (Persistence != null) { Console.WriteLine($"Fetch persisted ship with token={msg.Token}"); var shipFetcher = Persistence.GetShip(msg.Token, _gameTime); shipFetcher.Wait(); ship = shipFetcher.Result; } if (ship == null) { Console.WriteLine($"Create a new ship for token={msg.Token}"); ship = new LocalSpaceship(msg.Token, _gameTime); Quad randomShipBounds = MathUtils.RandomQuadInQuad(QuadTreeNode.Bounds, ship.Radius()); ship.Pos = new Vector2(randomShipBounds.CentreX, randomShipBounds.CentreY); } QuadTreeNode.ShipsByToken.Add(msg.Token, ship); Console.WriteLine($"Send message from {ApiUrl} to {ArbiterPeer.EndPoint}..."); Bus.SendMessage(new Messages.ShipConnected() { Token = msg.Token }, ArbiterPeer); }
public static LocalSpaceship FromJson(JObject json, GameTime gameTime) { LocalSpaceship ship = new LocalSpaceship(Spaceship.FromJson(json), gameTime); long now = gameTime.ElapsedMilliseconds; ship.LastUpdate = now - (long)json["lastUpdateDelta"]; ship.LastCombat = now - (long)json["lastCombatDelta"]; return(ship); }
public async Task PutShip(LocalSpaceship ship) { string url = $"{ElasticUrl}/{ElasticIndex}/_doc/{ship.Token}"; var resp = await RequestJson(url, "PUT", ship.ToJson()); if (resp.ContainsKey("error")) { throw new ApplicationException("ElasticSearch: " + resp["error"].ToString()); } }
public async Task <LocalSpaceship> GetShip(string token, GameTime gameTime) { string url = $"{ElasticUrl}/{ElasticIndex}/_doc/{token}"; var resp = await RequestJson(url, "GET"); if (resp.ContainsKey("_source")) { JObject shipJson = resp["_source"] as JObject; return(LocalSpaceship.FromJson(shipJson, gameTime)); } else { return(null); } }
/// <summary> /// "SuperUser DO"; debug-only message used to forcefully set attributes of a connected ship. /// </summary> public void OnSudo(NetPeer peer, Messages.Sudo data) { Console.WriteLine("Sudo: {0}", data.Json.ToString()); LocalSpaceship ship = null; if (data.Json.ContainsKey("token")) { var token = (string)data.Json["token"]; ship = QuadTreeNode.ShipsByToken.GetValueOrDefault(token, null); if (ship == null) { return; } } foreach (var kv in data.Json) { if (kv.Key == "token") { continue; } AttributeSetter setter = SUDO_SETTER_MAP.GetValueOrDefault(kv.Key, null); if (setter == null) { Console.Error.WriteLine("Sudo: Unrecognized attribute `" + kv.Key + "`"); return; } try { setter.Invoke(this, ship, kv.Value); } catch (Exception exc) { Console.Error.WriteLine("Sudo: Failed to set attribute `" + kv.Key + "`: " + exc.ToString()); return; } } // Send the same sudo back to the arbiter as ACK Bus.SendMessage(data, ArbiterPeer, LiteNetLib.DeliveryMethod.ReliableOrdered); }
/// <summary> /// Handles a "ship disconnected" bus message. /// </summary> public void OnShipDisconnected(NetPeer sender, Messages.ShipDisconnected msg) { Console.WriteLine($"Disconnecting player (token={msg.Token})"); LocalSpaceship ship = null; if (QuadTreeNode.ShipsByToken.Remove(msg.Token, out ship)) { if (Persistence != null) { Console.WriteLine($"Persist disconnected ship with token={msg.Token}"); var shipSaver = Persistence.PutShip(ship); shipSaver.Wait(); } Bus.SendMessage(new Messages.ShipDisconnected() { Token = msg.Token }, ArbiterPeer); } }
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(); }
private void OnShipTransferred(NetPeer peer, Messages.ShipTransferred msg) { LocalSpaceship localShip = new LocalSpaceship(msg.Ship, _gameTime); QuadTreeNode.ShipsByToken.Add(msg.Ship.Token, localShip); }