public void SyncChunksData()
    {
        bool can_read = Monitor.TryEnter(VFDataRTGen.s_dicTreeInfoList);

        if (can_read)
        {
            // Add trees
            _lstChnkIdxActive.Clear();
            foreach (KeyValuePair <IntVector2, List <TreeInfo> > kvp in VFDataRTGen.s_dicTreeInfoList)
            {
                int cnkidx = RSubTerrUtils.TilePosToIndex(kvp.Key);
                _lstChnkIdxActive.Add(cnkidx);
                if (m_Chunks.ContainsKey(cnkidx))
                {
                    continue;
                }
                int        cnkx    = RSubTerrUtils.IndexToChunkX(cnkidx);
                int        cnkz    = RSubTerrUtils.IndexToChunkZ(cnkidx);
                GameObject chunkgo = new GameObject("Tile [" + cnkx + "," + cnkz + "]");
                chunkgo.transform.parent   = s_Instance.ChunkGroup.transform;
                chunkgo.transform.position = new Vector3((cnkx + 0.5f) * RSubTerrConstant.ChunkSizeF, 0, (cnkz + 0.5f) * RSubTerrConstant.ChunkSizeF);
                RSubTerrainChunk chunk = chunkgo.AddComponent <RSubTerrainChunk>();
                chunk.m_Index = cnkidx;
                s_Instance.m_Chunks.Add(cnkidx, chunk);
                foreach (TreeInfo ti in kvp.Value)
                {
                    bool was_deleted = false;
                    // Delete cutted trees
                    if (RSubTerrSL.m_mapDelPos != null)
                    {
                        for (int x = cnkx - 1; x <= cnkx + 1; ++x)
                        {
                            for (int z = cnkz - 1; z <= cnkz + 1; ++z)
                            {
                                int idx = RSubTerrUtils.ChunkPosToIndex(x, z);
                                if (RSubTerrSL.m_mapDelPos.ContainsKey(idx))
                                {
                                    foreach (Vector3 pos in RSubTerrSL.m_mapDelPos[idx])
                                    {
                                        float diff = Mathf.Abs(pos.x - ti.m_pos.x) + Mathf.Abs(pos.y - ti.m_pos.y) + Mathf.Abs(pos.z - ti.m_pos.z);
                                        if (diff < 0.05f)
                                        {
                                            was_deleted = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (was_deleted)
                    {
                        continue;
                    }

                    chunk.AddTree(ti);
                    int idx32 = RSubTerrUtils.Tree32PosTo32Index(Mathf.FloorToInt(ti.m_pos.x / 32), Mathf.FloorToInt(ti.m_pos.z / 32));
                    if (!m_map32Trees.ContainsKey(idx32))
                    {
                        m_map32Trees.Add(idx32, new List <TreeInfo>());
                    }
                    if (HasCollider(ti.m_protoTypeIdx) || HasLight(ti.m_protoTypeIdx))
                    {
                        m_map32Trees[idx32].Add(ti);
                    }
                }
                if (IsChunkRendering(cnkidx))
                {
                    m_IsDirty = true;
                }
            }

            _lstChnkIdxToDel.Clear();
            foreach (KeyValuePair <int, RSubTerrainChunk> kvp in m_Chunks)
            {
                if (!_lstChnkIdxActive.Contains(kvp.Key))
                {
                    _lstChnkIdxToDel.Add(kvp.Key);
                }
            }
            foreach (int key in _lstChnkIdxToDel)
            {
                RemoveChunk(key);
                if (IsChunkRendering(key))
                {
                    m_IsDirty = true;
                }
            }
            Monitor.Exit(VFDataRTGen.s_dicTreeInfoList);
        }
    }
    public void RefreshTempGOsIn32Meter()
    {
        #region _TEMP_TREE_BY_32_METER
        int x32 = Mathf.FloorToInt(PlayerTransform.position.x / 32);
        int z32 = Mathf.FloorToInt(PlayerTransform.position.z / 32);
        for (int x = x32 - 2; x <= x32 + 2; ++x)
        {
            for (int z = z32 - 2; z <= z32 + 2; ++z)
            {
                int idx      = RSubTerrUtils.Tree32PosTo32Index(x, z);
                int oldCount = 0;
                int newCount = 0;
                if (m_map32Trees.ContainsKey(idx))
                {
                    newCount = m_map32Trees[idx].Count;
                }
                if (m_mapExistTempTrees.ContainsKey(idx))
                {
                    oldCount = m_mapExistTempTrees[idx].Count;
                }

                if (newCount != oldCount)
                {
                    // Delete old
                    if (oldCount != 0)
                    {
                        foreach (GameObject go in m_mapExistTempTrees[idx])
                        {
                            m_mapTempTreeInfos.Remove(go);
                            GameObject.Destroy(go);
                        }
                        m_mapExistTempTrees[idx].Clear();
                        m_mapExistTempTrees.Remove(idx);
                    }
                    // Add new
                    if (newCount != 0)
                    {
                        if (!m_mapExistTempTrees.ContainsKey(idx))
                        {
                            m_mapExistTempTrees.Add(idx, new List <GameObject> ());
                        }
                        List <GameObject> tmptreelist = m_mapExistTempTrees[idx];
                        foreach (TreeInfo _ti in m_map32Trees[idx])
                        {
                            if (GlobalPrototypeColliders[_ti.m_protoTypeIdx] == null)
                            {
                                continue;
                            }
                            GameObject temptree_go = GameObject.Instantiate(GlobalPrototypeColliders[_ti.m_protoTypeIdx],
                                                                            _ti.m_pos, Quaternion.identity) as GameObject;
                            temptree_go.transform.parent     = TempTreesGroup.transform;
                            temptree_go.transform.localScale = new Vector3(_ti.m_widthScale, _ti.m_heightScale, _ti.m_widthScale);
                            temptree_go.name  = temptree_go.transform.position.ToString() + " Type " + _ti.m_protoTypeIdx;
                            temptree_go.layer = NearTreeLayer;
                            temptree_go.SetActive(true);
                            tmptreelist.Add(temptree_go);
                            m_mapTempTreeInfos.Add(temptree_go, _ti);
                        }
                    }
                }
            }
        }
        List <int> keys_to_del = new List <int> ();
        foreach (KeyValuePair <int, List <GameObject> > kvp in m_mapExistTempTrees)
        {
            IntVec3 pos32 = RSubTerrUtils.Tree32KeyTo32Pos(kvp.Key);
            if (Mathf.Abs(pos32.x - x32) > 2 || Mathf.Abs(pos32.z - z32) > 2)
            {
                keys_to_del.Add(kvp.Key);
                foreach (GameObject go in kvp.Value)
                {
                    m_mapTempTreeInfos.Remove(go);
                    GameObject.Destroy(go);
                }
            }
        }
        foreach (int k in keys_to_del)
        {
            m_mapExistTempTrees.Remove(k);
        }
        #endregion
    }
    public static void DeleteTree(TreeInfo treeinfo)
    {
        if (s_Instance == null)
        {
            return;
        }
        if (treeinfo == null)
        {
            return;
        }

        // For two feet trees
        TreeInfo SecondFoot = null;

        // Delete it in Mgr's m_map32Trees
        int idx32 = RSubTerrUtils.Tree32PosTo32Index(Mathf.FloorToInt(treeinfo.m_pos.x / 32), Mathf.FloorToInt(treeinfo.m_pos.z / 32));

        if (s_Instance.m_map32Trees.ContainsKey(idx32))
        {
            s_Instance.m_map32Trees[idx32].Remove(treeinfo);
            if (s_Instance.m_map32Trees[idx32].Count == 0)
            {
                s_Instance.m_map32Trees.Remove(idx32);
            }
        }

        // Delete it in Mgr's m_mapExistTempTrees and m_mapTempTreeInfos
        if (s_Instance.m_mapExistTempTrees.ContainsKey(idx32))
        {
            GameObject gameobject_to_delete = null;
            foreach (GameObject go in s_Instance.m_mapExistTempTrees[idx32])
            {
                if (s_Instance.m_mapTempTreeInfos.ContainsKey(go))
                {
                    if (s_Instance.m_mapTempTreeInfos[go] == treeinfo)
                    {
                        // Found it!
                        gameobject_to_delete = go;
                        GameObject.Destroy(go);
                        s_Instance.m_mapTempTreeInfos.Remove(go);
                    }
                }
                else
                {
                    Debug.LogError("Can not find the GameObject key in m_mapTempTreeInfos when delete tree");
                }
            }
            if (gameobject_to_delete != null)
            {
                s_Instance.m_mapExistTempTrees[idx32].Remove(gameobject_to_delete);
            }
        }

        // Delete it in Node's m_mapTrees and m_listTrees
        int X         = Mathf.FloorToInt(treeinfo.m_pos.x / RSubTerrConstant.ChunkSizeF);
        int Z         = Mathf.FloorToInt(treeinfo.m_pos.z / RSubTerrConstant.ChunkSizeF);
        int del_count = 0;

        for (int x = X - 1; x <= X + 1; ++x)
        {
            for (int z = Z - 1; z <= Z + 1; ++z)
            {
                int idx     = RSubTerrUtils.ChunkPosToIndex(x, z);
                int treeidx = RSubTerrUtils.TreeWorldPosToChunkIndex(treeinfo.m_pos, idx);
                if (s_Instance.m_Chunks.ContainsKey(idx))
                {
                    RSubTerrainChunk chunk = s_Instance.m_Chunks[idx];
                    if (chunk.TreeList.Remove(treeinfo))
                    {
                        del_count++;
                    }
                    if (TreeInfo.RemoveTiFromDict(chunk.m_mapTrees, treeidx, treeinfo))
                    {
                        del_count++;
                    }
                }
            }
        }
        if (del_count != 2)
        {
            Debug.LogError("RSubTerrain Remove: count doesn't match");
        }

        // Delete it in layers
        foreach (RSubTerrCreator creator in s_Instance.LayerCreators)
        {
            creator.m_allTreesInLayer.Remove(treeinfo);
        }

        RSubTerrSL.AddDeletedTree(treeinfo);

        // Delete 2nd foot
        if (SecondFoot != null)
        {
            DeleteTree(SecondFoot);
        }
    }