Пример #1
0
        public override void Start()
        {
            if (!this.main.EditorEnabled && (this.Voxel.Value.Target == null || !this.Voxel.Value.Target.Active))
            {
                this.BaseBoxes.Clear();

                bool found = false;
                foreach (Voxel m in Lemma.Components.Voxel.Voxels)
                {
                    Voxel.Box box = m.GetBox(this.Position);
                    if (box != null && box.Type.ID == Components.Voxel.t.HardInfected)
                    {
                        foreach (Voxel.Box b in m.GetContiguousByType(new[] { box }))
                        {
                            this.BaseBoxes.Add(b);
                        }
                        this.Voxel.Value = m.Entity;
                        found            = true;
                        break;
                    }
                }
                if (!found)
                {
                    this.Delete.Execute();
                }
            }
        }
Пример #2
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            Transform transform = entity.GetOrCreate <Transform>("Transform");

            this.SetMain(entity, main);

            VoxelAttachable attachable = VoxelAttachable.MakeAttachable(entity, main, true, false);

            attachable.Enabled.Value = true;

            if (!main.EditorEnabled)
            {
                // -1 means we're currently submerged, anything above 0 is the timestamp of the last time we were submerged
                float submerged                  = -1.0f;
                float lastEmit                   = 0.0f;
                Water submergedWater             = null;
                Property <Vector3> coordinatePos = new Property <Vector3>();
                VoxelAttachable.BindTarget(entity, coordinatePos);
                Action check = delegate()
                {
                    Water nowSubmerged = Water.Get(coordinatePos);
                    if (nowSubmerged == null && main.TotalTime - submerged < 1.0f)
                    {
                        Entity ve = attachable.AttachedVoxel.Value.Target;
                        if (ve != null)
                        {
                            Voxel       v   = ve.Get <Voxel>();
                            Voxel.Box   b   = v.GetBox(attachable.Coord);
                            BoundingBox box = new BoundingBox(v.GetRelativePosition(b.X, b.Y, b.Z), v.GetRelativePosition(b.X + b.Width, b.Y + b.Height, b.Z + b.Depth));
                            if (submergedWater != null && main.TotalTime - lastEmit > 0.1f)
                            {
                                Water.SplashParticles(main, box.Transform(v.Transform), v, submergedWater.Position.Value.Y);
                                lastEmit = main.TotalTime;
                            }
                        }
                    }

                    if (nowSubmerged != null)
                    {
                        submerged      = -1.0f;
                        submergedWater = nowSubmerged;
                    }
                    else if (submerged == -1.0f && nowSubmerged == null)
                    {
                        Sound.PostEvent(AK.EVENTS.PLAY_WATER_SPLASH_OUT_BIG, transform.Position);
                        submerged = main.TotalTime;
                    }
                };
                transform.Add(new NotifyBinding(check, coordinatePos));
                entity.Add(new PostInitialization(delegate()
                {
                    submerged = Water.Get(coordinatePos) != null ? -1.0f : -2.0f;
                }));
            }

            entity.Add("AttachOffset", attachable.Offset);
            entity.Add("AttachVector", attachable.Vector);
        }
Пример #3
0
        // Search for nearby boxes that meet a filter criteria within a vaguely defined radius
        public static Voxel.Box BroadphaseSearch(Voxel v, Voxel.Coord coord, int radius, Func <Voxel.Box, bool> filter)
        {
            Queue <Voxel.Box>           queue   = new Queue <Voxel.Box>();
            Dictionary <Voxel.Box, int> visited = new Dictionary <Voxel.Box, int>();

            Voxel.Box startBox = v.GetBox(coord);
            if (startBox == null)
            {
                return(null);
            }
            queue.Enqueue(startBox);
            visited[startBox] = 0;
            int maxSearch   = radius * radius * radius;
            int searchIndex = 0;

            while (queue.Count > 0 && searchIndex < maxSearch)
            {
                searchIndex++;
                Voxel.Box b = queue.Dequeue();
                lock (b.Adjacent)
                {
                    int parentGScore = visited[b];
                    for (int i = 0; i < b.Adjacent.Count; i++)
                    {
                        Voxel.Box adjacent        = b.Adjacent[i];
                        int       tentativeGScore = parentGScore + adjacent.Width * adjacent.Height * adjacent.Depth;
                        int       previousGScore;
                        if (!visited.TryGetValue(adjacent, out previousGScore) || tentativeGScore < previousGScore)
                        {
                            visited[adjacent] = tentativeGScore;

                            if (parentGScore < radius * radius &&
                                coord.X >= adjacent.X - radius && coord.X < adjacent.X + adjacent.Width + radius &&
                                coord.Y >= adjacent.Y - radius && coord.Y < adjacent.Y + adjacent.Height + radius &&
                                coord.Z >= adjacent.Z - radius && coord.Z < adjacent.Z + adjacent.Depth + radius)
                            {
                                if (filter(adjacent))
                                {
                                    return(adjacent);
                                }
                                else
                                {
                                    queue.Enqueue(adjacent);
                                }
                            }
                        }
                    }
                }
            }
            return(null);
        }
