Mod to add automated signs.

I see people keep asking how to do automatic signs here is a method modding sign artists code.
Not the best way to do it but it works. It scans each of the vectors youv provided as location from the list then remove any signs in that spot.
It then teleports the admin to that location, spawns a blank sign using your settings and writes the url to it before moving on.

Open the Signartist.cs plugin file.
search for "[Command("sil"), Permission("signartist.url")]"

Above that paste

    [ChatCommand("signreload")]
    private void signtest(BasePlayer player, string command, string[] args)
    {
	if(player.IsAdmin)
	{
	Dictionary<Vector3, string> SignLocations =  new Dictionary<Vector3, string>();
        //Add Your locations here.
	//Location,RotationX,Y,Z,URL,SignPrefab
	SignLocations.Add(new Vector3(843.987f, 23.204f, -93.021f), @"357.878, 270.000, 0,https://google.com/images/Logo.jpg,assets/prefabs/deployable/signs/sign.pictureframe.xxl.prefab"); //Sample Outpost Logo

	foreach(KeyValuePair<Vector3, string> oldsign in SignLocations)
	{//Remove any signs in same spot.
		var hits = Physics.SphereCastAll(oldsign.Key, 0.1f, Vector3.up);
        	var x = new List<BaseEntity>();
       		foreach (var hit in hits)
       		{ 
		var entity = hit.GetEntity()?.GetComponent<BaseEntity>();
        	if (entity && !x.Contains(entity)){if(entity.ToString().Contains("sign")){try{entity.Kill();}catch{}}};
       		}
	}
	int delay = 2; //Wait for gibs to clear for 2 sec.
	foreach(KeyValuePair<Vector3, string> entry in SignLocations)
	{timer.Once(delay, () =>{
	string[] ImageSettings = entry.Value.ToString().Split(',');
	Vector3 Rotation = new Vector3(float.Parse(ImageSettings[0]),float.Parse(ImageSettings[1]),float.Parse(ImageSettings[2]));
	ServerImages(entry.Key, Rotation, ImageSettings[4], ImageSettings[3], player);
	});
	delay+=2;
	}}}

	private void ServerImages(Vector3 position1, Vector3 rotation1, string SignPrefab, string ImageURL, BasePlayer player)
	{
	  player.RemoveFromTriggers();
          player.EnableServerFall(true);
          player.Teleport(position1);

          if (player.IsConnected && !Network.Net.sv.visibility.IsInside(player.net.group, position1))
          {
            player.SetPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot, true);
	    player.SendEntityUpdate();
              player.UpdateNetworkGroup();
              player.SendNetworkUpdateImmediate(false);
            player.EnableServerFall(false);
            player.ForceUpdateTriggers();
        }
      	BaseEntity sign1 = GameManager.server.CreateEntity(SignPrefab, position1, Quaternion.Euler(rotation1)) as BaseEntity;
      	sign1.Spawn();
      	sign1.transform.localPosition = position1;
      	sign1.SendNetworkUpdateImmediate(true);
      	List<Signage> list = new List<Signage>();
      	Vis.Entities<Signage>(position1, 0.1f, list);
      	foreach (Signage sign in list) {
      	imageDownloader.QueueDownload(ImageURL, player, new PaintableSignage(sign), false, false);
      	Interface.Oxide.CallHook("OnImagePost", player, "");
      	}
	}

Usage:
Edit it where it says Your locations here.
I have provided one sample from my server which is the vector address of a sign at outpost.
You can get the address using rust edit when you have a prefab there selected. Its a good idea to place a invisable collider on that spot to protect the sign from players interacting/destorying it.

Lay out is.
Vector3 location, String seperated by comma. First 3 values are rotation xyz, Then image url, then prefab of the sign you want to spawn in.

Once you have that done from game as a admin run chat command /signreload

Heres some slight improvements. Only Teleports you when you need to be so a large room of signs youll only teleport into that room once instead of to each sign.

 

[ChatCommand("signreload")]
    private void signtest(BasePlayer player, string command, string[] args)
    {
	if(player.IsAdmin)
	{
	Dictionary<Vector3, string> SignLocations =  new Dictionary<Vector3, string>();
	//Location,RotationXYZ,URL,SignPrefab
       SignLocations.Add(new Vector3(843.987f, 23.204f, -93.021f), @"357.878, 270.000, 0,https://google.com/images/Logo.jpg,assets/prefabs/deployable/signs/sign.pictureframe.xxl.prefab"); //Sample Outpost Logo


	foreach(KeyValuePair<Vector3, string> oldsign in SignLocations)
	{//Remove any signs in same spot.
		var hits = Physics.SphereCastAll(oldsign.Key, 3f, Vector3.up);
        	var x = new List<Signage>();
       		foreach (var hit in hits)
       		{ 
		var entity = hit.GetEntity()?.GetComponent<Signage>();
        	if (entity && !x.Contains(entity)){if(entity.ToString().Contains("sign")){try{entity.Kill();}catch{}}};
       		}
	}
	int delay = 2;
	foreach(KeyValuePair<Vector3, string> entry in SignLocations)
	{
	string[] ImageSettings = entry.Value.ToString().Split(',');
	Vector3 Rotation = new Vector3(float.Parse(ImageSettings[0]),float.Parse(ImageSettings[1]),float.Parse(ImageSettings[2]));
                timer.Once(delay, () =>
                {
		ServerImages(entry.Key, Rotation, ImageSettings[4], ImageSettings[3], player);
                });
	delay+=2;
	}
	}}

	private void ServerImages(Vector3 position1, Vector3 rotation1, string SignPrefab, string ImageURL, BasePlayer player)
	{
	if(Vector3.Distance(player.transform.position, position1) > 150)
	{
	  player.RemoveFromTriggers();
          player.EnableServerFall(true);
          player.Teleport(position1);
          if (player.IsConnected && !Network.Net.sv.visibility.IsInside(player.net.group, position1))
          {
            player.SetPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot, true);
	    player.SendEntityUpdate();
            player.UpdateNetworkGroup();
            player.SendNetworkUpdateImmediate(false);
            player.EnableServerFall(false);
            player.ForceUpdateTriggers();
        }}
      	Signage sign1 = GameManager.server.CreateEntity(SignPrefab, position1, Quaternion.Euler(rotation1)) as Signage;
      	sign1.Spawn();
      	imageDownloader.QueueDownload(ImageURL, player, new PaintableSignage(sign1), false, false);
      	Interface.Oxide.CallHook("OnImagePost", player, "");
	}

Wow, this is an awesome idea/ability! Can it still work?

I'm looking for a way to manually assign URLs to picture frames inside a Copy/Paste build (or a Fortify build), to avoid having to go around to each picture frame after copy/pasting a build and manually setting each one with its URL.