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(); } } }
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); }
// 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); }
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(); }
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(); } } })); }
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); }
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); } }
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); }
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); }
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); } }