Пример #4
0
        private void set()
        {
            Entity voxelEntity = this.AttachedVoxel.Value.Target;

            if (voxelEntity == null)
            {
                return;
            }

            Voxel map = voxelEntity.Get <Voxel>();

            if (map == null)
            {
                return;
            }

            Voxel.State state = Voxel.States.All[this.State];
            if (this.Contiguous)
            {
                lock (map.MutationLock)
                {
                    Voxel.Box b = map.GetBox(this.Coord);
                    if (b != null && b.Type != state)
                    {
                        List <Voxel.Coord> coords = map.GetContiguousByType(new[] { b }).SelectMany(x => x.GetCoords()).Select(x => x.WithData(state)).ToList();
                        map.Empty(coords, true, true, map);
                        map.Fill(coords, true, map);
                        map.Regenerate();
                    }
                }
            }
            else
            {
                lock (map.MutationLock)
                {
                    if (map[this.Coord] != state)
                    {
                        map.Empty(this.Coord, true, true, map);
                        map.Fill(this.Coord, state, true, map);
                        map.Regenerate();
                    }
                }
            }
            this.OnSet.Execute();
        }
Пример #5
0
        public override void Awake()
        {
            base.Awake();

            this.Add(new CommandBinding(this.Set, delegate()
            {
                Entity voxelEntity = this.AttachedVoxel.Value.Target;
                if (voxelEntity == null)
                {
                    return;
                }

                Voxel map         = voxelEntity.Get <Voxel>();
                Voxel.State state = Voxel.States.All[this.State];
                if (this.Contiguous)
                {
                    Voxel.Box b = map.GetBox(this.Coord);
                    if (b != null && b.Type != state)
                    {
                        List <Voxel.Coord> coords = map.GetContiguousByType(new[] { b }).SelectMany(x => x.GetCoords()).Select(x => x.WithData(state)).ToList();
                        lock (map.MutationLock)
                        {
                            map.Empty(coords, true, true);
                            map.Fill(coords);
                        }
                        map.Regenerate();
                    }
                }
                else
                {
                    if (map[this.Coord] != state)
                    {
                        lock (map.MutationLock)
                        {
                            map.Empty(this.Coord, true, true);
                            map.Fill(this.Coord, state);
                        }
                        map.Regenerate();
                    }
                }
            }));
        }
