public static Vector3Int ClosestSource(Vector3Int position, EFluids fluid) { FluidInfo info = _fluids[(int)fluid]; LinkedList<TupleStruct<Vector3Int, int>> toVisit = new LinkedList<TupleStruct<Vector3Int, int>>(); toVisit.AddLast(new TupleStruct<Vector3Int, int>(position, 0)); List<Vector3Int> alreadyVisited = new List<Vector3Int>(); while(toVisit.Count > 0) { var node = toVisit.First.Value; toVisit.RemoveFirst(); if(alreadyVisited.Contains(node.item1)) continue; alreadyVisited.Add(node.item1); if(node.item2 == info.distance) continue; foreach(var adjacent in adjacents) { var adj = node.item1 + adjacent; if(!World.TryGetTypeAt(adj, out ushort typeadj)) continue; if(typeadj == info.source) return adj; if(typeadj == info.fake) if(!alreadyVisited.Contains(adj)) toVisit.AddLast(new TupleStruct<Vector3Int, int>(adj, node.item2 + 1)); } } return Vector3Int.maximum; }
public static void LoadConfig() { FluidInfo Water = new FluidInfo(); FluidInfo Lava = new FluidInfo(); Water.source = ItemTypes.IndexLookup.GetIndex("Khanx.SimpleFluids.Water"); Water.fake = ItemTypes.IndexLookup.GetIndex("Khanx.SimpleFluids.Fake.Water"); Water.bucket = ItemTypes.IndexLookup.GetIndex("Khanx.SimpleFluids.WaterBucket"); Lava.source = ItemTypes.IndexLookup.GetIndex("Khanx.SimpleFluids.Lava"); Lava.fake = ItemTypes.IndexLookup.GetIndex("Khanx.SimpleFluids.Fake.Lava"); Lava.bucket = ItemTypes.IndexLookup.GetIndex("Khanx.SimpleFluids.LavaBucket"); try { JSONNode config = JSON.Deserialize(MODPATH + "/config.json"); config.TryGetChild("water", out JSONNode waterConfig); if(!waterConfig.TryGetAs<int>("spreadDistance", out int w_spreadDistance)) Water.distance = W_DEFAULT_DISTANCE; else if(w_spreadDistance > W_MAX_DISTANCE || w_spreadDistance < W_MIN_DISTANCE) { Log.Write(string.Format("<color=red>Warning: Water spreadDistance must be between {0} and {1} included</color>", W_MIN_DISTANCE, W_MAX_DISTANCE)); Water.distance = W_DEFAULT_DISTANCE; } else Water.distance = w_spreadDistance; if(!waterConfig.TryGetAs<long>("spreadSpeed", out long w_spreadSpeed)) Water.time = W_DEFAULT_SPEED; else if(w_spreadSpeed > W_MAX_SPEED || w_spreadSpeed < W_MIN_SPEED) { Log.Write(string.Format("<color=red>Warning: Water spreadSpeed must be between {0} and {1} included</color>", W_MIN_SPEED, W_MAX_SPEED)); Water.time = W_DEFAULT_SPEED; } else Water.time = w_spreadSpeed; config.TryGetChild("lava", out JSONNode lavaConfig); if(!lavaConfig.TryGetAs<int>("spreadDistance", out int l_spreadDistance)) Lava.distance = L_DEFAULT_DISTANCE; else if(l_spreadDistance > L_MAX_DISTANCE || l_spreadDistance < L_MIN_DISTANCE) { Log.Write(string.Format("<color=red>Warning: Lava spreadDistance must be between {0} and {1} included</color>", L_MIN_DISTANCE, L_MAX_DISTANCE)); Lava.distance = L_DEFAULT_DISTANCE; } else Lava.distance = l_spreadDistance; if(!lavaConfig.TryGetAs<long>("spreadSpeed", out long l_spreadSpeed)) Lava.time = L_DEFAULT_SPEED; else if(l_spreadSpeed > L_MAX_SPEED || l_spreadSpeed < L_MIN_SPEED) { Log.Write(string.Format("<color=red>Warning: Lava spreadSpeed must be between {0} and {1} included</color>", L_MIN_SPEED, L_MAX_SPEED)); Lava.time = L_DEFAULT_SPEED; } else Lava.time = l_spreadSpeed; } catch(Exception) { Water.distance = W_DEFAULT_DISTANCE; Water.time = W_DEFAULT_SPEED; Lava.distance = L_DEFAULT_DISTANCE; Lava.time = L_DEFAULT_SPEED; } _fluids[(int)EFluids.Water] = Water; _fluids[(int)EFluids.Lava] = Lava; Buckets.EmptyBucket.fluidsInfo.Add(Water.source, EFluids.Water); Buckets.EmptyBucket.fluidsInfo.Add(BlockTypes.Builtin.BuiltinBlocks.Water, EFluids.Water); Buckets.EmptyBucket.fluidsInfo.Add(Lava.source, EFluids.Lava); }
public static void TryRemove(Vector3Int position, EFluids fluid, int distance = int.MinValue) { //Log.Write(string.Format("<color=blue>TryRemove {0}</color>", position)); FluidInfo info = _fluids[(int)fluid]; if(!World.TryGetTypeAt(position, out ushort typeToRemove) && ( typeToRemove != info.source && typeToRemove != info.fake )) return; if(distance == int.MinValue) distance = info.distance; if(distance < 0) return; if(!World.TryGetTypeAt(position, out ushort type)) return; if(type != info.fake) return; if(ClosestSource(position, fluid) == Vector3Int.maximum) { Pipliz.Threading.ThreadManager.InvokeOnMainThread(() => { if(World.TryGetTypeAt(position, out ushort posToRemove) && ( posToRemove == info.fake )) ServerManager.TryChangeBlock(position, BlockTypes.Builtin.BuiltinBlocks.Air); }); } var down = position + Vector3Int.down; if(!World.TryGetTypeAt(down, out ushort typeDown)) return; if(typeDown == info.source) { _actions.Add(Time.MillisecondsSinceStart + info.time, delegate () { Remove(down, fluid); }); _SomeAction.Set(); return; } foreach(var adjacent in adjacents) { var adj = position + adjacent; if(!World.TryGetTypeAt(adj, out ushort typeAdj)) continue; if(typeAdj == info.fake) { _actions.Add(Time.MillisecondsSinceStart + info.time, delegate () { TryRemove(adj, fluid, distance - 1); }); _SomeAction.Set(); } else if(typeAdj == BlockTypes.Builtin.BuiltinBlocks.Air) { var adjD = adj + Vector3Int.down; if(!World.TryGetTypeAt(adjD, out ushort typeAdjD)) continue; if(typeAdjD == info.source) { _actions.Add(Time.MillisecondsSinceStart + info.time, delegate () { Remove(adjD, fluid); }); _SomeAction.Set(); } } } }
public static void Spread(Vector3Int position, EFluids fluid, int distance = int.MinValue, bool start = true) { //Log.Write(string.Format("<color=blue>Spread {0}</color>", position)); FluidInfo info = _fluids[(int)fluid]; if(distance == int.MinValue) distance = info.distance; if(distance <= 0) return; if(start) { Pipliz.Threading.ThreadManager.InvokeOnMainThread(() => { if(World.TryGetTypeAt(position, out ushort posType) && ( posType == BlockTypes.Builtin.BuiltinBlocks.Air || posType == info.fake )) ServerManager.TryChangeBlock(position, info.source); }); } else { Pipliz.Threading.ThreadManager.InvokeOnMainThread(() => { if(World.TryGetTypeAt(position, out ushort posType) && ( posType == BlockTypes.Builtin.BuiltinBlocks.Air )) ServerManager.TryChangeBlock(position, info.fake); }); } var down = position + Vector3Int.down; if(!World.TryGetTypeAt(down, out ushort typeDown)) return; //If DOWN is source -> IGNORE if(typeDown == info.source) return; //If down is air or fake.fluid -> SPREAD DOWN if(typeDown == BlockTypes.Builtin.BuiltinBlocks.Air || typeDown == info.fake) { _actions.Add(Time.MillisecondsSinceStart + info.time, delegate () { Spread(down, fluid); }); _SomeAction.Set(); return; } foreach(var adjacent in adjacents) { var adj = position + adjacent; if(!World.TryGetTypeAt(adj, out ushort typeAdj)) continue; if(typeAdj == BlockTypes.Builtin.BuiltinBlocks.Air || typeAdj == info.fake) { var adjDown = adj + Vector3Int.down; if(!World.TryGetTypeAt(adjDown, out ushort typeAdjD)) continue; if(typeAdjD == info.source) // Source continue; //Continue spreading down if(typeAdjD == BlockTypes.Builtin.BuiltinBlocks.Air) { _actions.Add(Time.MillisecondsSinceStart + info.time, delegate () { Spread(adjDown, fluid); }); _SomeAction.Set(); } else //Spread Side { _actions.Add(Time.MillisecondsSinceStart + info.time, delegate () { Spread(adj, fluid, distance - 1, false); }); _SomeAction.Set(); } } } }