Ejemplo n.º 1
0
 public BlockValue(bool transparent, string name = "", string packName = "")
 {
     this.name = name;
     if (allBlocks == null)
     {
         allBlocks     = new BlockValue[initialSize];
         nameToBlockId = new Dictionary <string, int>();
         largestIdMag  = 2;
     }
     largestIdMag += 1;
     if (transparent)
     {
         AddNewBlockDelayed(-largestIdMag, name, packName);
     }
     else
     {
         AddNewBlockDelayed(largestIdMag, name, packName);
     }
 }
Ejemplo n.º 2
0
 public static int StringToBlockId(string blockName)
 {
     return(BlockValue.BlockNameToId(blockName));
 }
Ejemplo n.º 3
0
 public static string BlockIdToString(int blockId)
 {
     return(BlockValue.IdToBlockName(blockId));
 }
Ejemplo n.º 4
0
 public static void SetupAirAndWildcard()
 {
     Air      = new BlockValue(0, "Air");
     Wildcard = new BlockValue(-1, "Wildcard");
 }
Ejemplo n.º 5
0
        public static void LoadIdConfigFromJsonString(string idConfig)
        {
            // remove any previous blocks
            BlockValue[] prevBlocks = allBlocks;
            Dictionary <string, BlockValue> allPrevBlocks = new Dictionary <string, BlockValue>();

            for (int i = 0; i < prevBlocks.Length; i++)
            {
                if (prevBlocks[i] != null && prevBlocks[i].name != "")
                {
                    allPrevBlocks[prevBlocks[i].packName + ":" + prevBlocks[i].name] = prevBlocks[i];
                }
            }
            allBlocks        = null;
            nameToBlockId    = null;
            allBlocksTexture = null;
            largestIdMag     = 0;

            Air      = new BlockValue(0, "Air");
            Wildcard = new BlockValue(-1, "Wildcard");

            SavedBlockValues blockValues = JsonConvert.DeserializeObject <SavedBlockValues>(idConfig);

            for (int i = 0; i < blockValues.blockIds.Length; i++)
            {
                int    blockId   = blockValues.blockIds[i];
                string blockName = blockValues.blockNames[i];
                string blockPack = blockValues.blockPacks[i];

                BlockValue block;
                // we already took care of this above
                if (blockName == "Air")
                {
                    block = Air;
                }
                // we already took care of this above
                else if (blockName == "Wildcard")
                {
                    block = Wildcard;
                }
                // create the block and force the block id
                // note that if the texture doesn't exist anymore, this will force a cross pink rgb(255,0,255) texture to be used instead which should be fairly noticable
                else
                {
                    block = new BlockValue(blockId, blockName, blockPack);
                }

                string packBlockKey = block.packName + ":" + block.name;

                // update the id of the reference and no longer worry about it (since it is updated)
                if (allPrevBlocks.ContainsKey(packBlockKey))
                {
                    BlockValue prevBlock = allPrevBlocks[packBlockKey];
                    prevBlock._id = blockId;
                    allPrevBlocks.Remove(packBlockKey);
                }
            }

            // for all of the old things we haven't assigned to new ids yet, create them
            foreach (KeyValuePair <string, BlockValue> blockNotInSave in allPrevBlocks)
            {
                string     blockName = blockNotInSave.Key;
                BlockValue block     = blockNotInSave.Value;

                BlockValue newBlock = new BlockValue(block.id < 0, block.name, block.packName);
                block._id = newBlock.id;
            }
        }