Пример #6
0
        public static bool Broadphase(Voxel m, Voxel.Box start, Voxel.Coord target, Func <Voxel.State, bool> filter, Stack <Voxel.Box> result, int maxIterations = 50)
        {
            BroadphaseEntry closestEntry = null;
            bool            found        = false;

            lock (m.MutationLock)
            {
                Vector3         targetPos  = m.GetRelativePosition(target);
                BroadphaseEntry startEntry = new BroadphaseEntry
                {
                    Parent  = null,
                    Box     = start,
                    G       = 0,
                    F       = (targetPos - start.GetCenter()).Length(),
                    BoxSize = Math.Max(start.Width, Math.Max(start.Height, start.Depth)),
                };
                broadphaseQueue.Push(startEntry);
                broadphaseQueueLookup[start] = startEntry;

                float closestHeuristic = float.MaxValue;

                int iterations = 0;
                while (broadphaseQueue.Count > 0 && iterations < maxIterations)
                {
                    iterations++;

                    BroadphaseEntry entry = broadphaseQueue.Pop();

                    if (entry.Box.Contains(target))
                    {
                        closestEntry = entry;
                        found        = true;
                        break;
                    }

                    broadphaseQueueLookup.Remove(entry.Box);

                    broadphaseClosed[entry.Box] = entry.G;
                    lock (entry.Box.Adjacent)
                    {
                        for (int i = 0; i < entry.Box.Adjacent.Count; i++)
                        {
                            Voxel.Box adjacent = entry.Box.Adjacent[i];
                            if (adjacent == null || !filter(adjacent.Type))
                            {
                                continue;
                            }

                            int boxSize = (int)((adjacent.Width + adjacent.Height + adjacent.Depth) / 3.0f);

                            int tentativeGScore = entry.G + boxSize;

                            int  previousGScore;
                            bool hasPreviousGScore = broadphaseClosed.TryGetValue(adjacent, out previousGScore);

                            if (hasPreviousGScore && tentativeGScore > previousGScore)
                            {
                                continue;
                            }

                            BroadphaseEntry alreadyInQueue;
                            broadphaseQueueLookup.TryGetValue(adjacent, out alreadyInQueue);

                            if (alreadyInQueue == null || tentativeGScore < previousGScore)
                            {
                                BroadphaseEntry newEntry = alreadyInQueue != null ? alreadyInQueue : new BroadphaseEntry();

                                newEntry.Parent = entry;
                                newEntry.G      = tentativeGScore;
                                float heuristic = (targetPos - adjacent.GetCenter()).Length();
                                newEntry.F = tentativeGScore + heuristic;

                                if (heuristic < closestHeuristic)
                                {
                                    closestEntry     = newEntry;
                                    closestHeuristic = heuristic;
                                }

                                if (alreadyInQueue == null)
                                {
                                    newEntry.Box     = adjacent;
                                    newEntry.BoxSize = boxSize;
                                    broadphaseQueue.Push(newEntry);
                                    broadphaseQueueLookup[adjacent] = newEntry;
                                }
                            }
                        }
                    }
                }
            }
            broadphaseClosed.Clear();
            broadphaseQueue.Clear();
            broadphaseQueueLookup.Clear();
            if (closestEntry != null)
            {
                VoxelAStar.reconstructBroadphasePath(closestEntry, result);
            }
            return(found);
        }
Пример #7
0
        public static void Narrowphase(Voxel m, Voxel.Coord start, Voxel.Box target, Stack <Voxel.Coord> result)
        {
            Voxel.Box        currentBox = m.GetBox(start);
            Vector3          targetPos  = target.GetCenter();
            NarrowphaseEntry startEntry = new NarrowphaseEntry
            {
                Parent = null,
                Coord  = start,
                G      = 0,
                F      = (targetPos - m.GetRelativePosition(start)).Length(),
            };

            narrowphaseQueue.Push(startEntry);
            narrowphaseQueueLookup[start] = startEntry;

            NarrowphaseEntry closestEntry     = null;
            float            closestHeuristic = float.MaxValue;

            int iterations = 0;

            while (narrowphaseQueue.Count > 0 && iterations < 80)
            {
                iterations++;

                NarrowphaseEntry entry = narrowphaseQueue.Pop();

                if (m.GetBox(entry.Coord) == target)
                {
                    closestEntry = entry;
                    break;
                }

                narrowphaseQueueLookup.Remove(entry.Coord);

                narrowphaseClosed[entry.Coord] = entry.G;
                for (int i = 0; i < 6; i++)
                {
                    Voxel.Coord adjacent = entry.Coord.Move(DirectionExtensions.Directions[i]);
                    if (!currentBox.Contains(adjacent) && !target.Contains(adjacent))
                    {
                        continue;
                    }

                    int tentativeGScore = entry.G + 1;

                    int  previousGScore;
                    bool hasPreviousGScore = narrowphaseClosed.TryGetValue(adjacent, out previousGScore);

                    if (hasPreviousGScore && tentativeGScore > previousGScore)
                    {
                        continue;
                    }

                    NarrowphaseEntry alreadyInQueue;
                    narrowphaseQueueLookup.TryGetValue(adjacent, out alreadyInQueue);

                    if (alreadyInQueue == null || tentativeGScore < previousGScore)
                    {
                        NarrowphaseEntry newEntry = alreadyInQueue != null ? alreadyInQueue : new NarrowphaseEntry();

                        newEntry.Parent = entry;
                        newEntry.G      = tentativeGScore;
                        float heuristic = (targetPos - m.GetRelativePosition(adjacent)).Length();
                        newEntry.F = tentativeGScore + heuristic;

                        if (heuristic < closestHeuristic)
                        {
                            closestEntry     = newEntry;
                            closestHeuristic = heuristic;
                        }

                        if (alreadyInQueue == null)
                        {
                            newEntry.Coord = adjacent;
                            narrowphaseQueue.Push(newEntry);
                            narrowphaseQueueLookup[adjacent] = newEntry;
                        }
                    }
                }
            }
            narrowphaseClosed.Clear();
            narrowphaseQueue.Clear();
            narrowphaseQueueLookup.Clear();
            if (closestEntry != null)
            {
                VoxelAStar.reconstructNarrowphasePath(closestEntry, result);
            }
        }
