Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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());
            }
        }
Ejemplo n.º 4
0
        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);
            }
        }
Ejemplo n.º 5
0
        /// <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);
        }
Ejemplo n.º 6
0
        /// <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);
            }
        }
Ejemplo n.º 7
0
        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();
        }
Ejemplo n.º 8
0
        private void OnShipTransferred(NetPeer peer, Messages.ShipTransferred msg)
        {
            LocalSpaceship localShip = new LocalSpaceship(msg.Ship, _gameTime);

            QuadTreeNode.ShipsByToken.Add(msg.Ship.Token, localShip);
        }