DynamicMapService

동적 맵 제어 관련 기능을 제공합니다.

# Methods

[{"index":"DynamicMapResultCode CreateDynamicMap(string sourceMapName, string newMapName) (ServerOnly)","0":"동적 맵을 생성합니다. sourceMapName은 복사할 원본 맵의 이름, newMapName은 생성할 동적 맵의 이름입니다. 원본 맵으로 사용할 수 있는 맵은 룸 종류에 따라 달라집니다.정적 룸에서는 정적 맵만, 인스턴스 룸에서는 인스턴스 맵만 원본 맵으로 사용할 수 있고, 인스턴스 룸에서는 룸에 포함된 인스턴스 맵만 원본 맵으로 사용할 수 있습니다."}]

[{"index":"DynamicMapResultCode DestroyDynamicMap(string mapName) (ServerOnly)","0":"동적 맵을 파괴합니다. mapName은 파괴할 동적 맵의 이름입니다. 맵에 유저가 입장해 있다면 파괴할 수 없습니다."}]

[{"index":"table GetDynamicMapNameList() (ServerOnly)","0":"존재하는 모든 동적 맵의 이름을 얻어 옵니다."}]

##### inherited from Service:

[{"index":"EventHandlerBase ConnectEvent(string key, IScriptFunction eventHandler)","0":"이벤트를 연결합니다. 이 서비스에서 타입의 이름이 key인 이벤트가 발생하면, 핸들러로 통지받습니다. 핸들러는 event 매개 변수를 전달받습니다."}]

[{"index":"EventHandlerBase ConnectEvent(Type eventType, IScriptFunction eventHandler)","0":"이벤트를 연결합니다. 이 서비스에서 타입이 eventType인 이벤트가 발생하면, 핸들러로 통지받습니다. 핸들러는 event 매개 변수를 전달받습니다."}]

[{"index":"boolean DisconnectEvent(string key, EventHandlerBase eventHandler)","0":"타입의 이름이 key인 이벤트와 핸들러와의 이벤트 연결을 끊습니다."}]

[{"index":"boolean DisconnectEvent(Type eventType, EventHandlerBase eventHandler)","0":"타입이 eventType인 이벤트와 핸들러와의 연결을 끊습니다."}]

[{"index":"void SendEvent(EventType sendEvent)","0":"이벤트를 발생시킵니다."}]

# 유의 사항

  1. 동적 맵에 있는 모든 컴포넌트의 OnBeginPlay가 호출 된 후에 ResultCode가 반환됩니다. OnBeginPlay 실행이 오래 걸리는 맵을 동적 맵으로 생성하면 월드 성능 하락의 요인이 될 수 있습니다.

  2. OnBeginPlay에서 재귀 생성을 유의해야 합니다. 원본 맵의 OnBeginPlay에서 동적 맵을 생성하면 재귀적으로 반복해서 동적 맵이 생성되어 오류가 발생할 수 있습니다.




# Examples