Пример #8
0
        public static bool Go(Voxel voxel, Voxel.Coord center, int radius, Action <List <DynamicVoxel> > callback = null)
        {
            if (!voxel[center].Permanent)
            {
                // Break off a chunk of this voxel into a new DynamicMap.

                List <Voxel.Coord> edges = new List <Voxel.Coord>();

                Voxel.Coord ripStart = center.Move(-radius, -radius, -radius);
                Voxel.Coord ripEnd   = center.Move(radius, radius, radius);

                Dictionary <Voxel.Box, bool> permanentBoxes = new Dictionary <Voxel.Box, bool>();
                foreach (Voxel.Coord c in ripStart.CoordinatesBetween(ripEnd))
                {
                    Voxel.Box box = voxel.GetBox(c);
                    if (box != null && box.Type.Permanent)
                    {
                        permanentBoxes[box] = true;
                    }
                }

                foreach (Voxel.Box b in permanentBoxes.Keys)
                {
                    // Top and bottom
                    for (int x = b.X - 1; x <= b.X + b.Width; x++)
                    {
                        for (int z = b.Z - 1; z <= b.Z + b.Depth; z++)
                        {
                            Voxel.Coord coord = new Voxel.Coord {
                                X = x, Y = b.Y + b.Height, Z = z
                            };
                            if (coord.Between(ripStart, ripEnd))
                            {
                                edges.Add(coord);
                            }

                            coord = new Voxel.Coord {
                                X = x, Y = b.Y - 1, Z = z
                            };
                            if (coord.Between(ripStart, ripEnd))
                            {
                                edges.Add(coord);
                            }
                        }
                    }

                    // Outer shell
                    for (int y = b.Y; y < b.Y + b.Height; y++)
                    {
                        // Left and right
                        for (int z = b.Z - 1; z <= b.Z + b.Depth; z++)
                        {
                            Voxel.Coord coord = new Voxel.Coord {
                                X = b.X - 1, Y = y, Z = z
                            };
                            if (coord.Between(ripStart, ripEnd))
                            {
                                edges.Add(coord);
                            }

                            coord = new Voxel.Coord {
                                X = b.X + b.Width, Y = y, Z = z
                            };
                            if (coord.Between(ripStart, ripEnd))
                            {
                                edges.Add(coord);
                            }
                        }

                        // Backward and forward
                        for (int x = b.X; x < b.X + b.Width; x++)
                        {
                            Voxel.Coord coord = new Voxel.Coord {
                                X = x, Y = y, Z = b.Z - 1
                            };
                            if (coord.Between(ripStart, ripEnd))
                            {
                                edges.Add(coord);
                            }

                            coord = new Voxel.Coord {
                                X = x, Y = y, Z = b.Z + b.Depth
                            };
                            if (coord.Between(ripStart, ripEnd))
                            {
                                edges.Add(coord);
                            }
                        }
                    }
                }

                if (edges.Contains(center))
                {
                    return(false);
                }

                // Top and bottom
                for (int x = ripStart.X; x <= ripEnd.X; x++)
                {
                    for (int z = ripStart.Z; z <= ripEnd.Z; z++)
                    {
                        Voxel.Coord c = new Voxel.Coord {
                            X = x, Y = ripStart.Y, Z = z
                        };
                        Voxel.State s = voxel[c];
                        if (s != Voxel.States.Empty && !s.Permanent)
                        {
                            edges.Add(c);
                        }
                        c = new Voxel.Coord {
                            X = x, Y = ripEnd.Y, Z = z
                        };
                        s = voxel[c];
                        if (s != Voxel.States.Empty && !s.Permanent)
                        {
                            edges.Add(c);
                        }
                    }
                }

                // Sides
                for (int y = ripStart.Y + 1; y <= ripEnd.Y - 1; y++)
                {
                    // Left and right
                    for (int z = ripStart.Z; z <= ripEnd.Z; z++)
                    {
                        Voxel.Coord c = new Voxel.Coord {
                            X = ripStart.X, Y = y, Z = z
                        };
                        Voxel.State s = voxel[c];
                        if (s != Voxel.States.Empty && !s.Permanent)
                        {
                            edges.Add(c);
                        }
                        c = new Voxel.Coord {
                            X = ripEnd.X, Y = y, Z = z
                        };
                        s = voxel[c];
                        if (s != Voxel.States.Empty && !s.Permanent)
                        {
                            edges.Add(c);
                        }
                    }

                    // Backward and forward
                    for (int x = ripStart.X; x <= ripEnd.X; x++)
                    {
                        Voxel.Coord c = new Voxel.Coord {
                            X = x, Y = y, Z = ripStart.Z
                        };
                        Voxel.State s = voxel[c];
                        if (s != Voxel.States.Empty && !s.Permanent)
                        {
                            edges.Add(c);
                        }
                        c = new Voxel.Coord {
                            X = x, Y = y, Z = ripEnd.Z
                        };
                        s = voxel[c];
                        if (s != Voxel.States.Empty && !s.Permanent)
                        {
                            edges.Add(c);
                        }
                    }
                }

                Propagator p = WorldFactory.Instance.Get <Propagator>();
                foreach (Voxel.Coord c in edges)
                {
                    p.SparksLowPriority(voxel.GetAbsolutePosition(c), Propagator.Spark.Dangerous);
                }

                voxel.Empty(edges);

                voxel.Regenerate(callback);
                return(true);
            }
            return(false);
        }
