public static void AddSunlightRemovals(ref NativeArray3x3 <Light> lights, NativeList <TorchLightOp> lightOps, NativeQueue <LightRemovalNode> lrbfs) { for (int loi = 0; loi < lightOps.Length; ++loi) { TorchLightOp op = lightOps[loi]; int opx = op.index % S; int opy = op.index / (S * S); int opz = (op.index % (S * S)) / S; int startIndex = (opx + S) + (opz + S) * W + (opy + S) * W * W; Light curLight = lights.Get(opx, opy, opz); lrbfs.Enqueue(new LightRemovalNode { index = startIndex, light = curLight.sun }); curLight.sun = 0; lights.Set(opx, opy, opz, curLight); } }
public static void ProcessTorchLightOpsOptimal(ref NativeArray3x3 <Light> lights, ref NativeArray3x3 <Block> blocks, NativeArray <BlockData> blockData, NativeList <TorchLightOp> ops, NativeQueue <int> lbfs, NativeQueue <LightRemovalNode> lrbfs) { lights.flags = 0; // set blocks at torchlightops to have correct is light flag set for (int opIndex = 0; opIndex < ops.Length; ++opIndex) { TorchLightOp op = ops[opIndex]; int opx = op.index % S; int opy = op.index / (S * S); int opz = (op.index % (S * S)) / S; Light opLight = lights.Get(opx, opy, opz); opLight.torch = SetIsLight(opLight.torch, op.val > 0); lights.Set(opx, opy, opz, opLight); } // loop over each color channel of torch light for (int cIndex = 0; cIndex < 3; cIndex++) { for (int oi = 0; oi < ops.Length;) { // check to see what type of operation first op is bool isProp = GetChannel(ops[oi].val, cIndex) != 0; // queue up each matching operation type until you hit end or mismatch while (oi < ops.Length) { TorchLightOp op = ops[oi]; int opChannel = GetChannel(op.val, cIndex); if ((opChannel != 0) != isProp) { break; // this ops type is different from first in run } int opx = op.index % S; int opy = op.index / (S * S); int opz = (op.index % (S * S)) / S; int startIndex = (opx + S) + (opz + S) * W + (opy + S) * W * W; Light curLight = lights.Get(opx, opy, opz); int curChannel = GetChannel(curLight.torch, cIndex); if (isProp) { // set the new light value here Light newLight = curLight; newLight.torch = SetChannel(newLight.torch, cIndex, opChannel); lights.Set(opx, opy, opz, newLight); // if the new ops channel value is same as current light channel then add to propagate if (opChannel > curChannel) { lbfs.Enqueue(startIndex); } } else { lrbfs.Enqueue(new LightRemovalNode { index = startIndex, light = (byte)curChannel }); curLight.torch = SetChannel(curLight.torch, cIndex, 0); lights.Set(opx, opy, opz, curLight); } oi++; } if (!isProp) { while (lrbfs.Count > 0) { LightRemovalNode node = lrbfs.Dequeue(); // extract coords from index int x = node.index % W - S; int y = node.index / (W * W) - S; int z = (node.index % (W * W)) / W - S; byte oneLess = (byte)(node.light - 1); // each time reduce light by one //ushort westLight = light.Get(x - 1, y, z).torch; Light westLight = lights.Get(x - 1, y, z); byte westChannel = (byte)GetChannel(westLight.torch, cIndex); if (westChannel != 0) { int index = x - 1 + S + (z + S) * W + (y + S) * W * W; if (westChannel < node.light) { if (!GetIsLight(westLight.torch)) { westLight.torch = SetChannel(westLight.torch, cIndex, 0); lights.Set(x - 1, y, z, westLight); } else // if this node is a light, dont override value, but still add a removal node as if you did, then add to repropagate to fill it back in { lbfs.Enqueue(index); } lrbfs.Enqueue(new LightRemovalNode { index = index, light = oneLess }); } else // add to propagate queue so can fill gaps left behind by removal { lbfs.Enqueue(index); } } Light downLight = lights.Get(x, y - 1, z); byte downChannel = (byte)GetChannel(downLight.torch, cIndex); if (downChannel != 0) { int index = x + S + (z + S) * W + (y - 1 + S) * W * W; if (downChannel < node.light) { if (!GetIsLight(downLight.torch)) { downLight.torch = SetChannel(downLight.torch, cIndex, 0); lights.Set(x, y - 1, z, downLight); } else { lbfs.Enqueue(index); } lrbfs.Enqueue(new LightRemovalNode { index = index, light = oneLess }); } else // add to propagate queue so can fill gaps left behind by removal { lbfs.Enqueue(index); } } Light southLight = lights.Get(x, y, z - 1); byte southChannel = (byte)GetChannel(southLight.torch, cIndex); if (southChannel != 0) { int index = x + S + (z - 1 + S) * W + (y + S) * W * W; if (southChannel < node.light) { if (!GetIsLight(southLight.torch)) { southLight.torch = SetChannel(southLight.torch, cIndex, 0); lights.Set(x, y, z - 1, southLight); } else { lbfs.Enqueue(index); } lrbfs.Enqueue(new LightRemovalNode { index = index, light = oneLess }); } else // add to propagate queue so can fill gaps left behind by removal { lbfs.Enqueue(index); } } Light eastLight = lights.Get(x + 1, y, z); byte eastChannel = (byte)GetChannel(eastLight.torch, cIndex); if (eastChannel != 0) { int index = x + 1 + S + (z + S) * W + (y + S) * W * W; if (eastChannel < node.light) { if (!GetIsLight(eastLight.torch)) { eastLight.torch = SetChannel(eastLight.torch, cIndex, 0); lights.Set(x + 1, y, z, eastLight); } else { lbfs.Enqueue(index); } lrbfs.Enqueue(new LightRemovalNode { index = index, light = oneLess }); } else // add to propagate queue so can fill gaps left behind by removal { lbfs.Enqueue(index); } } Light upLight = lights.Get(x, y + 1, z); byte upChannel = (byte)GetChannel(upLight.torch, cIndex); if (upChannel != 0) { int index = x + S + (z + S) * W + (y + 1 + S) * W * W; if (upChannel < node.light) { if (!GetIsLight(upLight.torch)) { upLight.torch = SetChannel(upLight.torch, cIndex, 0); lights.Set(x, y + 1, z, upLight); } else { lbfs.Enqueue(index); } lrbfs.Enqueue(new LightRemovalNode { index = index, light = oneLess }); } else // add to propagate queue so can fill gaps left behind by removal { lbfs.Enqueue(index); } } Light northLight = lights.Get(x, y, z + 1); byte northChannel = (byte)GetChannel(northLight.torch, cIndex); if (northChannel != 0) { int index = x + S + (z + 1 + S) * W + (y + S) * W * W; if (northChannel < node.light) { if (!GetIsLight(northLight.torch)) { northLight.torch = SetChannel(northLight.torch, cIndex, 0); lights.Set(x, y, z + 1, northLight); } else { lbfs.Enqueue(index); } lrbfs.Enqueue(new LightRemovalNode { index = index, light = oneLess }); } else // add to propagate queue so can fill gaps left behind by removal { lbfs.Enqueue(index); } } } } // propagate either way while (lbfs.Count > 0) { int index = lbfs.Dequeue(); // extract coords from index int x = index % W - S; int y = index / (W * W) - S; int z = (index % (W * W)) / W - S; // get light level at this node int mChan = GetChannel(lights.Get(x, y, z).torch, cIndex); //if(mChan == 0) { // can happen frequently when batching together light removals // continue; //} // check each neighbor blocks light reduction value // if neighbor light level is 2 or more levels less than this node, set them to this light-1 and add to queue // also add additional light reduction value byte LR = blockData[blocks.Get(x - 1, y, z).type].lightReduction; if (LR < mChan) // WEST { Light light = lights.Get(x - 1, y, z); if (GetChannel(light.torch, cIndex) + 2 + LR <= mChan) { light.torch = SetChannel(light.torch, cIndex, mChan - 1 - LR); lights.Set(x - 1, y, z, light); lbfs.Enqueue(x - 1 + S + (z + S) * W + (y + S) * W * W); } } LR = blockData[blocks.Get(x, y - 1, z).type].lightReduction; if (LR < mChan) // DOWN { Light light = lights.Get(x, y - 1, z); if (GetChannel(light.torch, cIndex) + 2 + LR <= mChan) { light.torch = SetChannel(light.torch, cIndex, mChan - 1 - LR); lights.Set(x, y - 1, z, light); lbfs.Enqueue(x + S + (z + S) * W + (y - 1 + S) * W * W); } } LR = blockData[blocks.Get(x, y, z - 1).type].lightReduction; if (LR < mChan) // SOUTH { Light light = lights.Get(x, y, z - 1); if (GetChannel(light.torch, cIndex) + 2 + LR <= mChan) { light.torch = SetChannel(light.torch, cIndex, mChan - 1 - LR); lights.Set(x, y, z - 1, light); lbfs.Enqueue(x + S + (z - 1 + S) * W + (y + S) * W * W); } } LR = blockData[blocks.Get(x + 1, y, z).type].lightReduction; if (LR < mChan) // EAST { Light light = lights.Get(x + 1, y, z); if (GetChannel(light.torch, cIndex) + 2 + LR <= mChan) { light.torch = SetChannel(light.torch, cIndex, mChan - 1 - LR); lights.Set(x + 1, y, z, light); lbfs.Enqueue(x + 1 + S + (z + S) * W + (y + S) * W * W); } } LR = blockData[blocks.Get(x, y + 1, z).type].lightReduction; if (LR < mChan) // UP { Light light = lights.Get(x, y + 1, z); if (GetChannel(light.torch, cIndex) + 2 + LR <= mChan) { light.torch = SetChannel(light.torch, cIndex, mChan - 1 - LR); lights.Set(x, y + 1, z, light); lbfs.Enqueue(x + S + (z + S) * W + (y + 1 + S) * W * W); } } LR = blockData[blocks.Get(x, y, z + 1).type].lightReduction; if (LR < mChan) // NORTH { Light light = lights.Get(x, y, z + 1); if (GetChannel(light.torch, cIndex) + 2 + LR <= mChan) { light.torch = SetChannel(light.torch, cIndex, mChan - 1 - LR); lights.Set(x, y, z + 1, light); lbfs.Enqueue(x + S + (z + 1 + S) * W + (y + S) * W * W); } } } } } }