Ejemplo n.º 6
0
        void AddNewBlock(int id, string name, string packName = "")
        {
            this.name     = name;
            this.packName = packName;
            string texturePath = "";

            if (packName != "")
            {
                texturePath = GetBlockTexturePath(packName, name);
            }
            if (allBlocks == null)
            {
                allBlocks     = new BlockValue[initialSize];
                nameToBlockId = new Dictionary <string, int>();
                largestIdMag  = 2;
                SetupTexture();
            }

            if (allBlocksTexture == null)
            {
                SetupTexture();
            }
            nameToBlockId[name] = id;
            int uid = System.Math.Abs(id);

            // increase number of blocks until we have enough
            while (allBlocks.Length <= uid)
            {
                BlockValue[] newAllBlocks = new BlockValue[allBlocks.Length * 2];
                for (int i = 0; i < allBlocks.Length; i++)
                {
                    newAllBlocks[i] = allBlocks[i];
                }
                allBlocks = newAllBlocks;
                // if we are done doubling the size, create the texture
                if (allBlocks.Length > uid)
                {
                    SetupTexture();
                }
            }
            if (allBlocks[uid] != null)
            {
                UnityEngine.Debug.LogWarning("warning: multiple blocks have id" + uid + "(technically " + id + " with transparency flag)");
            }
            allBlocks[uid] = this;

            _id = id;

            largestIdMag = System.Math.Max(largestIdMag, uid);
            Debug.Log(name + " has id " + id);

            string modelPath = "";

            if (packName != "")
            {
                modelPath = GetBlockModelPath(packName, name);
            }

            if (modelPath != "" && File.Exists(modelPath))
            {
                BlockModel  model    = BlockModel.FromJSONFilePath(modelPath);
                Texture2D[] textures = model.GetTextures();
                for (int i = 0; i < textures.Length; i++)
                {
                    Color[] pixels = textures[i].GetPixels();
                    allBlocksTexture.SetPixels(i * 32, (uid - 1) * 16 * 3, 16 * 2, 16 * 3, pixels);
                }
                allBlocksTexture.Apply();
                File.WriteAllBytes("res.png", allBlocksTexture.EncodeToPNG());

                if (id > 0)
                {
                    _id = -uid;
                    Debug.LogWarning("warning: detected custom model for block " + name + " with updated id " + id + " but we were told it does not have a custom model, set it to custom model anyway");
                }

                customModels[_id] = model;
            }

            else if (texturePath != "")
            {
                if (File.Exists(texturePath))
                {
                    byte[]    imageData    = File.ReadAllBytes(texturePath);
                    Texture2D blockTexture = new Texture2D(2, 2);
                    blockTexture.LoadImage(imageData); // (will automatically resize as needed)
                    blockTexture.Apply();

                    // convert to argb32
                    Texture2D argbTexture = new Texture2D(blockTexture.width, blockTexture.height, TextureFormat.ARGB32, false, true);
                    argbTexture.SetPixels(blockTexture.GetPixels());
                    argbTexture.Apply();
                    Color32[] argbColors = argbTexture.GetPixels32();

                    // check for transparency
                    bool isTransparent = false;
                    for (int j = 0; j < argbColors.Length; j++)
                    {
                        if (argbColors[j].a < 240) // if it is only 240/255 or higher it isn't noticable enough to actually use the transparency
                        {
                            isTransparent = true;
                            break;
                        }
                    }


                    // sign of id should match transparency, fix if not
                    if (isTransparent)
                    {
                        if (id > 0)
                        {
                            _id = -uid;
                            Debug.LogWarning("warning: detected transparent texture for block " + name + " with updated id " + id + " and texture path " + texturePath + " but we were told it is not transparent, set it to transparent anyway");
                        }
                    }
                    else
                    {
                        if (id < 0)
                        {
                            _id = uid;
                            Debug.LogWarning("warning: detected not transparent texture for block " + name + " with updated id " + id + " and texture path " + texturePath + " but we were told it is transparent, set it to not transparent anyway");
                        }
                    }



                    if (argbTexture.width != 16 * 2 || argbTexture.height != 16 * 3)
                    {
                        Debug.Log("rescaling texture of block " + name + " with id " + id + " and texture path " + texturePath);
                        TextureScale.Bilinear(argbTexture, 16 * 2, 16 * 3);
                    }
                    argbTexture.Apply();
                    Color[] pixels = argbTexture.GetPixels();
                    for (int k = 0; k < animFrames; k++)
                    {
                        allBlocksTexture.SetPixels(k * 32, (uid - 1) * 16 * 3, 16 * 2, 16 * 3, pixels);
                    }
                    allBlocksTexture.Apply();
                    File.WriteAllBytes("res.png", allBlocksTexture.EncodeToPNG());
                }
                else
                {
                    //bool animated = false;
                    // test if animated
                    for (int i = 0; i < 32; i++)
                    {
                        string frameITexture = texturePath.Substring(0, texturePath.Length - ".png".Length) + i + ".png";
                        if (File.Exists(frameITexture))
                        {
                            //animated = true;

                            byte[]    imageData    = File.ReadAllBytes(frameITexture);
                            Texture2D blockTexture = new Texture2D(2, 2);
                            blockTexture.LoadImage(imageData); // (will automatically resize as needed)
                            blockTexture.Apply();

                            // convert to argb32
                            Texture2D argbTexture = new Texture2D(blockTexture.width, blockTexture.height, TextureFormat.ARGB32, false, true);
                            argbTexture.SetPixels(blockTexture.GetPixels());
                            argbTexture.Apply();
                            Color32[] argbColors = argbTexture.GetPixels32();

                            // check for transparency
                            bool isTransparent = false;
                            for (int j = 0; j < argbColors.Length; j++)
                            {
                                if (argbColors[j].a < 240) // if it is only 240/255 or higher it isn't noticable enough to actually use the transparency
                                {
                                    isTransparent = true;
                                    break;
                                }
                            }


                            // sign of id should match transparency, fix if not
                            if (isTransparent)
                            {
                                if (id > 0)
                                {
                                    _id = -uid;
                                    Debug.LogWarning("warning: detected transparent texture for block " + name + " with updated id " + id + " and texture path " + texturePath + " but we were told it is not transparent, set it to transparent anyway");
                                }
                            }
                            else
                            {
                                if (id < 0)
                                {
                                    _id = uid;
                                    Debug.LogWarning("warning: detected not transparent texture for block " + name + " with updated id " + id + " and texture path " + texturePath + " but we were told it is transparent, set it to not transparent anyway");
                                }
                            }



                            if (argbTexture.width != 16 * 2 || argbTexture.height != 16 * 3)
                            {
                                Debug.Log("rescaling texture of block " + name + " with id " + id + " and texture path " + texturePath);
                                TextureScale.Bilinear(argbTexture, 16 * 2, 16 * 3);
                            }
                            argbTexture.Apply();
                            Color[] pixels = argbTexture.GetPixels();
                            // offset x by frame count
                            allBlocksTexture.SetPixels(i * 16 * 2, (uid - 1) * 16 * 3, 16 * 2, 16 * 3, pixels);
                            allBlocksTexture.Apply();
                        }
                    }
                    Debug.LogWarning("warning: texture " + texturePath + " for block " + name + " with id " + id + " does not exist");
                }
            }
        }
