Exemplo n.º 1
0
        private async Task <IEntity?> Construct(IEntity user, string materialContainer, ConstructionGraphPrototype graph, ConstructionGraphEdge edge, ConstructionGraphNode targetNode)
        {
            // We need a place to hold our construction items!
            var container = ContainerManagerComponent.Ensure <Container>(materialContainer, user, out var existed);

            if (existed)
            {
                user.PopupMessageCursor(Loc.GetString("You can't start another construction now!"));
                return(null);
            }

            var containers = new Dictionary <string, Container>();

            var doAfterTime = 0f;

            // HOLY SHIT THIS IS SOME HACKY CODE.
            // But I'd rather do this shit than risk having collisions with other containers.
            Container GetContainer(string name)
            {
                if (containers !.ContainsKey(name))
                {
                    return(containers[name]);
                }

                while (true)
                {
                    var random = _robustRandom.Next();
                    var c      = ContainerManagerComponent.Ensure <Container>(random.ToString(), user !, out var existed);

                    if (existed)
                    {
                        continue;
                    }

                    containers[name] = c;
                    return(c);
                }
            }

            void FailCleanup()
            {
                foreach (var entity in container !.ContainedEntities.ToArray())
                {
                    container.Remove(entity);
                }

                foreach (var cont in containers !.Values)
                {
                    foreach (var entity in cont.ContainedEntities.ToArray())
                    {
                        cont.Remove(entity);
                    }
                }

                // If we don't do this, items are invisible for some f*****g reason. Nice.
                Timer.Spawn(1, ShutdownContainers);
            }

            void ShutdownContainers()
            {
                container !.Shutdown();
                foreach (var c in containers !.Values.ToArray())
                {
                    c.Shutdown();
                }
            }

            var failed = false;

            var steps = new List <ConstructionGraphStep>();

            foreach (var step in edge.Steps)
            {
                doAfterTime += step.DoAfter;

                var handled = false;

                switch (step)
                {
                case MaterialConstructionGraphStep materialStep:
                    foreach (var entity in EnumerateNearby(user))
                    {
                        if (!materialStep.EntityValid(entity, out var sharedStack))
                        {
                            continue;
                        }

                        var stack = (StackComponent)sharedStack;

                        if (!stack.Split(materialStep.Amount, user.ToCoordinates(), out var newStack))
                        {
                            continue;
                        }

                        if (string.IsNullOrEmpty(materialStep.Store))
                        {
                            if (!container.Insert(newStack))
                            {
                                continue;
                            }
                        }
                        else if (!GetContainer(materialStep.Store).Insert(newStack))
                        {
                            continue;
                        }

                        handled = true;
                        break;
                    }

                    break;

                case ComponentConstructionGraphStep componentStep:
                    foreach (var entity in EnumerateNearby(user))
                    {
                        if (!componentStep.EntityValid(entity))
                        {
                            continue;
                        }

                        if (string.IsNullOrEmpty(componentStep.Store))
                        {
                            if (!container.Insert(entity))
                            {
                                continue;
                            }
                        }
                        else if (!GetContainer(componentStep.Store).Insert(entity))
                        {
                            continue;
                        }

                        handled = true;
                        break;
                    }

                    break;

                case PrototypeConstructionGraphStep prototypeStep:
                    foreach (var entity in EnumerateNearby(user))
                    {
                        if (!prototypeStep.EntityValid(entity))
                        {
                            continue;
                        }

                        if (string.IsNullOrEmpty(prototypeStep.Store))
                        {
                            if (!container.Insert(entity))
                            {
                                continue;
                            }
                        }
                        else if (!GetContainer(prototypeStep.Store).Insert(entity))
                        {
                            continue;
                        }

                        handled = true;
                        break;
                    }

                    break;
                }

                if (handled == false)
                {
                    failed = true;
                    break;
                }

                steps.Add(step);
            }

            if (failed)
            {
                user.PopupMessageCursor(Loc.GetString("You don't have the materials to build that!"));
                FailCleanup();
                return(null);
            }

            var doAfterSystem = Get <DoAfterSystem>();

            var doAfterArgs = new DoAfterEventArgs(user, doAfterTime)
            {
                BreakOnDamage     = true,
                BreakOnStun       = true,
                BreakOnTargetMove = false,
                BreakOnUserMove   = true,
                NeedHand          = true,
            };

            if (await doAfterSystem.DoAfter(doAfterArgs) == DoAfterStatus.Cancelled)
            {
                FailCleanup();
                return(null);
            }

            var newEntity = EntityManager.SpawnEntity(graph.Nodes[edge.Target].Entity, user.Transform.Coordinates);

            // Yes, this should throw if it's missing the component.
            var construction = newEntity.GetComponent <ConstructionComponent>();

            // We attempt to set the pathfinding target.
            construction.Target = targetNode;

            // We preserve the containers...
            foreach (var(name, cont) in containers)
            {
                var newCont = ContainerManagerComponent.Ensure <Container>(name, newEntity);

                foreach (var entity in cont.ContainedEntities.ToArray())
                {
                    cont.ForceRemove(entity);
                    newCont.Insert(entity);
                }
            }

            // We now get rid of all them.
            ShutdownContainers();

            // We have step completed steps!
            foreach (var step in steps)
            {
                foreach (var completed in step.Completed)
                {
                    await completed.PerformAction(newEntity, user);
                }
            }

            // And we also have edge completed effects!
            foreach (var completed in edge.Completed)
            {
                await completed.PerformAction(newEntity, user);
            }

            return(newEntity);
        }
Exemplo n.º 2
0
        private bool UpdatePathfinding(EntityUid uid, ConstructionGraphPrototype graph,
                                       ConstructionGraphNode currentNode, ConstructionGraphNode targetNode,
                                       ConstructionGraphEdge?currentEdge,
                                       ConstructionComponent?construction = null)
        {
            if (!Resolve(uid, ref construction))
            {
                return(false);
            }

            construction.TargetNode = targetNode.Name;

            // Check if we reached the target node.
            if (currentNode == targetNode)
            {
                ClearPathfinding(uid, construction);
                return(true);
            }

            // If we don't have a path, generate it.
            if (construction.NodePathfinding == null)
            {
                var path = graph.PathId(currentNode.Name, targetNode.Name);

                if (path == null || path.Length == 0)
                {
                    // No path.
                    ClearPathfinding(uid, construction);
                    return(false);
                }

                construction.NodePathfinding = new Queue <string>(path);
            }

            // If the next pathfinding node is the one we're at, dequeue it.
            if (construction.NodePathfinding.Peek() == currentNode.Name)
            {
                construction.NodePathfinding.Dequeue();
            }

            if (currentEdge != null && construction.TargetEdgeIndex is {} targetEdgeIndex)
            {
                if (currentNode.Edges.Count >= targetEdgeIndex)
                {
                    // Target edge is incorrect.
                    construction.TargetEdgeIndex = null;
                }
                else if (currentNode.Edges[targetEdgeIndex] != currentEdge)
                {
                    // We went the wrong way, clean up!
                    ClearPathfinding(uid, construction);
                    return(false);
                }
            }

            if (construction.EdgeIndex == null &&
                construction.TargetEdgeIndex == null &&
                construction.NodePathfinding != null)
            {
                construction.TargetEdgeIndex = (currentNode.GetEdgeIndex(construction.NodePathfinding.Peek()));
            }

            return(true);
        }