Do X when entering or leaving a biomeSolved
I want to make a code do something when you enter and leave a biome. I tried using 

void OnEntityEnter(TriggerBase trigger, BaseEntity entity)
{		 
if (entity is BasePlayer) {
var player = entity.ToPlayer();
var pos = entity.transform.position;
if (TerrainMeta.BiomeMap.GetBiome(pos, 1) > 0.5f)
{
SendReply(player, "Entered Desert.");
}
}
}​

 

But it doesn't seem to work properly. So I'm missing something or doing something wrong. Any ideas? Would be greatly appreciated. :)
Hey!
Are you sure biomes have triggers for it?
In response to misticos ():
Hey!
Are you sure biomes have triggers for it?
Nope I'm not sure of that. But there must be some way to do it...

Merged post

I tried

void OnPlayerTick(BasePlayer player)
       {
	   var pos = player.transform.position;
	   if (TerrainMeta.BiomeMap.GetBiome(pos, 1) > 0.5f)
	   {
	   timer.Once(1, () =>
	   {
		SendReply(player, "Entered Desert"); 
	   });
	   }
	   else return;
	   {
	   }
	   }​

But obviously it would simply spam "Entered Desert" when you enter desert...
In response to TTRRust ():
Nope I'm not sure of that. But there must be some way to do it...

Merged post

...
The spam is so ez to fix, just add a check for some variable 
bool isAlreadyIn = false;
​void OnPlayerTick(BasePlayer player)
       {
	   var pos = player.transform.position;
	   if (TerrainMeta.BiomeMap.GetBiome(pos, 1) > 0.5f)
	   {
	   timer.Once(1, () =>
	   {
if(!isAlreadyIn)
		SendReply(player, "Entered Desert");
isAlreadyIn = true; 
	   });
	   }
	   }​

Also, you don't need "return;" at the end, hook is "void"
And also DO YOU understand how many of these hooks would be called every second on a server with just 5 players? I suggest you to use a global timer which would do a check every second or two.

Thanks man. Got it working thanks to you. And yes I know they would have I was just testing.

Merged post

I removed the timer part as it's not necessary as OnPlayerTick takes care of that. But yeah it's far from optimal. Some trigger would be better.

Merged post

Ok question to people here that actually know what they are doing... I'm very much a noob at programming and I'm not trying to pretend that I know what I'm doing. So much so that when 2CHVSKII said that when a hook is void you don't need return... it was news to me. But I'm trying to learn. Rust modding is quite cool. Anyway... I'm using this code: 

bool isAlreadyIn = false;
void OnPlayerTick(BasePlayer player)
{
    var pos = player.transform.position;
    if (player is BasePlayer && player != null)
    {
        if (TerrainMeta.BiomeMap.GetBiome(pos, 1) > 0.5f)
        {
            if (!isAlreadyIn)
                SendReply(player, "You've entered the Desert.")
            isAlreadyIn = true;
        }
        else
        {
            Something else
            isAlreadyIn = false;
        }
    }
}​

And my question is... how demanding is it? I know that OnPlayerTick means it's pretty much checking every player that's online every second for their location and if it's desert biome it will send the reply. But does it keep spamming the server even with the isAlreadyIn bool? How inefficient is it? Thanks to anyone responding. :)
 
 
You need to keep track of the isAlreadyIn state for each player instead of a single variable for all players. Better yet, keep track of which biome they were in before (you can use that to do biome to biome specific tasks, like things that only run when the player moved from Desert to Snow or something):
Dictionary<ulong, float> lastBiome = new Dictionary<ulong, float>();​
Then you can use that list to check if a player is in a different biome than in the tick before and act upon it:
// Get the current biome of the player
float currentBiome = TerrainMeta.BiomeMap.GetBiome(player.transform.position, 1);

// Add the player and biome to the list if the player doesn't exist in it (first time, eg. after connecting)
if (!lastBiome.ContainsKey(player.userID))
    lastBiome.Add(player.userID, currentBiome);

// Check if the biome has changed
if (currentBiome != lastBiome[player.userID])
{
    // Player has moved from lastBiome[player.id] to currentBiome
    switch (currentBiome)
    {
        case 0.5f: // Desert
            SendReply(player, "You've entered the Desert.");
            break;
        // Mock values, just as an example
        case 0.3f: // Snow
          if (lastBiome[player.userID] == 0.5f) // Desert as last biome
            SendReply(player, "You've moved from the Desert to Snow.");
          else
            SendReply(player, "You've moved to Snow.");
          break;
    }

    // Save the current biome of this player in lastBiome
    lastBiome[player.userID] = currentBiome;
}
Doing this every tick may not be optimal. Although there aren't any large tasks like looping through a big list, it shouldn't have a big performance impact but methods like GetBiome or SendReply are out of your control and may cause slowdowns. It would probably be better if you run this on a timer and loop through all players in a coroutine every second or so.

OnPlayerTick runs as many times as you have FPS on your server, that's easily over 20 times per second. What's best for you depends on how precise you need this to be. If you want there to be no chance that a player can move from biome A to B to C within a second and not have the A->B move trigger your code then you have to use a very small delay between your checks, so OnPlayerTick would be the most precise. If precision like that isn't necessary then I would recommend to use a timer and coroutine:

private IEnumerator checkPlayerBiomeChange()
{
    BasePlayer[] players = BasePlayer.activePlayerList.ToArray();
    foreach (BasePlayer player in players)
    {
        if (!player.IsConnected)
            continue;

        // Per-player code goes here

        yield return new WaitForFixedUpdate();
    }
}​​
This will run code that loops through all active players and waits for the next frame after each player, so if you have 40 players this will take 40 frames to complete. Adjust the timer accordingly so that this method doesn't get started while the previous one is still running or use a bool to prevent execution when it's already running.

This is how to run a timer that starts this method as a coroutine every 2 seconds:
timer.Every(2f, () => ServerMgr.Instance.StartCoroutine(checkPlayerBiomeChange()));​
Hope that gives you a little something to work with.
Wow man. Awesome. Thanks alot. :)

Merged post

Hmmm... I keep getting error CS0151: A switch expression of type `float' cannot be converted to an integral type, bool, char, string, enum or nullable type with that first code... :S

Merged post

And the IEnumarator part gives "error CS0305: Using the generic type `System.Collections.Generic.IEnumerator<T>' requires `1' type argument(s)"

Merged post

My bad. Was missing using System.Collections;
Locked automatically