Which part?
Track the player’s current room: This option depends on how your room system is set up so it could work slightly differently but; if you have a cut scene for transitioning between each room you could keep a dictionary on the server which tracks the room the player is in.
local playerDic = {}
local function moveRooms(player, newRoom)
playerDic[player.Name] = newRoom
end
local function getCurrentRoom(player)
return playerDic[player.Name]
end
This could be coupled with region3 as @goldenstein64 is suggesting above (checking adjacent rooms to see if the player moved using region3 and keeping the current room in the dictionary), or could use some other method that part is up to you.
Magnitude checks: By this, I mean to loop through each room part and check if the magnitude of the distance between the character and the room is smaller than a pre-defined value or the largest axis of the room’s size. You could then use region3 on each of the returned rooms and this would mean you are using region3 on less rooms as just all of them.
You could also use a different method where you check if the magnitude between the player and the room is smaller than the rooms largest size axis, and then check each axis individually, but I’m not sure if this would be more efficient than checking region3’s for the few rooms where the player could be in the room instead.
For example:
-- get the distance between the player and the room.
local function getDistFromRoom(player, room)
return (player.Character.HumanoidRootPart.Position - room.Position).Magnitude
end
-- get the largest axis of size for the room
local function getMaxSize(room)
local size = room.Size
return math.max(math.max(size.X, size.Y), size.Z) -- bit weird
end
-- check if the players position is within the room
local function isPlayerInRoom(player, room)
local playerPos = player.Character.HumanoidRootPart.Position
local roomPos = room.Position
local roomSize = room.Size
local minX, maxX, minY, maxY, minZ, maxZ = roomPos.X - roomSize.X, roomPos.X + roomSize.X, roomPos.Y - roomSize.Y, roomPos.Y + roomSize.Y, roomPos.Z - roomSize.Z, roomPos.Z + roomSize.Z
return (playerPos.X > minX) and (playerPos.X < maxX) and (playerPos.Y > minY) and (playerPos.Y < maxY) and (playerPos.Z > minZ) and (playerPos.Z < maxZ)
end
local function playerInRoom(player, room)
if getDistFromRoom(player, room) < getMaxSize(room) then -- they might be in the room!
return isPlayerInRoom(player, room)
-- return true if the player is in the room, or false
end
return false -- not in the room.
end
This method I just came up with so it be a bad way of doing things, however I believe it would be quicker than checking each axis individually for every room.
Hope that explained it a bit better! 
I wrote this on my phone while walking, and it only just sent so hopefully everything works ok and makes sense!