A method I use for dividing scenes up, is to create a zone, which is essentially just an invisible cube, within this cube you can have sub-zones which are children to the parent zone. Depending on the environment you are rendering, you can optimize in relation to how you partition your world with these zones.
If you have an internal environment, you can make the building a parent zone, each room a zone and then create a portal in the doorway of each zone. Essentially, the portal checks to see if it is within your view volume and if so, renders the geometry on the other side of the portal. If you have several doorways in view, this means you can see each portal, and the contents of each room rendered visibly, but this is a local optimization, however this does relate.
In an external environment, you can register the players within zones and the players that are visible and of immediate effect to them. Once they enter this zone, the agents and players visible to the player are of high priority, so you prioritize the amount of data you process in relation to their actions over agents and players of a greater distance (or not at all if they are in a separate zone).
A quick method is a AABB collision detection with the zone, or use four points(like you're catching them in a net) and do your localized data streaming for that area as previously mentioned.
You do not need to fire an event constantly to check if they have left/entered a zone, as it is network based, you can check against child objects in the zone after so much movement has been detected, in relation to the size of the environment and then increase your checks as they draw closer to the zone limits, but this only works if zones are connected.
If you have "layers" of zone sizes, you can quickly isolate the location of an agent or player, then recursively traverse the relevant zones that are contained within each other, to find the player. This saves you traversing all zones in the environment to find them, and you can do checks in relation to what you need. If you need their rough location, find a "top layer" zone, one of the largest, but if you need their exact location, traverse down to the "bottom layer" zones, that pin point them in relation to objects.
Register player location in zone, check zone verts, approximate player location in relation to objects (cache data, only upate if change occurs), you now have cached data you can use to locate/reference.
Traverse zone tree starting from top, checking if depth of information is enough(do we need their rough location in an area, or their exact transform, acceleration and velocity), traverse tree.
Register other players in zone, reference those from primarily player, prioritize data packet size over closer players, approximate players further away, ignore external zones (or high approximation depending on environment)
Do other checking here(this will validate what information we need). Check player location in relation to objects (are we leaving the zone?) if not, 2, else 1.