Пример #1
0
    public static void ProcessSunlight(ref NativeArray3x3 <Light> lights, ref NativeArray3x3 <Block> blocks, NativeArray <BlockData> blockData,
                                       NativeQueue <int> lbfs, NativeQueue <int> lbfs_U, NativeQueue <LightRemovalNode> lrbfs, NativeQueue <LightRemovalNode> lrbfs_U)
    {
        // not sure if going to have sunlightops... the ordering might get boned up on quick place delete operations, but way more efficient this way
        //for (int oi = 0; oi < ops.Length;) {
        //    // check to see what type of operation first op is
        //    bool isProp = ops[oi].val != 0;
        //    // queue up each matching operation type until you hit end or mismatch
        //    while (oi < ops.Length) {
        //        SunLightOp op = ops[oi];
        //        if ((op.val != 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);
        //        if (isProp) {
        //            // set the new light value here
        //            Light newLight = curLight;
        //            newLight.sun = op.val;
        //            lights.Set(opx, opy, opz, newLight);

        //            // if the new sun value is same or less than current dont need to progagate
        //            // this might not happen with sunlight but left check anyways
        //            if (op.val <= curLight.sun) {
        //                continue;
        //            }
        //        } else {
        //            lrbfs.Enqueue(new LightRemovalNode { index = startIndex, light = curLight.sun });
        //            curLight.sun = 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

            Light light = lights.Get(x - 1, y, z);
            if (light.sun != 0)   // WEST
            {
                int index = x - 1 + S + (z + S) * W + (y + S) * W * W;
                if (light.sun < node.light)
                {
                    light.sun = 0;
                    lights.Set(x - 1, y, z, light);
                    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 = lights.Get(x, y - 1, z);
            if (light.sun != 0)   // DOWN
            {
                int index = x + S + (z + S) * W + (y - 1 + S) * W * W;
                if (light.sun < node.light || node.light == MAX_LIGHT)
                {
                    light.sun = 0;
                    lights.Set(x, y - 1, z, light);
                    byte lv = node.light == MAX_LIGHT ? MAX_LIGHT : oneLess;
                    lrbfs.Enqueue(new LightRemovalNode {
                        index = index, light = lv
                    });
                }
                else     // add to propagate queue so can fill gaps left behind by removal
                {
                    lbfs.Enqueue(index);
                }
            }

            light = lights.Get(x, y, z - 1);
            if (light.sun != 0)   // SOUTH
            {
                int index = x + S + (z - 1 + S) * W + (y + S) * W * W;
                if (light.sun < node.light)
                {
                    light.sun = 0;
                    lights.Set(x, y, z - 1, light);
                    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 = lights.Get(x + 1, y, z);
            if (light.sun != 0)   // EAST
            {
                int index = x + 1 + S + (z + S) * W + (y + S) * W * W;
                if (light.sun < node.light)
                {
                    light.sun = 0;
                    lights.Set(x + 1, y, z, light);
                    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 = lights.Get(x, y + 1, z);
            if (light.sun != 0)   // UP
            {
                int index = x + S + (z + S) * W + (y + 1 + S) * W * W;
                if (light.sun < node.light)
                {
                    light.sun = 0;
                    lights.Set(x, y + 1, z, light);
                    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 = lights.Get(x, y, z + 1);
            if (light.sun != 0)   // NORTH
            {
                int index = x + S + (z + 1 + S) * W + (y + S) * W * W;
                if (light.sun < node.light)
                {
                    light.sun = 0;
                    lights.Set(x, y, z + 1, light);
                    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 sunLight = lights.Get(x, y, z).sun;

            // 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 < sunLight)   // WEST
            {
                Light light = lights.Get(x - 1, y, z);
                if (light.sun + 2 + LR <= sunLight)
                {
                    light.sun = (byte)(sunLight - 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 < sunLight)   // DOWN
            {
                Light light = lights.Get(x, y - 1, z);
                if (light.sun + 2 + LR <= sunLight)
                {
                    if (sunLight == MAX_LIGHT)   // if at maxlight dont reduce by 1 each time
                    {
                        light.sun = (byte)(sunLight - LR);
                    }
                    else
                    {
                        light.sun = (byte)(sunLight - 1 - LR);
                    }
                    lights.Set(x, y - 1, z, light);
                    if (y <= -31)
                    {
                        lbfs_U.Enqueue(x + S + (z + S) * W + (32 + S) * W * W); // add to unfinished queue and shift index to be proper for downdown chunk
                    }
                    else
                    {
                        lbfs.Enqueue(x + S + (z + S) * W + (y - 1 + S) * W * W);
                    }
                }
            }
            LR = blockData[blocks.Get(x, y, z - 1).type].lightReduction;
            if (LR < sunLight)   // SOUTH
            {
                Light light = lights.Get(x, y, z - 1);
                if (light.sun + 2 + LR <= sunLight)
                {
                    light.sun = (byte)(sunLight - 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 < sunLight)   // EAST
            {
                Light light = lights.Get(x + 1, y, z);
                if (light.sun + 2 + LR <= sunLight)
                {
                    light.sun = (byte)(sunLight - 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 < sunLight)   // UP
            {
                Light light = lights.Get(x, y + 1, z);
                if (light.sun + 2 + LR <= sunLight)
                {
                    light.sun = (byte)(sunLight - 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 < sunLight)   // NORTH
            {
                Light light = lights.Get(x, y, z + 1);
                if (light.sun + 2 + LR <= sunLight)
                {
                    light.sun = (byte)(sunLight - 1 - LR);
                    lights.Set(x, y, z + 1, light);
                    lbfs.Enqueue(x + S + (z + 1 + S) * W + (y + S) * W * W);
                }
            }
        }
    }
Пример #2
0
    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);
                        }
                    }
                }
            }
        }
    }