What's the best way to save and load a world with easy save 3?

Im working on a game where I have the terrain procedurally generated, and I downloaded easy save 3 off of the asset store but I don’t know the best way to save my trees, animals, and enemies. The game is 2d and I use perlin noise to generate the tilemap for the terrain, and use the noise to say if a random number is a certain amount and the tile is grass, then spawn a tree. This breaks when I quit the game and load the world up again, because all the trees are randomly generated again. So the terrain is the same, but everything else isn’t.
I’ve tried to store all the existing trees into a game object list, but when I loaded the world everything was duplicated and it took forever to load when I had a lot of trees in the world. I also thought of the idea of using a different noise pattern on top of the terrain to spawn the trees but then the problem would be if the tree is chopped down by the player, than it would be fully grown again. Hopefully that all made sense and im hoping there’s an easy solution to this. This is the code for generating the world:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;

public class MapGenerator : MonoBehaviour
{
	public Tilemap ground;
	public Tilemap ground2;
	public Tilemap groundTop;
	public Tilemap waterTiles;
	public RuleTile baseGrass;
	public RuleTile water;
	public Tile[] flower;
	public Tile[] sand;
	public Tile grass1;
	public Tile grass2;
	public Tile grass3;

	public int width;
	public int height;

	public GameObject player;
	public GameObject saveMan;

	public List<GameObject> spawners;
	public GameObject spawner;
	public List<GameObject> treeSpawners;
	public GameObject treeSpawner;
	public List<GameObject> enemySpawners;
	public GameObject enemySpawner;
	public List<GameObject> animalSpawners;
	public GameObject animalSpawner;

	public float scale;
	public float offsetX;
	public float offsetY;

	public GameObject bossShrine;
	public bool shrineSpawned;
	public int randX;
	public int randY;

	private int tileNumb;

	public int distanceX;
	public int distanceY;

	public int islandSize;
	public int villageSize;

	public int villageOffsetX;
	public int villageOffsetY;

	public int villageRadius;

	public GameObject village;

	public int chunkSize;
	public int offLoad;

	public GameObject invent;
	private InventoryNum inventory;

	private bool cooldown;
	private int randTile;
	public int sam;

	public bool loadingWorld;

	public Texture2D treeNoise;

	// Start is called before the first frame update
	void Start()
    {
		GameObject playerCopy = Instantiate(player, transform.position, transform.rotation, transform.parent);
		player = playerCopy;

		villageOffsetX = Random.Range(-villageRadius, villageRadius);
		villageOffsetY = Random.Range(-villageRadius, villageRadius);

		Renderer renderer = GetComponent<Renderer>();

		//renderer.material.mainTexture = GenerateTexture();

		int[,] map = new int[width, height];

		invent = GameObject.FindWithTag("inventoryGrid");

		SetWorld();
		

		SpawnPlayer();
	}

