/// <summary>
        /// Handles the reception, verification of a strings package
        /// and subsequent mapping of strings and initiator of
        /// receipt response.
        ///
        /// Uncached flow: <code>
        /// Client      |      Server
        /// | &lt;-------------- Hash |
        /// | Need Strings ------&gt; |
        /// | &lt;----------- Strings |
        /// | Dont Need Strings -&gt; | &lt;- you are here on client
        ///
        /// Verification failure flow: <code>
        /// Client      |      Server
        /// | &lt;-------------- Hash |
        /// | Need Strings ------&gt; |
        /// | &lt;----------- Strings |
        /// + Hash Failed          | &lt;- you are here on client
        /// | Need Strings ------&gt; |
        /// | &lt;----------- Strings |
        /// | Dont Need Strings -&gt; | &lt;- you are here on client
        ///  </code>
        ///
        /// NOTE: Verification failure flow is currently not implemented.
        /// </code>
        /// </summary>
        /// <exception cref="InvalidOperationException">Unable to verify strings package by hash.</exception>
        /// <seealso cref="NetworkInitialize"/>
        private void HandleStringsMessage(INetManager net, MsgRobustMappedStringsSerializerStrings msgRobustMappedStringsSerializer)
        {
            if (net.IsServer)
            {
                LogSzr.Error("Received strings from client.");
                return;
            }

            LockMappedStrings = false;
            ClearStrings();
            DebugTools.Assert(msgRobustMappedStringsSerializer.Package != null, "msg.Package != null");
            LoadStrings(new MemoryStream(msgRobustMappedStringsSerializer.Package !, false));
            var checkHash = CalculateHash(msgRobustMappedStringsSerializer.Package !);

            if (!checkHash.SequenceEqual(ServerHash))
            {
                // TODO: retry sending MsgClientHandshake with NeedsStrings = false
                throw new InvalidOperationException("Unable to verify strings package by hash." + $"\n{ConvertToBase64Url(checkHash)} vs. {ConvertToBase64Url(ServerHash)}");
            }

            _stringMapHash    = ServerHash;
            LockMappedStrings = true;

            LogSzr.Debug($"Locked in at {_mappedStrings.Count} mapped strings.");

            WriteStringCache();

            // ok we're good now
            var channel = msgRobustMappedStringsSerializer.MsgChannel;

            OnClientCompleteHandshake(net, channel);
        }
        /// <summary>
        /// Polymorphs the target entity into the specific polymorph prototype
        /// </summary>
        /// <param name="target">The entity that will be transformed</param>
        /// <param name="id">The id of the polymorph prototype</param>
        public EntityUid?PolymorphEntity(EntityUid target, string id)
        {
            if (!_proto.TryIndex <PolymorphPrototype>(id, out var proto))
            {
                _saw.Error("Invalid polymorph prototype");
                return(null);
            }

            return(PolymorphEntity(target, proto));
        }