Ejemplo n.º 7
0
 public bool Equals(BlockValue other)
 {
     return(this.id == other.id);
 }
Ejemplo n.º 8
0
 public abstract void OnSearchForFood(out bool lookForBlock, out BlockValue lookForBlockValue);
Ejemplo n.º 9
0
        public void UpdatePathing()
        {
            ////// new temp stuff
            MovingEntity body = GetComponent <MovingEntity>();

            //pathingTarget = LVector3.FromUnityVector3(FindObjectOfType<BlocksPlayer>().transform.position);

            /*
             * // find position on ground below player and path to that instead
             * int goDownAmount = 10; // don't get into infinite loop, give up eventually
             * while (pathingTarget.BlockV == BlockValue.Air && goDownAmount > 0)
             * {
             *  pathingTarget = pathingTarget - new LVector3(0, 1, 0);
             *  goDownAmount--;
             * }
             * pathingTarget += new LVector3(0, 2, 0);
             */
            //////

            pathingTarget = LVector3.Invalid;

            if (thingDoing != null)
            {
                if (thingDoing.target != null)
                {
                    if (thingDoing.target.entity != null)
                    {
                        pathingTarget        = LVector3.FromUnityVector3(thingDoing.target.entity.transform.position);
                        iNeedToPathfindAgain = true;
                    }
                    else if (thingDoing.target.block != LVector3.Invalid)
                    {
                        pathingTarget = thingDoing.target.block;
                        //Debug.Log("going to pathing target with block in thing doing of " + pathingTarget);
                    }
                }
            }

            if (curPath == null)
            {
                iNeedToPathfindAgain = true;
            }

            if (pathingTarget == LVector3.Invalid)
            {
                body.desiredMove = Vector3.zero;
            }
            if (PhysicsUtils.millis() - lastPathfind > 1000.0 / pathfindsPerSecond && frameUpdatedLast != Time.frameCount && iNeedToPathfindAgain) // offset so everyone isn't aligned on the same frame
            {
                LVector3 myPos = LVector3.FromUnityVector3(transform.position);
                LVector3 foundThing;

                /*
                 * if (Search(out foundThing))
                 * {
                 *  // found it, is it closer?
                 *  if (pathingTarget == LVector3.Invalid || LVector3.CityBlockDistance(foundThing, myPos) < LVector3.CityBlockDistance(pathingTarget, myPos))
                 *  {
                 *      // if so, go to it instead
                 *      ThingDoing newThingDoing = new ThingDoing(thingDoing.typeOfThing, new ThingDoingTarget(foundThing));
                 *      // copy over valid blocks for future reference
                 *      if (thingDoing != null && thingDoing.target != null)
                 *      {
                 *          newThingDoing.target.validBlocks = thingDoing.target.validBlocks;
                 *      }
                 *      thingDoing = newThingDoing;
                 *      pathingTarget = foundThing;
                 *  }
                 *  //Debug.Log("found thing when looking");
                 * }
                 * else
                 * {
                 *  // did not find
                 *  //Debug.Log("did not find thing when looking");
                 *  //Debug.Log("did not find thing in " + steps + " steps");
                 * }
                 */
                frameUpdatedLast = Time.frameCount;
                //Debug.Log("updating pathing");
                RaycastResults blockStandingOn;

                bool lookingForBlocks = false;
                if (thingDoing != null && thingDoing.target != null && thingDoing.target.entity == null && thingDoing.target.block == LVector3.Invalid && thingDoing.target.validBlocks != null)
                {
                    lookingForBlocks = true;
                }

                if (pathingTarget != LVector3.Invalid || lookingForBlocks)
                {
                    if (PhysicsUtils.RayCastAlsoHitWater(body.transform.position, -Vector3.up, 20.0f, out blockStandingOn))
                    {
                        // if we are using shift and standing over an empty block, but our feet are on a neighboring block, use that neighboring block for pathfinding instead
                        if (blockStandingOn != LVector3.Invalid)
                        {
                            myPos = blockStandingOn.hitBlock + new LVector3(0, blocksHeight, 0);
                        }
                        //LVector3 playerPos = LVector3.FromUnityVector3(pathingTarget.transform.position);
                        bool iShouldJump;
                        if (thingDoing.typeOfThing == TypeOfThingDoing.RunningAway)
                        {
                            PhysicsUtils.PathfindAway(blocksHeight, ref curPath, out iShouldJump, myPos, pathingTarget, 100);
                        }
                        else
                        {
                            //// new stuff
                            bool             pathingSuccess = false;
                            PathingRegionPos resPath        = null;
                            if (lookingForBlocks)
                            {
                                resPath = PathingChunk.PathindToResource(World.mainWorld, myPos, GetComponent <MovingEntity>().reachRange, thingDoing.target.validBlocks, new MobilityCriteria(1, 1, blocksHeight, 1), out pathingSuccess, out blockWeCanSeeOnceWeGetThere, verbose: world.blocksWorld.verbosePathing);
                                if (resPath != null)
                                {
                                    pathingTarget = new LVector3(resPath.wx, resPath.wy, resPath.wz);
                                    thingDoing    = new ThingDoing(thingDoing.typeOfThing, new ThingDoingTarget(pathingTarget, thingDoing.target.validBlocks));
                                }
                            }
                            else
                            {
                                resPath = BlocksPathing.Pathfind(World.mainWorld, myPos, pathingTarget, 1, 1, blocksHeight, 1, out pathingSuccess, verbose: false);
                            }
                            iShouldJump = false;
                            if (resPath != null)
                            {
                                curPath = (new PathingResult(resPath)).GetPathNode();

                                iNeedToPathfindAgain = false;

                                //Debug.Log("got path with next pos " + curPath.pos + " also, my pos is " + myPos + " and pathing target is " + pathingTarget);
                                if (curPath.nextNode != null && curPath.nextNode.pos.y > curPath.pos.y)
                                {
                                    iShouldJump = true;
                                }

                                if (curPath.nextNode != null)
                                {
                                    //curPath = curPath.nextNode;
                                }
                            }
                            else
                            {
                                curPath = null;
                                iNeedToPathfindAgain = true;
                            }


                            /////
                            ///

                            // old thing:
                            //PhysicsUtils.Pathfind(blocksHeight, ref curPath, out iShouldJump, myPos, pathingTarget+new LVector3(0,1,0), 100);
                        }
                        if (curPath != null)
                        {
                            if (curPath.nextNode == null)
                            {
                                //Debug.Log("curPath = " + curPath.pos + " myPos = " + myPos + " next null");
                            }
                            else
                            {
                                //Debug.Log("curPath = " + curPath.pos + " myPos = " + myPos + " nextPath = " + curPath.nextNode.pos);
                            }
                        }
                        if (iShouldJump)
                        {
                            body.jumping = true;
                        }
                    }
                    else
                    {
                        //Debug.Log("falling far, cannot pathfind");
                    }
                }
                lastPathfind = PhysicsUtils.millis();
            }


            if (pathingTarget == LVector3.Invalid)
            {
                //Debug.Log("has invalid pathing target?");
                iNeedToPathfindAgain = true;
            }
            body.desiredMove = Vector3.zero;
            Vector3 targetPos = transform.position;

            if (curPath != null && pathingTarget != LVector3.Invalid)
            {
                /* // dani commented this out recently
                 * LVector3 myPos = LVector3.FromUnityVector3(transform.position);
                 * RaycastResults blockStandingOn;
                 * if (PhysicsUtils.RayCastAlsoHitWater(body.transform.position, -Vector3.up, 20.0f, out blockStandingOn))
                 * {
                 *  // if we are using shift and standing over an empty block, but our feet are on a neighboring block, use that neighboring block for pathfinding instead
                 * myPos = blockStandingOn.hitBlock + new LVector3(0, blocksHeight, 0);
                 * }
                 * LVector3 myPosBeforeJump = myPos - new LVector3(0, 1, 0);
                 * LVector3 myPosBeforeFall = myPos + new LVector3(0, 1, 0);
                 */



                //if (curPath.prevNode != null && (myPos == curPath.prevNode.pos || myPosBeforeJump == curPath.prevNode.pos))
                //{

                //}
                //else

                /*
                 * PathNode closest = curPath;
                 * float closestDist = LVector3.EuclideanDistance(closest.pos, myPos);
                 * PathNode curTmp = closest;
                 * while(curTmp.prevNode != null)
                 * {
                 *  curTmp = curTmp.prevNode;
                 *  float tmpDist = LVector3.EuclideanDistance(curTmp.pos, myPos);
                 *  if (tmpDist < closestDist)
                 *  {
                 *      closest = curTmp;
                 *      closestDist = tmpDist;
                 *  }
                 * }
                 * curTmp = curPath;
                 * while (curTmp.nextNode != null)
                 * {
                 *  curTmp = curTmp.nextNode;
                 *  float tmpDist = LVector3.EuclideanDistance(curTmp.pos, myPos);
                 *  if (tmpDist < closestDist)
                 *  {
                 *      closest = curTmp;
                 *      closestDist = tmpDist;
                 *  }
                 * }
                 *
                 * if (closest.pos == myPos)
                 * {
                 *  if (closest.nextNode == null)
                 *  {
                 *      Debug.Log("reached end of path");
                 *  }
                 *  else
                 *  {
                 *      curPath = closest.nextNode;
                 *  }
                 * }
                 * else
                 * {
                 *  curPath = closest;
                 * }*/


                /* // dani commented this out recently
                 * if (curPath.nextNode != null && (myPos == curPath.nextNode.pos || myPosBeforeJump == curPath.nextNode.pos || myPosBeforeFall == curPath.nextNode.pos))
                 * {
                 *  curPath = curPath.nextNode;
                 * }
                 * else if (myPos == curPath.pos || myPosBeforeJump == curPath.pos || myPosBeforeFall == curPath.pos)
                 * {
                 *  if (curPath.nextNode != null)
                 *  {
                 *      curPath = curPath.nextNode;
                 *  }
                 * }
                 *
                 *
                 * LVector3 targetBlock = curPath.pos;
                 * if (targetBlock.y == LVector3.FromUnityVector3(transform.position).y)
                 * {
                 *  //body.usingShift = true;
                 *  body.usingShift = false;
                 * }
                 * else
                 * {
                 *  body.usingShift = false;
                 * }
                 * if (targetBlock.y > myPos.y)
                 * {
                 *  body.jumping = true;
                 * }
                 * else
                 * {
                 *  body.jumping = false;
                 * }
                 * targetPos = targetBlock.BlockCentertoUnityVector3();
                 * body.SetAbsoluteDesiredMove((targetPos - transform.position).normalized);
                 */


                Vector3 dirToMove;
                bool    pushedOffPath;
                curPath = curPath.GetCurNode(transform.position, out body.jumping, out dirToMove, out pushedOffPath);
                body.SetAbsoluteDesiredMove(dirToMove);

                if (pushedOffPath)
                {
                    //Debug.Log("pushed off path");
                    //iNeedToPathfindAgain = true;
                }

                if (curPath.nextNode != null)
                {
                    //Debug.Log("got cur path " + curPath.pos + " with jumping " + body.jumping + " and dir to move " + dirToMove + " and next " + curPath.nextNode.pos + " and pushed off path " + pushedOffPath);
                }
                else
                {
                    //Debug.Log("got cur path " + curPath.pos + " with jumping " + body.jumping + " and dir to move " + dirToMove + " and no next and pushed off path " + pushedOffPath);
                }


                BlockValue blockWeAreGoingTo = blockWeCanSeeOnceWeGetThere.BlockV;

                if (!DesiredBlock(blockWeAreGoingTo) && thingDoing != null && thingDoing.target != null && thingDoing.target.entity == null)
                {
                    Debug.Log("rip someone took my block , my block is now " + World.BlockToString(blockWeAreGoingTo));
                    curPath       = null;
                    pathingTarget = LVector3.Invalid;
                }
                else
                {
                    float myDist = LVector3.CityBlockDistance(LVector3.FromUnityVector3(transform.position), pathingTarget);
                    // found it, eat it
                    if (myDist <= 2)
                    {
                        //Debug.Log("got to desired block");
                        if (thingDoing != null && thingDoing.typeOfThing == TypeOfThingDoing.GettingFood)
                        {
                            OnReachFoodBlock(blockWeCanSeeOnceWeGetThere);
                        }
                        else if (thingDoing != null && thingDoing.typeOfThing == TypeOfThingDoing.Gathering)
                        {
                            OnReachBlockToGather(blockWeCanSeeOnceWeGetThere);
                        }

                        /*
                         * DidEatObject(pathingTarget, 1.0f);
                         * world[pathingTarget] = (int)Example.Flower;
                         */
                        //this.thingDoing = new ThingDoing(TypeOfThingDoing.GettingFood, null);
                        if (thingDoing != null && thingDoing.target != null)
                        {
                            this.thingDoing = new ThingDoing(thingDoing.typeOfThing, new ThingDoingTarget(thingDoing.target.validBlocks));
                        }
                        else if (thingDoing != null)
                        {
                            this.thingDoing = new ThingDoing(thingDoing.typeOfThing, null);
                        }
                        curPath              = null;
                        pathingTarget        = LVector3.Invalid;
                        body.jumping         = false;
                        iNeedToPathfindAgain = true;
                    }
                    // still pathing to it
                    else
                    {
                    }
                }
            }
        }
