Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
SubsystemFluidBlockBehavior.cs
浏览该文件的文档.
1using Engine;
3
4namespace Game {
6 public static Point2[] m_sideNeighbors = [new(-1, 0), new(1, 0), new(0, -1), new(0, 1)];
7
9
10 public Dictionary<Point3, bool> m_toUpdate = [];
11
12 public Dictionary<Point3, int> m_toSet = [];
13
14 public Dictionary<Point3, int> m_visited = [];
15
16 public Dictionary<Point3, Vector2> m_fluidRandomFlowDirections = [];
17
18 public bool m_generateSources;
19
20 public SubsystemTime SubsystemTime { get; set; }
21
22 public SubsystemAudio SubsystemAudio { get; set; }
23
25
26 public SubsystemFluidBlockBehavior(FluidBlock fluidBlock, bool generateSources) {
27 m_fluidBlock = fluidBlock;
28 m_generateSources = generateSources;
29 }
30
31 public virtual void UpdateIsTop(int value, int x, int y, int z) {
32 Terrain terrain = SubsystemTerrain.Terrain;
33 if (y < 255) {
34 TerrainChunk chunkAtCell = terrain.GetChunkAtCell(x, z);
35 if (chunkAtCell != null) {
36 int num = TerrainChunk.CalculateCellIndex(x & 0xF, y, z & 0xF);
37 int contents = Terrain.ExtractContents(chunkAtCell.GetCellValueFast(num + 1));
38 int data = Terrain.ExtractData(value);
39 bool isTop = !m_fluidBlock.IsTheSameFluid(contents);
40 chunkAtCell.SetCellValueFast(num, Terrain.ReplaceData(value, FluidBlock.SetIsTop(data, isTop)));
41 }
42 }
43 }
44
45 public override void OnBlockAdded(int value, int oldValue, int x, int y, int z) {
46 UpdateIsTop(value, x, y, z);
47 }
48
49 public override void OnBlockModified(int value, int oldValue, int x, int y, int z) {
50 UpdateIsTop(value, x, y, z);
51 }
52
53 public override void OnNeighborBlockChanged(int x, int y, int z, int neighborX, int neighborY, int neighborZ) {
54 m_toUpdate[new Point3 { X = x, Y = y, Z = z }] = true;
55 if (neighborY == y + 1) {
56 UpdateIsTop(SubsystemTerrain.Terrain.GetCellValueFast(x, y, z), x, y, z);
57 }
58 }
59
60 public override void OnItemHarvested(int x, int y, int z, int blockValue, ref BlockDropValue dropValue, ref int newBlockValue) {
61 newBlockValue = Terrain.MakeBlockValue(m_fluidBlock.BlockIndex);
62 dropValue.Value = 0;
63 dropValue.Count = 0;
64 }
65
66 public float? GetSurfaceHeight(int x, int y, int z, out FluidBlock surfaceFluidBlock) {
67 if (y >= 0
68 && y < 255) {
69 TerrainChunk chunkAtCell = SubsystemTerrain.Terrain.GetChunkAtCell(x, z);
70 if (chunkAtCell != null) {
71 int num = TerrainChunk.CalculateCellIndex(x & 0xF, 0, z & 0xF);
72 while (y < 255) {
73 int num2 = Terrain.ExtractContents(chunkAtCell.GetCellValueFast(num + y + 1));
74 if (BlocksManager.FluidBlocks[num2] == null) {
75 int cellValueFast = chunkAtCell.GetCellValueFast(num + y);
76 int num3 = Terrain.ExtractContents(cellValueFast);
77 FluidBlock fluidBlock = BlocksManager.FluidBlocks[num3];
78 if (fluidBlock != null) {
79 surfaceFluidBlock = fluidBlock;
80 int level = FluidBlock.GetLevel(Terrain.ExtractData(cellValueFast));
81 return y + surfaceFluidBlock.GetLevelHeight(level);
82 }
83 surfaceFluidBlock = null;
84 return null;
85 }
86 y++;
87 }
88 }
89 }
90 surfaceFluidBlock = null;
91 return null;
92 }
93
94 public float? GetSurfaceHeight(int x, int y, int z) => GetSurfaceHeight(x, y, z, out FluidBlock _);
95
96 public Vector2? CalculateFlowSpeed(int x, int y, int z, out FluidBlock surfaceBlock, out float? surfaceHeight) {
97 surfaceHeight = GetSurfaceHeight(x, y, z, out surfaceBlock);
98 if (surfaceHeight.HasValue) {
99 y = (int)surfaceHeight.Value;
100 int cellValue = SubsystemTerrain.Terrain.GetCellValue(x, y, z);
101 int num = Terrain.ExtractContents(cellValue);
102 if (BlocksManager.Blocks[num] is FluidBlock) {
103 int cellValue2 = SubsystemTerrain.Terrain.GetCellValue(x - 1, y, z);
104 int cellValue3 = SubsystemTerrain.Terrain.GetCellValue(x + 1, y, z);
105 int cellValue4 = SubsystemTerrain.Terrain.GetCellValue(x, y, z - 1);
106 int cellValue5 = SubsystemTerrain.Terrain.GetCellValue(x, y, z + 1);
107 int num2 = Terrain.ExtractContents(cellValue2);
108 int num3 = Terrain.ExtractContents(cellValue3);
109 int num4 = Terrain.ExtractContents(cellValue4);
110 int num5 = Terrain.ExtractContents(cellValue5);
111 int level = FluidBlock.GetLevel(Terrain.ExtractData(cellValue));
112 int num6 = num2 == num ? FluidBlock.GetLevel(Terrain.ExtractData(cellValue2)) : level;
113 int num7 = num3 == num ? FluidBlock.GetLevel(Terrain.ExtractData(cellValue3)) : level;
114 int num8 = num4 == num ? FluidBlock.GetLevel(Terrain.ExtractData(cellValue4)) : level;
115 int num9 = num5 == num ? FluidBlock.GetLevel(Terrain.ExtractData(cellValue5)) : level;
116 Vector2 vector = default;
117 vector.X = Math.Sign(level - num6) - Math.Sign(level - num7);
118 vector.Y = Math.Sign(level - num8) - Math.Sign(level - num9);
119 Vector2 v = vector;
120 if (v.LengthSquared() > 1f) {
121 v = Vector2.Normalize(v);
122 }
123 if (!m_fluidRandomFlowDirections.TryGetValue(new Point3(x, y, z), out Vector2 value)) {
124 value.X = 0.05f * (2f * SimplexNoise.OctavedNoise(x + 0.2f * (float)SubsystemTime.GameTime, z, 0.1f, 1, 1f, 1f) - 1f);
125 value.Y = 0.05f * (2f * SimplexNoise.OctavedNoise(x + 0.2f * (float)SubsystemTime.GameTime + 100f, z, 0.1f, 1, 1f, 1f) - 1f);
126 if (m_fluidRandomFlowDirections.Count < 1000) {
127 m_fluidRandomFlowDirections[new Point3(x, y, z)] = value;
128 }
129 else {
131 }
132 }
133 v += value;
134 return v * 2f;
135 }
136 }
137 return null;
138 }
139
140 public Vector2? CalculateFlowSpeed(int x, int y, int z) => CalculateFlowSpeed(x, y, z, out FluidBlock _, out float? _);
141
142 public override void Load(ValuesDictionary valuesDictionary) {
143 base.Load(valuesDictionary);
144 SubsystemTime = Project.FindSubsystem<SubsystemTime>(true);
145 SubsystemAudio = Project.FindSubsystem<SubsystemAudio>(true);
147 }
148
149 public void SpreadFluid() {
150 for (int i = 0; i < 2; i++) {
151 foreach (Point3 key in m_toUpdate.Keys) {
152 int x = key.X;
153 int y = key.Y;
154 int z = key.Z;
155 int cellValue = SubsystemTerrain.Terrain.GetCellValue(x, y, z);
156 int contents = Terrain.ExtractContents(cellValue);
157 int data = Terrain.ExtractData(cellValue);
158 int level = FluidBlock.GetLevel(data);
159 if (m_fluidBlock.IsTheSameFluid(contents)) {
160 int cellValue2 = SubsystemTerrain.Terrain.GetCellValue(x, y - 1, z);
161 int contents2 = Terrain.ExtractContents(cellValue2);
162 int data2 = Terrain.ExtractData(cellValue2);
163 int level2 = FluidBlock.GetLevel(data2);
164 int num = m_fluidBlock.MaxLevel + 1;
165 int num2 = 0;
166 for (int j = 0; j < 4; j++) {
167 int cellValue3 = SubsystemTerrain.Terrain.GetCellValue(x + m_sideNeighbors[j].X, y, z + m_sideNeighbors[j].Y);
168 int contents3 = Terrain.ExtractContents(cellValue3);
169 if (m_fluidBlock.IsTheSameFluid(contents3)) {
170 int level3 = FluidBlock.GetLevel(Terrain.ExtractData(cellValue3));
171 num = MathUtils.Min(num, level3);
172 if (level3 == 0) {
173 num2++;
174 }
175 }
176 }
177 if (level != 0
178 && level <= num) {
179 int contents4 = Terrain.ExtractContents(SubsystemTerrain.Terrain.GetCellValue(x, y + 1, z));
180 if (!m_fluidBlock.IsTheSameFluid(contents4)) {
181 Set(
182 x,
183 y,
184 z,
185 num + 1 > m_fluidBlock.MaxLevel ? 0 : Terrain.MakeBlockValue(contents, 0, FluidBlock.SetLevel(data, num + 1))
186 );
187 continue;
188 }
189 }
191 && level != 0
192 && num2 >= 2) {
193 Set(x, y, z, Terrain.MakeBlockValue(contents, 0, FluidBlock.SetLevel(data, 0)));
194 }
195 else if (m_fluidBlock.IsTheSameFluid(contents2)) {
196 if (level2 > 1) {
197 Set(x, y - 1, z, Terrain.MakeBlockValue(contents2, 0, FluidBlock.SetLevel(data2, 1)));
198 }
199 }
200 else if (!OnFluidInteract(
201 cellValue2,
202 x,
203 y - 1,
204 z,
206 )
207 && level < m_fluidBlock.MaxLevel) {
208 m_visited.Clear();
209 int num3 = LevelAtNearestFall(x + 1, y, z, level + 1, m_visited);
210 int num4 = LevelAtNearestFall(x - 1, y, z, level + 1, m_visited);
211 int num5 = LevelAtNearestFall(x, y, z + 1, level + 1, m_visited);
212 int num6 = LevelAtNearestFall(x, y, z - 1, level + 1, m_visited);
213 int num7 = MathUtils.Min(num3, num4, num5, num6);
214 if (num3 == num7) {
215 FlowTo(x + 1, y, z, level + 1);
216 FlowTo(x, y, z - 1, m_fluidBlock.MaxLevel);
217 FlowTo(x, y, z + 1, m_fluidBlock.MaxLevel);
218 }
219 if (num4 == num7) {
220 FlowTo(x - 1, y, z, level + 1);
221 FlowTo(x, y, z - 1, m_fluidBlock.MaxLevel);
222 FlowTo(x, y, z + 1, m_fluidBlock.MaxLevel);
223 }
224 if (num5 == num7) {
225 FlowTo(x, y, z + 1, level + 1);
226 FlowTo(x - 1, y, z, m_fluidBlock.MaxLevel);
227 FlowTo(x + 1, y, z, m_fluidBlock.MaxLevel);
228 }
229 if (num6 == num7) {
230 FlowTo(x, y, z - 1, level + 1);
231 FlowTo(x - 1, y, z, m_fluidBlock.MaxLevel);
232 FlowTo(x + 1, y, z, m_fluidBlock.MaxLevel);
233 }
234 }
235 }
236 }
237 m_toUpdate.Clear();
238 foreach (KeyValuePair<Point3, int> item in m_toSet) {
239 int x2 = item.Key.X;
240 int y2 = item.Key.Y;
241 int z2 = item.Key.Z;
242 int value = item.Value;
243 int contents5 = Terrain.ExtractContents(item.Value);
244 int cellContents = SubsystemTerrain.Terrain.GetCellContents(x2, y2, z2);
245 FluidBlock fluidBlock = BlocksManager.FluidBlocks[cellContents];
246 if (fluidBlock != null
247 && !fluidBlock.IsTheSameFluid(contents5)) {
248 SubsystemTerrain.DestroyCell(
249 0,
250 x2,
251 y2,
252 z2,
253 value,
254 false,
255 false
256 );
257 }
258 else {
259 SubsystemTerrain.ChangeCell(x2, y2, z2, value);
260 }
261 }
262 m_toSet.Clear();
263 SubsystemTerrain.ProcessModifiedCells();
264 }
265 }
266
267 public virtual bool OnFluidInteract(int interactValue, int x, int y, int z, int fluidValue) {
268 if (!BlocksManager.Blocks[Terrain.ExtractContents(interactValue)].IsFluidBlocker_(interactValue)) {
269 SubsystemTerrain.DestroyCell(
270 0,
271 x,
272 y,
273 z,
274 0,
275 false,
276 false
277 );
278 Set(x, y, z, fluidValue);
279 return true;
280 }
281 return false;
282 }
283
284 public float? CalculateDistanceToFluid(Vector3 p, int radius, bool flowingFluidOnly) {
285 float num = float.MaxValue;
286 Terrain terrain = SubsystemTerrain.Terrain;
287 int num2 = Terrain.ToCell(p.X) - radius;
288 int num3 = Terrain.ToCell(p.X) + radius;
289 int num4 = Math.Clamp(Terrain.ToCell(p.Y) - radius, 0, 254);
290 int num5 = Math.Clamp(Terrain.ToCell(p.Y) + radius, 0, 254);
291 int num6 = Terrain.ToCell(p.Z) - radius;
292 int num7 = Terrain.ToCell(p.Z) + radius;
293 for (int i = num6; i <= num7; i++) {
294 for (int j = num2; j <= num3; j++) {
295 TerrainChunk chunkAtCell = terrain.GetChunkAtCell(j, i);
296 if (chunkAtCell == null) {
297 continue;
298 }
299 int k = TerrainChunk.CalculateCellIndex(j & 0xF, num4, i & 0xF);
300 for (int l = num4; l <= num5; l++, k++) {
301 int cellValueFast = chunkAtCell.GetCellValueFast(k);
302 int contents = Terrain.ExtractContents(cellValueFast);
303 if (!m_fluidBlock.IsTheSameFluid(contents)) {
304 continue;
305 }
306 if (flowingFluidOnly) {
307 if (FluidBlock.GetLevel(Terrain.ExtractData(cellValueFast)) == 0) {
308 continue;
309 }
310 int contents2 = Terrain.ExtractContents(chunkAtCell.GetCellValueFast(k + 1));
311 if (m_fluidBlock.IsTheSameFluid(contents2)) {
312 continue;
313 }
314 }
315 float num8 = p.X - (j + 0.5f);
316 float num9 = p.Y - (l + 1f);
317 float num10 = p.Z - (i + 0.5f);
318 float num11 = num8 * num8 + num9 * num9 + num10 * num10;
319 if (num11 < num) {
320 num = num11;
321 }
322 }
323 }
324 }
325 if (num == float.MaxValue) {
326 return null;
327 }
328 return MathF.Sqrt(num);
329 }
330
331 public void Set(int x, int y, int z, int value) {
332 Point3 key = new(x, y, z);
333 m_toSet.TryAdd(key, value);
334 }
335
336 public void FlowTo(int x, int y, int z, int level) {
337 if (level > m_fluidBlock.MaxLevel) {
338 return;
339 }
340 int cellValue = SubsystemTerrain.Terrain.GetCellValue(x, y, z);
341 int contents = Terrain.ExtractContents(cellValue);
342 int data = Terrain.ExtractData(cellValue);
343 if (m_fluidBlock.IsTheSameFluid(contents)) {
344 int level2 = FluidBlock.GetLevel(data);
345 if (level < level2) {
346 Set(x, y, z, Terrain.MakeBlockValue(contents, 0, FluidBlock.SetLevel(data, level)));
347 }
348 }
349 else {
350 OnFluidInteract(cellValue, x, y, z, Terrain.MakeBlockValue(m_fluidBlock.BlockIndex, 0, FluidBlock.SetLevel(0, level)));
351 }
352 }
353
354 public int LevelAtNearestFall(int x, int y, int z, int level, Dictionary<Point3, int> levels) {
355 if (level > m_fluidBlock.MaxLevel) {
356 return int.MaxValue;
357 }
358 if (!levels.TryGetValue(new Point3(x, y, z), out int value)) {
359 value = int.MaxValue;
360 }
361 if (level >= value) {
362 return int.MaxValue;
363 }
364 levels[new Point3(x, y, z)] = level;
365 int cellValue = SubsystemTerrain.Terrain.GetCellValue(x, y, z);
366 int num = Terrain.ExtractContents(cellValue);
367 if (m_fluidBlock.IsTheSameFluid(num)) {
368 if (FluidBlock.GetLevel(Terrain.ExtractData(cellValue)) < level) {
369 return int.MaxValue;
370 }
371 }
372 else if (BlocksManager.Blocks[num].IsFluidBlocker_(cellValue)) {
373 return int.MaxValue;
374 }
375 int cellValue2 = SubsystemTerrain.Terrain.GetCellValue(x, y - 1, z);
376 int num2 = Terrain.ExtractContents(cellValue2);
377 Block block = BlocksManager.Blocks[num2];
378 if (m_fluidBlock.IsTheSameFluid(num2)
379 || !block.IsFluidBlocker_(cellValue2)) {
380 return level;
381 }
382 int x2 = LevelAtNearestFall(x - 1, y, z, level + 1, levels);
383 int x3 = LevelAtNearestFall(x + 1, y, z, level + 1, levels);
384 int x4 = LevelAtNearestFall(x, y, z - 1, level + 1, levels);
385 int x5 = LevelAtNearestFall(x, y, z + 1, level + 1, levels);
386 return MathUtils.Min(x2, x3, x4, x5);
387 }
388 }
389}
static int Min(int x1, int x2)
virtual bool IsFluidBlocker_(int value)
static FluidBlock[] FluidBlocks
static int GetLevel(int data)
static int SetLevel(int data, int level)
bool IsTheSameFluid(int contents)
static int SetIsTop(int data, bool isTop)
static float OctavedNoise(float x, float frequency, int octaves, float frequencyStep, float amplitudeStep, bool ridged=false)
void FlowTo(int x, int y, int z, int level)
void Set(int x, int y, int z, int value)
Dictionary< Point3, Vector2 > m_fluidRandomFlowDirections
virtual bool OnFluidInteract(int interactValue, int x, int y, int z, int fluidValue)
int LevelAtNearestFall(int x, int y, int z, int level, Dictionary< Point3, int > levels)
float? GetSurfaceHeight(int x, int y, int z, out FluidBlock surfaceFluidBlock)
override void OnItemHarvested(int x, int y, int z, int blockValue, ref BlockDropValue dropValue, ref int newBlockValue)
override void OnNeighborBlockChanged(int x, int y, int z, int neighborX, int neighborY, int neighborZ)
float? CalculateDistanceToFluid(Vector3 p, int radius, bool flowingFluidOnly)
virtual void UpdateIsTop(int value, int x, int y, int z)
Vector2? CalculateFlowSpeed(int x, int y, int z, out FluidBlock surfaceBlock, out float? surfaceHeight)
override void OnBlockAdded(int value, int oldValue, int x, int y, int z)
override void Load(ValuesDictionary valuesDictionary)
SubsystemFluidBlockBehavior(FluidBlock fluidBlock, bool generateSources)
override void OnBlockModified(int value, int oldValue, int x, int y, int z)
static int CalculateCellIndex(int x, int y, int z)
virtual int GetCellValueFast(int index)
virtual void SetCellValueFast(int x, int y, int z, int value)
static int ExtractContents(int value)
static int ReplaceData(int value, int data)
static int ToCell(float x)
virtual TerrainChunk GetChunkAtCell(int x, int z)
static int MakeBlockValue(int contents)
static int ExtractData(int value)
ValuesDictionary ValuesDictionary
static Vector2 Normalize(Vector2 v)
float LengthSquared()