RVInterior 模块:车辆内部地图管理
-- RVInterior 模块,用于管理车辆内部地图的相关功能 if RVInterior == nil then RVInterior = { 'interior' = {}, -- 存储车辆内部地图的信息 'interiorStride' = 60, -- 内部地图的步长 'interiorSquare' = 5 -- 内部地图的边长 } end
--- 为指定的车辆基本名称关联一组25个内部地图。这些内部地图应该按照5x5的网格排列,每60个瓦片重复一次。 ---@param vehicleName string 车辆名称,由vehicle:getScript():getFullName返回。 ---@param entryPoint table 玩家应该出现在第一个车辆实例中的 '{x,y,z}' 坐标中 --- (也就是5x5车辆内部地图中最左上角的那个实例)。 ---@param generatorOffset table (可选) 如果设置,定义了内部的隐藏发电机应放置的 '{x,y,z}' 偏移量。 --- 如果省略,默认为'{0,9,0}' RVInterior.addInterior = function(vehicleName, entryPoint, generatorOffset) -- 检查是否与现有的内部地图重叠 local margin = RVInterior.interiorStride / 3 local max = (RVInterior.interiorSquare - 1) * RVInterior.interiorStride + margin for otherVehicleName, params in pairs(RVInterior.interior) do if params.entryPoint and entryPoint[1] + max > params.entryPoint[1] - margin and entryPoint[1] - margin < params.entryPoint[1] + max and entryPoint[2] + max > params.entryPoint[2] - margin and entryPoint[2] - margin < params.entryPoint[2] + max then error('RVInterior ERROR: 新区域 ' .. vehicleName .. ' 与现有地图 ' .. otherVehicleName .. ' 重叠') end end RVInterior.interior[vehicleName] = { entryPoint = entryPoint, generatorOffset = generatorOffset or {0, 9, 0} } end
--- 标记某些车辆/内部地图为船,因此在从车辆到内部地图和反之间进行转换时,mod会采取额外的步骤 --- (否则,玩家会在水中停留一会儿并被淋湿) RVInterior.setInteriorIsBoat = function(vehicleName) if not RVInterior.interior[vehicleName] or not RVInterior.interior[vehicleName].entryPoint then error('RVInterior ERROR: 必须先调用addInterior(''..vehicleName..''),再调用setInteriorIsBoat函数。') end RVInterior.interior[vehicleName].isBoat = true end
--- 注册共享现有内部地图的其他车辆类型。 RVInterior.shareInterior = function(vehicleName, sharedInteriorVehicleName) if not RVInterior.interior[sharedInteriorVehicleName] then error('RVInterior ERROR: 必须先定义共享的内部地图 ' .. sharedInteriorVehicleName .. ',再调用shareInterior函数。') end RVInterior.interior[vehicleName] = { sharedInterior = sharedInteriorVehicleName } end
--- 添加用于查找车辆内部实例的替代字段名 RVInterior.addVehicleInteriorInstanceAlias = function(vehicleName, fieldName) if not RVInterior.interior[vehicleName] then error('RVInterior ERROR: 必须先添加 ' .. vehicleName .. ' 的内部地图,再调用addInteriorAlias函数。') end if RVInterior.interior[vehicleName].interiorInstanceAlias then table.insert(RVInterior.interior[vehicleName].interiorInstanceAlias, fieldName) else RVInterior.interior[vehicleName].interiorInstanceAlias = { fieldName } end end
--- 设置仅用于指定位置删除旧发电机实例的发电机偏移量 RVInterior.addVehicleDeleteGeneratorOffset = function(vehicleName, deleteGeneratorOffset) if not RVInterior.interior[vehicleName] or not RVInterior.interior[vehicleName].entryPoint then error('RVInterior ERROR: 必须先调用addInterior(''..vehicleName..''),再调用addVehicleDeleteGeneratorOffset函数。') end if not RVInterior.interior[vehicleName].deleteGeneratorOffset then RVInterior.interior[vehicleName].deleteGeneratorOffsets = { deleteGeneratorOffset } else table.insert(RVInterior.interior[vehicleName].deleteGeneratorOffsets, deleteGeneratorOffset) end end
--- 获取规范的车辆名称,以处理共享现有内部地图的车辆。 RVInterior.getVehicleName = function(vehicleName, nilOnUnknown) while RVInterior.interior[vehicleName] and RVInterior.interior[vehicleName].sharedInterior do vehicleName = RVInterior.interior[vehicleName].sharedInterior end if not RVInterior.interior[vehicleName] then if nilOnUnknown then return nil else error('RVInterior ERROR: 未知的车辆类型: ' .. vehicleName) end end return vehicleName end
--- 是否存在车辆内部地图参数 RVInterior.hasInteriorParameters = function(vehicleName) return (RVInterior.interior[vehicleName] ~= nil) end
--- 车辆是否有内部地图参数 RVInterior.vehicleHasInteriorParameters = function(vehicle) return (vehicle and RVInterior.interior[vehicle:getScript():getFullName()] ~= nil) end
--- 获取内部地图参数 RVInterior.getInteriorParameters = function(vehicleName) return RVInterior.interior[RVInterior.getVehicleName(vehicleName)] end
--- 获取内部地图坐标 RVInterior.getInteriorCoordinates = function(vehicleName, interiorInstance) local interiorParams = RVInterior.getInteriorParameters(vehicleName) local interiorX = (interiorInstance - 1) % RVInterior.interiorSquare; local interiorY = math.floor((interiorInstance - 1) / RVInterior.interiorSquare); local x = interiorParams.entryPoint[1] + RVInterior.interiorStride * interiorX local y = interiorParams.entryPoint[2] + RVInterior.interiorStride * interiorY local z = interiorParams.entryPoint[3] return { x = x, y = y, z = z } end
--- 获取发电机坐标 RVInterior.getGeneratorCoordinates = function(vehicleName, interiorInstance) local entryPoint = RVInterior.getInteriorCoordinates(vehicleName, interiorInstance) local interiorParams = RVInterior.getInteriorParameters(vehicleName) return { x = entryPoint.x + interiorParams.generatorOffset[1], y = entryPoint.y + interiorParams.generatorOffset[2], z = entryPoint.z + interiorParams.generatorOffset[3] } end
RVInterior.getDeleteGeneratorCoordinates = function(vehicleName, interiorInstance) local interiorParams = RVInterior.getInteriorParameters(vehicleName) local result = {} if interiorParams.deleteGeneratorOffsets then local entryPoint = RVInterior.getInteriorCoordinates(vehicleName, interiorInstance) for index, offset in pairs(interiorParams.deleteGeneratorOffsets) do result[index] = { x = entryPoint.x + offset[1], y = entryPoint.y + offset[2], z = entryPoint.z + offset[3] } end end return result end
-- Iterate over all added interiors and return the vehicleName of the map region the player's X & Y coords are inside. RVInterior.playerInsideInterior = function(player) local x = player:getX() local y = player:getY() local margin = RVInterior.interiorStride / 3 local max = (RVInterior.interiorSquare - 1) * RVInterior.interiorStride + margin for vehicleName, params in pairs(RVInterior.interior) do if params.entryPoint and x > params.entryPoint[1] - margin and x < params.entryPoint[1] + max and y > params.entryPoint[2] - margin and y < params.entryPoint[2] + max then return vehicleName end end return nil end
--- Calculate a player's interiorInstance and vehicleName (if not provided) based on their coordinates. RVInterior.calculatePlayerInteriorInstance = function(player, vehicleName) if not vehicleName then vehicleName = RVInterior.playerInsideInterior(player) if not vehicleName then return nil end else vehicleName = RVInterior.getVehicleName(vehicleName) end local interiorParams = RVInterior.getInteriorParameters(vehicleName) local instanceX = math.floor(0.5 + (player:getX() - interiorParams.entryPoint[1]) / RVInterior.interiorStride) local instanceY = math.floor(0.5 + (player:getY() - interiorParams.entryPoint[2]) / RVInterior.interiorStride) if instanceX < 0 or instanceX >= RVInterior.interiorSquare or instanceY < 0 or instanceY >= RVInterior.interiorSquare then return nil end local interiorInstance = 1 + instanceX + instanceY * RVInterior.interiorSquare return { vehicleName = vehicleName, interiorInstance = interiorInstance } end
--- Get the rvInterior modData associated with a vehicle, potentially migrating legacy modData. Turns out vehicle --- modData is available on both the client and server in MP. RVInterior.getVehicleModData = function(vehicle, interiorParams) if not interiorParams then local vehicleName = RVInterior.getVehicleName(vehicle:getScript():getFullName()) interiorParams = RVInterior.getInteriorParameters(vehicleName) end local result = vehicle:getModData().rvInterior if not result and interiorParams.interiorInstanceAlias then for _, alias in pairs(interiorParams.interiorInstanceAlias) do if vehicle:getModData()[alias] then vehicle:getModData().rvInterior = { interiorInstance = vehicle:getModData()[alias] } return vehicle:getModData().rvInterior end end end return result end
--- Test if a player would be considered to be trespassing in a vehicle interior, based on whether they're in a --- multiplayer game or not, the server's trespass setting and whether someone has created a safehouse in the interior. RVInterior.isPlayerTrespassingInInterior = function(vehicle, player) if getWorld():getGameMode() == 'Multiplayer' and not getServerOptions():getBoolean('SafehouseAllowTrepass') then -- Trepass. Not trespass, trepass. local vehicleName = RVInterior.getVehicleName(vehicle:getScript():getFullName()) local vehicleModData = RVInterior.getVehicleModData(vehicle, RVInterior.getInteriorParameters(vehicleName)) if vehicleModData then local interiorInstance = vehicleModData.interiorInstance local coords = RVInterior.getInteriorCoordinates(vehicleName, interiorInstance) local square = getCell():getOrCreateGridSquare(coords.x, coords.y, coords.z) if SafeHouse.isSafeHouse(square, player:getUsername(), true) then -- Trespassing in safehouses is not allowed in general and the interior is a non-friendly safehouse. return true end end end return false end
--- Flag certain vehicle as being able to be entered from the back. --- Add new vehicles by adding 'RVInterior.canEnterFromBack(vehicleName,true)' in their ServerDeal file --- A restart is necessary to apply changes RVInterior.canEnterFromBackList = {} RVInterior.canEnterFromBack = function(vehicleName, canEnter) if not vehicleName then return end if not canEnter then canEnter = false end RVInterior.canEnterFromBackList[vehicleName] = canEnter end
原文地址: https://www.cveoy.top/t/topic/nn1d 著作权归作者所有。请勿转载和采集!