Ejemplo n.º 10
0
        public bool InventoryMatchesRecipe(Inventory inventory, int nRows, int maxBlocks, bool useResources)
        {
            if (maxBlocks == -1)
            {
                maxBlocks = inventory.capacity;
            }
            if (maxBlocks > inventory.capacity)
            {
                maxBlocks = inventory.capacity;
            }
            if (maxBlocks % nRows != 0)
            {
                Debug.LogError("maxBlocks size of " + maxBlocks + " is not a multiple of given nRows=" + nRows);
                return(false);
            }


            if (unordered)
            {
                int   numMatchesNeeded = unorderedRecipe.Length;
                int   numMatches       = 0;
                int[] matches          = new int[unorderedRecipe.Length];
                for (int i = 0; i < matches.Length; i++)
                {
                    matches[i] = -1;
                }
                for (int i = 0; i < maxBlocks; i++)
                {
                    if (!IsEmptyBlockStack(inventory.blocks[i]))
                    {
                        bool foundMatch = false;
                        for (int j = 0; j < unorderedRecipe.Length; j++)
                        {
                            if (matches[j] == -1 && unorderedRecipe[j] == inventory.blocks[i].Block)
                            {
                                matches[j]  = i;
                                foundMatch  = true;
                                numMatches += 1;
                                break;
                            }
                        }
                        if (!foundMatch)
                        {
                            return(false);
                        }
                    }
                }

                if (numMatches == numMatchesNeeded)
                {
                    if (useResources)
                    {
                        for (int i = 0; i < matches.Length; i++)
                        {
                            inventory.blocks[matches[i]].count -= 1;
                            if (inventory.blocks[matches[i]].count <= 0)
                            {
                                inventory.blocks[matches[i]] = new BlockStack(BlockValue.Air, 0);
                            }
                        }
                    }
                    return(true);
                }



                return(false);
            }
            else
            {
                int nColumns         = maxBlocks / nRows;
                int numMatchesNeeded = recipe.GetLength(0) * recipe.GetLength(1);
                for (int topLeftX = 0; topLeftX < nColumns; topLeftX++)
                {
                    for (int topLeftY = 0; topLeftY < nRows; topLeftY++)
                    {
                        int numMatches = 0;
                        for (int i = 0; i < recipe.GetLength(1); i++)
                        {
                            for (int j = 0; j < recipe.GetLength(0); j++)
                            {
                                int x = topLeftX + i;
                                int y = topLeftY + j;
                                if (x < nColumns && y < nRows)
                                {
                                    int        index     = x + y * nColumns;
                                    BlockStack cur       = inventory.blocks[index];
                                    BlockValue recipeCur = recipe[recipe.GetLength(0) - j - 1, i];
                                    if (IsEmptyBlockStack(cur))
                                    {
                                        if (recipeCur == BlockValue.Air)
                                        {
                                            //Debug.Log(x + " " + y + "inventory empty here and recipe is too, recipeCur=" + World.BlockToString((int)recipeCur));
                                            numMatches += 1;
                                        }
                                        else
                                        {
                                            //Debug.Log(x + " " + y + "inventory empty here and recipe is not, recipeCur=" + World.BlockToString((int)recipeCur));
                                        }
                                    }
                                    else if (!IsEmptyBlockStack(cur))
                                    {
                                        if (cur.block == recipeCur)
                                        {
                                            //Debug.Log(x + " " + y + "same: inventory is " + World.BlockToString(cur.block) + " and recipe is " + World.BlockToString((int)recipeCur));
                                            numMatches += 1;
                                        }
                                        else
                                        {
                                            //Debug.Log(x + " " + y + "different: inventory is " + World.BlockToString(cur.block) + " and recipe is " + World.BlockToString((int)recipeCur));
                                        }
                                    }
                                }
                            }
                        }
                        //Debug.Log("got num matches " + numMatches + " with top left x=" + topLeftX + " and topLeftY=" + topLeftY);
                        if (numMatches == numMatchesNeeded)
                        {
                            bool hasExtraStuff = false;
                            for (int x = 0; x < topLeftX; x++)
                            {
                                for (int y = 0; y < nRows; y++)
                                {
                                    int index = x + y * nColumns;
                                    if (!IsEmptyBlockStack(inventory.blocks[index]))
                                    {
                                        hasExtraStuff = true;
                                        break;
                                    }
                                }
                                if (hasExtraStuff)
                                {
                                    break;
                                }
                            }

                            for (int x = topLeftX; x < nColumns; x++)
                            {
                                for (int y = 0; y < topLeftY; y++)
                                {
                                    int index = x + y * nColumns;
                                    if (!IsEmptyBlockStack(inventory.blocks[index]))
                                    {
                                        hasExtraStuff = true;
                                        break;
                                    }
                                }
                                if (hasExtraStuff)
                                {
                                    break;
                                }
                            }
                            if (hasExtraStuff)
                            {
                                //Debug.Log("matches recipe but has extra stuff");
                                return(false);
                            }
                            else
                            {
                                //Debug.Log("matches recipe completely");


                                if (useResources)
                                {
                                    for (int i = 0; i < recipe.GetLength(1); i++)
                                    {
                                        for (int j = 0; j < recipe.GetLength(0); j++)
                                        {
                                            int x     = topLeftX + i;
                                            int y     = topLeftY + j;
                                            int index = x + y * nColumns;
                                            if (!IsEmptyBlockStack(inventory.blocks[index]))
                                            {
                                                inventory.blocks[index].count -= 1;
                                                if (inventory.blocks[index].count <= 0)
                                                {
                                                    inventory.blocks[index] = new BlockStack(BlockValue.Air, 0);
                                                }
                                            }
                                        }
                                    }
                                }
                                return(true);
                            }
                        }
                        else if (numMatches > numMatchesNeeded)
                        {
                            Debug.LogWarning("numMatches = " + numMatches + " but maximum num matches is " + numMatchesNeeded + " this is invalid how u do this");
                        }
                    }
                }
                return(false);
            }
        }