	public void SetWorld()
    {

		if (loadingWorld)
        {
			if (ES3.KeyExists("offsetX"))
			{
				offsetX = ES3.Load<float>("offsetX");
			}
			if (ES3.KeyExists("offsetY"))
			{
				offsetY = ES3.Load<float>("offsetY");
			}
			if (ES3.KeyExists("playerPos"))
			{
				player.transform.position = ES3.Load<Vector3>("playerPos");
			}
			if (ES3.KeyExists("playerWeapon"))
			{
				player.GetComponent<PlayerController>().LoadWeapon();
			}
			if (ES3.KeyExists("playerHealth"))
			{
				player.GetComponent<PlayerController>().health = ES3.Load<float>("playerHealth");
				player.GetComponent<PlayerController>().UpdateHealthbar();
			}

			for (int i = 0; i < spawners.Count; i++)
			{
				Destroy(spawners*);*
  •  	}*
    
  •  	for (int i = 0; i < treeSpawners.Count; i++)*
    
  •  	{*
    

_ Destroy(treeSpawners*);_
_
}_
_
for (int i = 0; i < enemySpawners.Count; i++)_
_
{_
_ Destroy(enemySpawners);
}
for (int i = 0; i < animalSpawners.Count; i++)
{
Destroy(animalSpawners);
}*_

* ground.ClearAllTiles();*
* ground2.ClearAllTiles();*
* groundTop.ClearAllTiles();*
* waterTiles.ClearAllTiles();*

* spawners = new List();*
* treeSpawners = new List();*
* enemySpawners = new List();*
* animalSpawners = new List();*

* }*
else
{
* offsetX = Random.Range(0, 99999f);*
* offsetY = Random.Range(0, 99999f);*
* }*

* }*

* public void NewWorld()*
{
* ground.ClearAllTiles();*
* ground2.ClearAllTiles();*
* groundTop.ClearAllTiles();*
* waterTiles.ClearAllTiles();*

* for (int i = 0; i < spawners.Count; i++)*
* {*
_ Destroy(spawners*);
}
for (int i = 0; i < treeSpawners.Count; i++)
{
Destroy(treeSpawners);
}
for (int i = 0; i < enemySpawners.Count; i++)
{
Destroy(enemySpawners);
}
for (int i = 0; i < animalSpawners.Count; i++)
{
Destroy(animalSpawners);
}*_

* spawners = new List();*
* treeSpawners = new List();*
* enemySpawners = new List();*
* animalSpawners = new List();*

* offsetX = Random.Range(0, 99999f);*
* offsetY = Random.Range(0, 99999f);*

* inventory = invent.GetComponent();*
* for (int i = 0; i < inventory.slots.Length; i++)*
* {*
_ inventory.slots*.GetComponent().SetDefaults();
}*_

* SpawnPlayer();*

* loadingWorld = false;*
* }*

// Update is called once per frame
void Update()
{

* if (player.GetComponent().health <= 0)*
* {*
* player.GetComponent().color = new Color(255, 255, 255);*
* inventory = invent.GetComponent();*

* for (int i = 0; i < inventory.slots.Length; i++)*
{
if (inventory.slots*.GetComponent().id > 0)*
{
_ for (int x = 0; x < inventory.slots*.GetComponent().value; x++)
{
Instantiate(inventory.items[inventory.slots.GetComponent().id - 1], player.transform.position, player.transform.rotation);
}*_

_ inventory.slots*.GetComponent().id = 0;
inventory.slots.GetComponent().value = 0;
inventory.slots.GetComponent().full = false;
Destroy(inventory.slots.GetComponent().child);
Destroy(player.GetComponent().currentWeapon);
}
}*_

if (!cooldown)
{
* StartCoroutine(SpawnCooldown());*
* cooldown = true;*
* }*
* }*

_ /
for (int x = -offLoad; x < offLoad; x++)
{
for (int y = -offLoad; y < offLoad; y++)
{
if (x > chunkSize || x < -chunkSize)
{
if (y > chunkSize || y < -chunkSize)
{
Vector3 playerPos = new Vector3((int)player.transform.position.x + x, (int)player.transform.position.y + y, 0);*_

* Vector3Int tilePos = groundTop.WorldToCell(playerPos);*

* if (ground.GetTile(tilePos) != null)*
* {*
* ground.SetTile(tilePos, null);*
* }*
* if (ground2.GetTile(tilePos) != null)*
* {*
* ground2.SetTile(tilePos, null);*
* }*
* if (groundTop.GetTile(tilePos) != null)*
* {*
* groundTop.SetTile(tilePos, null);*
* }*
* if (waterTiles.GetTile(tilePos) != null)*
* {*
* waterTiles.SetTile(tilePos, null);*
* }*
* }*
}
* }*
* }*
_ */_

for (int x = -chunkSize; x < chunkSize; x++)
{
for (int y = -chunkSize; y < chunkSize; y++)
{

* Vector3 playerPos = new Vector3((int)player.transform.position.x + x, (int)player.transform.position.y + y, 0);*

* Vector3Int tilePos = groundTop.WorldToCell(playerPos);*

* if (groundTop.GetTile(tilePos) == null)*
* {*

* CalculateColor((int)player.transform.position.x + x, (int)player.transform.position.y + y);*
* }*

* if (ground2.GetTile(tilePos) == null)*
* {*
* int randNumb = Random.Range(0, 100);*
* int numb = 0;*

* if (randNumb < 90)*
* {*
* numb = 0;*
* }*
* else*
* {*
* if (randNumb > 92 && randNumb < 95)*
* {*
* numb = 0;*
* }*
* else*
* {*
* if (randNumb > 95 && randNumb < 98)*
* {*
* numb = 1;*
* }*
* else*
* {*
* if (randNumb > 98)*
* {*
* numb = 2;*
* }*
* else*
* {*
* numb = 0;*
* }*
* }*
* }*
* }*
* ground2.SetTile(tilePos, sand[numb]);*
* }*

* }*
}

* }*

public void SpawnPlayer()
* {*
* Vector3 playerPos2 = new Vector3((int)player.transform.position.x, (int)player.transform.position.y, 0);*

* Vector3Int tilePos = groundTop.WorldToCell(playerPos2);*

* if (waterTiles.GetTile(tilePos) != null)*
{
* player.transform.position = new Vector3(player.transform.position.x + 1, player.transform.position.y, 0);*
* SpawnPlayer();*
}
else
{
* if (player.GetComponent().health <= 0)*
* {*
* player.GetComponent().health = player.GetComponent().maxHealth;*
* player.GetComponent().SetSize(player.GetComponent().health / player.GetComponent().maxHealth);*
* }*
* player.SetActive(true);*
if (!loadingWorld)
{
* player.transform.position = new Vector2(0, 0);*
* player.GetComponent().health = player.GetComponent().maxHealth;*
* player.GetComponent().SetSize(player.GetComponent().health / player.GetComponent().maxHealth);*
* }*

* cooldown = false;*
* }*
* }*

* IEnumerator SpawnCooldown()*
* {*
* player.SetActive(false);*
* yield return new WaitForSeconds(5.1f);*
* SpawnPlayer();*
* }*

* Texture2D GenerateTexture()*
* {*
* Texture2D texture = new Texture2D(width, height);*

* randX = Random.Range(0, width);*
* randY = Random.Range(0, height);*

* for (int x = -(width / 2); x < width / 2; x++)*
* {*
* for (int y = -(height / 2); y < height / 2; y++)*
* {*

* //Color color = CalculateColor(x, y);*
* //texture.SetPixel(x, y, color);*

* }*
* }*

* texture.Apply();*
* return texture;*
* }*

Color CalculateColor(int x, int y)
* {*
_ float xCoord = (float)x / width * scale + offsetX;
float yCoord = (float)y / height * scale + offsetY;_

* float sample = Mathf.PerlinNoise(xCoord, yCoord);*
* sample = sample;*

* if (Mathf.Pow(x - villageOffsetX, 2) + Mathf.Pow(y - villageOffsetY, 2) < Mathf.Pow(villageSize, 2))*
* {*

if (x == villageOffsetX && y == villageOffsetY)
{

* }*
* }*

* if (sample >= 0.4f)*
* {*

* ground.SetTile(new Vector3Int((int)x, (int)y, 0), baseGrass);*

* if (sample > 0.5f)*
* {*

* randTile = Random.Range(0, 100);*
* if (randTile < 90)*
* {*
* groundTop.SetTile(new Vector3Int((int)x, (int)y, 0), grass3);*
* }*
* else*
* {*
* if (randTile > 92 && randTile < 95)*
* {*
* groundTop.SetTile(new Vector3Int((int)x, (int)y, 0), grass1);*
* }*
* else*
* {*
* if (randTile > 95 && randTile < 98)*
* {*
* groundTop.SetTile(new Vector3Int((int)x, (int)y, 0), flower[Random.Range(0, flower.Length)]);*
* }*
* else*
* {*
* if (randTile > 98)*
* {*
* groundTop.SetTile(new Vector3Int((int)x, (int)y, 0), grass2);*
* }*
* else*
* {*
* ground.SetTile(new Vector3Int((int)x, (int)y, 0), baseGrass);*
* }*
* }*
* }*

* }*

* int randSpawn = Random.Range(0, 1000);*

* if (randSpawn > 995)*
* {*
* spawners.Add(Instantiate(spawner, new Vector3Int((int)x, (int)y, 0), transform.rotation, transform.parent));*
* }*

* if (randSpawn < 11)*
* {*
* treeSpawners.Add(Instantiate(treeSpawner, new Vector3Int((int)x, (int)y, 0), transform.rotation, transform.parent));*
* }*

* if (randSpawn > 10 && randSpawn < 12)*
* {*
* enemySpawners.Add(Instantiate(enemySpawner, new Vector3Int((int)x, (int)y, 0), transform.rotation, transform.parent));*
* }*

* if (randSpawn > 12 && randSpawn < 17)*
* {*
* animalSpawners.Add(Instantiate(animalSpawner, new Vector3Int((int)x, (int)y, 0), transform.rotation, transform.parent));*
* }*

* }*

* }*
* else*
* {*
if(sample < 0.4f && sample > 0.35f)
* {*

* }*
* else*
* {*
* waterTiles.SetTile(new Vector3Int((int)x, (int)y, 0), water);*
* }*
* }*

* return new Color(sample, sample, sample);*
* }*
}

@jobothehobo Did you solve it? I’m having a similar issue. My game is 3d, but for a 2d context as yours something like a dictionary with the tile-type could work, having different letters/strings for each state of the tree. I hope you’ve solved it! Good luck