DynamicMap 생성, 관리, 파괴하는 시나리오 예제입니다.
    
    
    @Component
    script DynamicBossMapManager extends Component
        @ExecSpace("ServerOnly")
        method boolean TryEnterPartyBossMap(table userList, string bossName, integer difficult)
        -- 원본 맵의 이름을 지정합니다. 이 예제는 보스 이름 + Base+ 난이도(예: ZakumBase1)로 가정합니다.
        local bossMapName = bossName .. "Base" .. tostring(math.tointeger(difficult))
        local newMapName = bossName .. tostring(_UtilLogic:RandomInteger())
    
        -- 동적 맵은 중복된 이름을 사용할 수 없습니다. 이름이 중복되는 경우 새로운 이름을 만듭니다.
        while not self:IsValidDynamicMapName(newMapName) do
        	newMapName = bossName .. tostring(_UtilLogic:RandomInteger())
        end
    
        -- 동적 맵을 생성합니다.
        local resultCode = _DynamicMapService:CreateDynamicMap(bossMapName, newMapName)
    
        if resultCode ~= DynamicMapResultCode.Success then
        	-- 동적 맵 생성에 실패한 경우 에러 코드를 알려줍니다.
        	self:OnError(resultCode)
        	return false
        end
    
        local reservedUserEntities = {}
        local reserved = true
    
        -- 새로운 맵으로 이동할 수 있도록 예약합니다.
        for index, userId in pairs(userList) do
        	local userEntity = _UserService:GetUserEntityByUserId(userId)
        	reserved = reserved and  _TeleportService:ReserveTeleportToMapPosition(userEntity, Vector3.zero, newMapName)
        	if not reserved then
        		break
        	end
        	table.insert(reservedUserEntities, userEntity)
        end
    
        -- 맵 이동 예약을 실패 시의 처리 방식입니다.
        if not reserved then
        	for index, userEntity in pairs(reservedUserEntities) do
        		_TeleportService:UnReserveTeleport(userEntity)
        	end
        	self:DestroyDynamicMap(newMapName)
        	return false
        end
    
        -- 동적 맵 관리에 필요한 정보를 생성한 후 예약된 맵 이동을 실행합니다.
        local userIdSet = {}
        for index, userId in pairs(userList) do
        	userIdSet[userId] = true
        end
    
        self.userIdSetByDynamicMapName[newMapName] = userIdSet
        self.dynamicMapNameSet[newMapName] = true
        _TeleportService:TeleportReservedEntities()
    
        return true
        end
    
        @ExecSpace("ServerOnly")
        method void OnBossCleared(string mapName)
        if self.dynamicMapNameSet[mapName] == nil then
        	return
        end
    
        -- 동적 맵에 존재하는 모든 유저를 'Lobby' 맵으로 이동시킵니다.
        local userEntityList = _UserService:GetUsersByMapName(mapName)
        for i, userEntity in pairs(userEntityList) do
        	_TeleportService:ReserveTeleportToMapPosition(userEntity, Vector3.zero, "Lobby")
        end
        _TeleportService:TeleportReservedEntities()
    
        self:DestroyDynamicMap(mapName)
        end
    
        @ExecSpace("ServerOnly")
        method void DestroyDynamicMap(string mapName)
        -- 동적 맵을 파괴합니다.
        local resultCode = _DynamicMapService:DestroyDynamicMap(mapName)
    
        if resultCode ~= DynamicMapResultCode.Success then
        	self:OnError(resultCode)
        	return
        end
    
        -- 파괴한 동적 맵과 관련된 정보를 제거합니다.
        self.dynamicMapNameSet[mapName] = nil
        self.userIdSetByDynamicMapName[mapName] = nil
        end
    
        @ExecSpace("ServerOnly")
        @EventSender("Service", "UserService")
        handler HandleUserLeaveEvent(UserLeaveEvent event)
        	-- 동적 맵에 존재하던 유저가 월드에서 퇴장 시 처리 방식입니다.
        	local UserId = event.UserId
        	local userEntity = _UserService:GetUserEntityByUserId(UserId)
        	local mapName = userEntity.CurrentMapName
    
        	-- 유저가 있던 맵이 동적 맵인지 확인합니다.
        	if self.dynamicMapNameSet[mapName] == nil then
        		return
        	end
    
        	-- 동적 맵에 입장해 있는 유저 목록에서 해당 유저를 제거합니다.
        	local userSet = self.userIdSetByDynamicMapName[mapName]
        	userSet[UserId] = nil
    
        	-- 동적 맵에 남은 유저가 없으면 동적 맵을 파괴합니다.
        	local isEmpty = (next(userSet, nil) == nil)
        	if isEmpty then
    
        -- 		userEntity:ConnectEvent(EntityDestroyEvent, function()
        -- 			self:DestroyDynamicMap(mapName)
        -- 		end)
        -- [Commented: MLUA requires @EventSender + handler pattern]
        	end
        end
    end
    

# SeeAlso

  * UtilLogic
  * math
  * TeleportService
  * UserService