Example #3
0
        private void RequestHandler(IRequestHandlerContext context)
        {
            Uri newUri = new Uri(context.Url);

            if (newUri.Scheme == "usr")
            {
                Stream         stream;
                HttpStatusCode status;
                var            path = new ResourcePath(newUri.AbsolutePath);
                try
                {
                    stream = _resourceManager.UserData.OpenRead(_dreamResource.GetCacheFilePath(newUri.AbsolutePath));
                    status = HttpStatusCode.OK;
                }
                catch (FileNotFoundException)
                {
                    stream = Stream.Null;
                    status = HttpStatusCode.NotFound;
                }
                catch (Exception e)
                {
                    _sawmill.Error($"Exception while loading file from usr://:\n{e}");
                    stream = Stream.Null;
                    status = HttpStatusCode.InternalServerError;
                }

                if (!FileExtensionMimeTypes.TryGetValue(path.Extension, out var mimeType))
                {
                    mimeType = "application/octet-stream";
                }

                context.DoRespondStream(stream, mimeType, status);
                return;
            }
        }
    private void HandleCameraKick(CameraKickEvent args)
    {
        if (!EntityManager.TryGetComponent(args.Euid, out CameraRecoilComponent recoil))
        {
            _log.Warning($"Received a kick for euid {args.Euid}, but it is missing required components.");
            return;
        }

        if (!float.IsFinite(args.Recoil.X) || !float.IsFinite(args.Recoil.Y))
        {
            _log.Error($"CameraRecoilComponent on entity {recoil.Owner} passed a NaN recoil value. Ignoring.");
            return;
        }

        // Use really bad math to "dampen" kicks when we're already kicked.
        var existing = recoil.CurrentKick.Length;
        var dampen   = existing / KickMagnitudeMax;

        recoil.CurrentKick += args.Recoil * (1 - dampen);

        if (recoil.CurrentKick.Length > KickMagnitudeMax)
        {
            recoil.CurrentKick = recoil.CurrentKick.Normalized * KickMagnitudeMax;
        }

        recoil.LastKickTime = 0;
    }
        private void LoadGroupYamlStream(Stream stream)
        {
            try
            {
                using (var reader = new StreamReader(stream))
                {
                    var groupList = new Deserializer().Deserialize <List <ConGroup> >(reader);

                    foreach (var permGroup in groupList)
                    {
                        var grpIndex = new ConGroupIndex(permGroup.Index);
                        if (!_groups.ContainsKey(grpIndex))
                        {
                            _groups.Add(grpIndex, permGroup);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                _logger.Error($"Could not parse the yaml group file! {e.Message}");
            }
        }
Example #6
0
        private void UpdateEffects(ThirstComponent component)
        {
            if (IsMovementThreshold(component.LastThirstThreshold) != IsMovementThreshold(component.CurrentThirstThreshold) &&
                TryComp(component.Owner, out MovementSpeedModifierComponent? movementSlowdownComponent))
            {
                _movement.RefreshMovementSpeedModifiers(component.Owner, movementSlowdownComponent);
            }

            // Update UI
            if (ThirstComponent.ThirstThresholdAlertTypes.TryGetValue(component.CurrentThirstThreshold, out var alertId))
            {
                _alerts.ShowAlert(component.Owner, alertId);
            }
            else
            {
                _alerts.ClearAlertCategory(component.Owner, AlertCategory.Thirst);
            }

            switch (component.CurrentThirstThreshold)
            {
            case ThirstThreshold.OverHydrated:
                component.LastThirstThreshold = component.CurrentThirstThreshold;
                component.ActualDecayRate     = component.BaseDecayRate * 1.2f;
                return;

            case ThirstThreshold.Okay:
                component.LastThirstThreshold = component.CurrentThirstThreshold;
                component.ActualDecayRate     = component.BaseDecayRate;
                return;

            case ThirstThreshold.Thirsty:
                // Same as okay except with UI icon saying drink soon.
                component.LastThirstThreshold = component.CurrentThirstThreshold;
                component.ActualDecayRate     = component.BaseDecayRate * 0.8f;
                return;

            case ThirstThreshold.Parched:
                _movement.RefreshMovementSpeedModifiers(component.Owner);
                component.LastThirstThreshold = component.CurrentThirstThreshold;
                component.ActualDecayRate     = component.BaseDecayRate * 0.6f;
                return;

            case ThirstThreshold.Dead:
                return;

            default:
                _sawmill.Error($"No thirst threshold found for {component.CurrentThirstThreshold}");
                throw new ArgumentOutOfRangeException($"No thirst threshold found for {component.CurrentThirstThreshold}");
            }
        }
            public void Error(string message, params object[] args)
            {
                if (message.StartsWith("Failed connection to") || message == "Failed to connect for some reason.")
                {
                    if (_successfullyConnected)
                    {
                        _successfullyConnected = false;
                    }
                    else
                    {
                        return;
                    }
                }

                _sawmill.Error(message, args);
            }
        /// <summary>
        /// Interpret a server's handshake, either requesting a package
        /// of strings or completing the handshake.
        ///
        /// Uncached flow: <code>
        /// Client      |      Server
        /// | &lt;-------------- Hash | &lt;- you are here on client
        /// | Need Strings ------&gt; |
        /// | &lt;----------- Strings |
        /// | Dont Need Strings -&gt; |
        /// </code>
        ///
        /// Cached flow: <code>
        /// Client      |      Server
        /// | &lt;-------------- Hash | &lt;- you are here on client
        /// | Dont Need Strings -&gt; |
        /// </code>
        ///
        /// Verification failure flow: <code>
        /// Client      |      Server
        /// | &lt;-------------- Hash | &lt;- you are here on client
        /// | Need Strings ------&gt; |
        /// | &lt;----------- Strings |
        /// + Hash Failed          |
        /// | Need Strings ------&gt; |
        /// | &lt;----------- Strings |
        /// | Dont Need Strings -&gt; |
        ///  </code>
        ///
        /// NOTE: Verification failure flow is currently not implemented.
        /// </summary>
        /// <exception cref="InvalidOperationException">Mapped strings are locked.</exception>
        /// <seealso cref="NetworkInitialize"/>
        private void HandleServerHandshake(MsgMapStrServerHandshake msgMapStr)
        {
            if (_net.IsServer)
            {
                LogSzr.Error("Received server handshake on server.");
                return;
            }

            _serverHash = msgMapStr.Hash;

            var hashStr = ConvertToBase64Url(msgMapStr.Hash !);

            LogSzr.Debug($"Received server handshake with hash {hashStr}.");

            var fileName = CacheForHash(hashStr);

            if (!File.Exists(fileName))
            {
                LogSzr.Debug($"No string cache for {hashStr}.");
                var handshake = _net.CreateNetMessage <MsgMapStrClientHandshake>();
                LogSzr.Debug("Asking server to send mapped strings.");
                handshake.NeedsStrings = true;
                msgMapStr.MsgChannel.SendMessage(handshake);
            }
            else
            {
                LogSzr.Debug($"We had a cached string map that matches {hashStr}.");
                using var file = File.OpenRead(fileName);
                var added = _dict.LoadFromPackage(file, out _);

                _stringMapHash = msgMapStr.Hash !;
                LogSzr.Debug($"Read {added} strings from cache {hashStr}.");
                LogSzr.Debug($"Locked in at {_dict.StringCount} mapped strings.");
                // ok we're good now
                var channel = msgMapStr.MsgChannel;
                OnClientCompleteHandshake(_net, channel);
            }
        }
        private void PreloadTextures(ISawmill sawmill)
        {
            sawmill.Debug("Preloading textures...");
            var sw      = Stopwatch.StartNew();
            var resList = GetTypeDict <TextureResource>();

            var texList = ContentFindFiles("/Textures/")
                          // Skip PNG files inside RSIs.
                          .Where(p => p.Extension == "png" && !p.ToString().Contains(".rsi/") && !resList.ContainsKey(p))
                          .Select(p => new TextureResource.LoadStepData {
                Path = p
            })
                          .ToArray();

            Parallel.ForEach(texList, data =>
            {
                try
                {
                    TextureResource.LoadPreTexture(this, data);
                }
                catch (Exception e)
                {
                    // Mark failed loads as bad and skip them in the next few stages.
                    // Avoids any silly array resizing or similar.
                    sawmill.Error($"Exception while loading RSI {data.Path}:\n{e}");
                    data.Bad = true;
                }
            });

            foreach (var data in texList)
            {
                if (data.Bad)
                {
                    continue;
                }

                try
                {
                    TextureResource.LoadTexture(_clyde, data);
                }
                catch (Exception e)
                {
                    sawmill.Error($"Exception while loading RSI {data.Path}:\n{e}");
                    data.Bad = true;
                }
            }

            var errors = 0;

            foreach (var data in texList)
            {
                if (data.Bad)
                {
                    errors += 1;
                    continue;
                }

                try
                {
                    var texResource = new TextureResource();
                    texResource.LoadFinish(this, data);
                    resList[data.Path] = texResource;
                }
                catch (Exception e)
                {
                    sawmill.Error($"Exception while loading RSI {data.Path}:\n{e}");
                    data.Bad = true;
                    errors  += 1;
                }
            }

            sawmill.Debug(
                "Preloaded {CountLoaded} textures ({CountErrored} errored) in {LoadTime}",
                texList.Length,
                errors,
                sw.Elapsed);
        }
        private void PreloadRsis(ISawmill sawmill)
        {
            var sw      = Stopwatch.StartNew();
            var resList = GetTypeDict <RSIResource>();

            var rsiList = ContentFindFiles("/Textures/")
                          .Where(p => p.ToString().EndsWith(".rsi/meta.json"))
                          .Select(c => c.Directory)
                          .Where(p => !resList.ContainsKey(p))
                          .Select(p => new RSIResource.LoadStepData {
                Path = p
            })
                          .ToArray();

            Parallel.ForEach(rsiList, data =>
            {
                try
                {
                    RSIResource.LoadPreTexture(this, data);
                }
                catch (Exception e)
                {
                    // Mark failed loads as bad and skip them in the next few stages.
                    // Avoids any silly array resizing or similar.
                    sawmill.Error($"Exception while loading RSI {data.Path}:\n{e}");
                    data.Bad = true;
                }
            });

            foreach (var data in rsiList)
            {
                if (data.Bad)
                {
                    continue;
                }

                try
                {
                    RSIResource.LoadTexture(_clyde, data);
                }
                catch (Exception e)
                {
                    sawmill.Error($"Exception while loading RSI {data.Path}:\n{e}");
                    data.Bad = true;
                }
            }

            Parallel.ForEach(rsiList, data =>
            {
                if (data.Bad)
                {
                    return;
                }

                try
                {
                    RSIResource.LoadPostTexture(data);
                }
                catch (Exception e)
                {
                    data.Bad = true;
                    sawmill.Error($"Exception while loading RSI {data.Path}:\n{e}");
                }
            });

            var errors = 0;

            foreach (var data in rsiList)
            {
                if (data.Bad)
                {
                    errors += 1;
                    continue;
                }

                try
                {
                    var rsiRes = new RSIResource();
                    rsiRes.LoadFinish(this, data);
                    resList[data.Path] = rsiRes;
                }
                catch (Exception e)
                {
                    sawmill.Error($"Exception while loading RSI {data.Path}:\n{e}");
                    data.Bad = true;
                    errors  += 1;
                }
            }

            sawmill.Debug(
                "Preloaded {CountLoaded} RSIs ({CountErrored} errored) in {LoadTime}",
                rsiList.Length,
                errors,
                sw.Elapsed);
        }
        private DockingComponent?GetDockable(PhysicsComponent body, TransformComponent dockingXform)
        {
            // Did you know Saltern is the most dockable station?

            // Assume the docking port itself (and its body) is valid

            if (!_mapManager.TryGetGrid(dockingXform.GridUid, out var grid) ||
                !HasComp <ShuttleComponent>(grid.GridEntityId))
            {
                return(null);
            }

            var transform      = body.GetTransform();
            var dockingFixture = _fixtureSystem.GetFixtureOrNull(body, DockingFixture);

            if (dockingFixture == null)
            {
                return(null);
            }

            Box2?aabb = null;

            for (var i = 0; i < dockingFixture.Shape.ChildCount; i++)
            {
                aabb = aabb?.Union(dockingFixture.Shape.ComputeAABB(transform, i)) ?? dockingFixture.Shape.ComputeAABB(transform, i);
            }

            if (aabb == null)
            {
                return(null);
            }

            var enlargedAABB = aabb.Value.Enlarged(DockingRadius * 1.5f);

            // Get any docking ports in range on other grids.
            _mapManager.FindGridsIntersectingEnumerator(dockingXform.MapID, enlargedAABB, out var enumerator);

            while (enumerator.MoveNext(out var otherGrid))
            {
                if (otherGrid.GridEntityId == dockingXform.GridUid)
                {
                    continue;
                }

                foreach (var ent in otherGrid.GetAnchoredEntities(enlargedAABB))
                {
                    if (!TryComp(ent, out DockingComponent? otherDocking) ||
                        !otherDocking.Enabled ||
                        !TryComp(ent, out PhysicsComponent? otherBody))
                    {
                        continue;
                    }

                    var otherTransform      = otherBody.GetTransform();
                    var otherDockingFixture = _fixtureSystem.GetFixtureOrNull(otherBody, DockingFixture);

                    if (otherDockingFixture == null)
                    {
                        DebugTools.Assert(false);
                        _sawmill.Error($"Found null docking fixture on {ent}");
                        continue;
                    }

                    for (var i = 0; i < otherDockingFixture.Shape.ChildCount; i++)
                    {
                        var otherAABB = otherDockingFixture.Shape.ComputeAABB(otherTransform, i);

                        if (!aabb.Value.Intersects(otherAABB))
                        {
                            continue;
                        }

                        // TODO: Need CollisionManager's GJK for accurate bounds
                        // Realistically I want 2 fixtures anyway but I'll deal with that later.
                        return(otherDocking);
                    }
                }
            }

            return(null);
        }
 public void Error(string message, params object[] args)
 {
     _sawmill.Error(message, args);
 }