Пример #9
0
        private bool determineShouldBuildFloor(Voxel.State floorState)
        {
            bool result = false;

            if (floorState == Voxel.States.Blue || floorState == Voxel.States.Powered)
            {
                // If we're standing on blue or powered, we need to check if we're close to a non-blue block before we can build a floor
                // This prevents the player from building a floor infinitely
                Queue <Voxel.Box>           queue   = new Queue <Voxel.Box>();
                Dictionary <Voxel.Box, int> visited = new Dictionary <Voxel.Box, int>();
                Voxel.Box floorBox = this.floorMap.GetBox(this.floorCoordinate);
                queue.Enqueue(floorBox);
                visited[floorBox] = 0;
                const int radius      = 6;
                const int maxSearch   = radius * radius * radius;
                int       searchIndex = 0;
                while (queue.Count > 0 && searchIndex < maxSearch)
                {
                    searchIndex++;
                    Voxel.Box b = queue.Dequeue();
                    lock (b.Adjacent)
                    {
                        int parentGScore = visited[b];
                        for (int i = 0; i < b.Adjacent.Count; i++)
                        {
                            Voxel.Box adjacent        = b.Adjacent[i];
                            int       tentativeGScore = parentGScore + adjacent.Width * adjacent.Height * adjacent.Depth;
                            int       previousGScore;
                            if (!visited.TryGetValue(adjacent, out previousGScore) || tentativeGScore < previousGScore)
                            {
                                visited[adjacent] = tentativeGScore;

                                if (parentGScore < radius * radius &&
                                    this.floorCoordinate.X >= adjacent.X - radius && this.floorCoordinate.X < adjacent.X + adjacent.Width + radius &&
                                    this.floorCoordinate.Y >= adjacent.Y - radius && this.floorCoordinate.Y < adjacent.Y + adjacent.Height + radius &&
                                    this.floorCoordinate.Z >= adjacent.Z - radius && this.floorCoordinate.Z < adjacent.Z + adjacent.Depth + radius)
                                {
                                    if (adjacent.Type != Voxel.States.Blue && adjacent.Type != Voxel.States.Powered)
                                    {
                                        // Non-blue block. It's close enough, we can build a floor
                                        result = true;
                                        break;
                                    }
                                    else
                                    {
                                        queue.Enqueue(adjacent);
                                    }
                                }
                            }
                        }
                    }
                    if (result)
                    {
                        break;
                    }
                }
            }
            else
            {
                result = true;
            }
            return(result);
        }
Пример #10
0
        public void Update(float dt)
        {
            Entity mapEntity = this.Voxel.Value.Target;

            if (mapEntity == null || !mapEntity.Active)
            {
                // Find closest map
                int         closest  = 5;
                Voxel.Coord newCoord = default(Voxel.Coord);
                foreach (Voxel m in Lemma.Components.Voxel.Voxels)
                {
                    Voxel.Coord mCoord = m.GetCoordinate(this.Position);
                    Voxel.Coord?c      = m.FindClosestFilledCell(mCoord, closest);
                    if (c.HasValue)
                    {
                        mapEntity = m.Entity;
                        newCoord  = c.Value;
                        closest   = Math.Min(Math.Abs(mCoord.X - newCoord.X), Math.Min(Math.Abs(mCoord.Y - newCoord.Y), Math.Abs(mCoord.Z - newCoord.Z)));
                    }
                }
                if (mapEntity == null)
                {
                    this.Delete.Execute();
                }
                else
                {
                    this.Voxel.Value = mapEntity;
                    this.Coord.Value = this.LastCoord.Value = newCoord;
                    this.Blend.Value = 1.0f;
                }
            }
            else
            {
                Voxel m = mapEntity.Get <Voxel>();

                if (this.EnableMovement)
                {
                    this.Blend.Value += dt * this.Speed;
                }

                if (this.Blend > 1.0f)
                {
                    this.Blend.Value = 0.0f;

                    Voxel.Coord c = this.Coord.Value;

                    this.Moved.Execute(m, c);

                    this.LastCoord.Value = c;

                    if (this.EnablePathfinding)
                    {
                        if (this.broadphasePath.Count == 0 || this.main.TotalTime - this.lastPathCalculation > 1.0f)
                        {
                            this.lastPathCalculation = this.main.TotalTime;
                            Voxel.Coord?targetCoord = m.FindClosestFilledCell(m.GetCoordinate(this.Target));
                            if (targetCoord.HasValue)
                            {
                                this.narrowphasePath.Clear();
                                this.broadphasePath.Clear();
                                Voxel.Box box = m.GetBox(c);
                                VoxelAStar.Broadphase(m, box, targetCoord.Value, this.Filter, this.broadphasePath);
                                if (this.broadphasePath.Count > 0)
                                {
                                    this.broadphasePath.Pop();                                     // First box is the current one
                                }
                                //this.debugBroadphase(m, this.broadphasePath);
                            }
                        }

                        if (this.narrowphasePath.Count == 0 && this.broadphasePath.Count > 0)
                        {
                            VoxelAStar.Narrowphase(m, this.Coord, this.broadphasePath.Pop(), this.narrowphasePath);
                            if (this.narrowphasePath.Count <= 1)
                            {
                                this.broadphasePath.Clear();
                                this.narrowphasePath.Clear();
                                this.Blend.Value = 1.0f;
                            }
                            else
                            {
                                this.narrowphasePath.Pop();                                 // First coordinate is the current one
                            }
                            //this.debugNarrowphase(m, this.narrowphasePath);
                        }

                        if (this.narrowphasePath.Count > 0)
                        {
                            Voxel.Coord newCoord = this.narrowphasePath.Pop();
                            if (this.Filter(m[newCoord]))
                            {
                                this.Coord.Value = newCoord;
                            }
                            else
                            {
                                this.broadphasePath.Clear();
                                this.narrowphasePath.Clear();
                                this.Blend.Value = 1.0f;
                            }
                        }
                    }
                }

                Vector3 last = m.GetAbsolutePosition(this.LastCoord), current = m.GetAbsolutePosition(this.Coord);
                this.Position.Value = Vector3.Lerp(last, current, this.Blend);
            }
        }