Files
2025-09-29 00:52:08 +02:00

838 lines
26 KiB
Plaintext
Executable File

-- Memory Resident Zones:
-- Functions for building/exporting/loading files for setting up memory-resident model-lists
--
-- Neal D Corbett (R* Leeds) 04/2014
-- Struct will be instanced to this global:
global gRsMemResidentLists = undefined
struct RsMemResidentLists
(
-- Used to tag metafiles with format-version:
VersionNum = 1,
-- Exported prop-lists will a maximum of this many model-names:
MaxPropCount = 200,
-- Area-zone metafiles are given this prefix:
AreaFilePrefix = "AreaZone_",
-- Data loaded from scenexmls will be cached to here:
SceneXmlCachePath = (RsMakeSafeSlashes ((RsConfigGetStreamDir core:True) + "/MemResCache/")),
-- Returns the path where Memory Resident lists are stored
fn GetMetaFilePath dlc: =
(
if (dlc == Unsupplied) do
dlc = RsIsDLCProj()
return (RsMakeSafePath (RsConfigGetCommonDir core:(not dlc) + "/data/levels/" + (RsConfigGetProjectName core:(not dlc)) + "/resident/"))
),
-- Returns folder that current project is exported to
fn GetProjExportRoot dlc: =
(
if (dlc == Unsupplied) do
dlc = RsIsDLCProj()
return (RsMakeSafePath ((RsConfigGetExportLevelsDir core:(not dlc)) + ((RsConfigGetProjectName core:(not dlc))) ))
),
------------------------------------------------------------------------------------------
-- Returns list of Xml-paths for Exterior maps:
------------------------------------------------------------------------------------------
fn GetMapXmlPaths dlc: =
(
-- Get content-tree nodes for all scenes in current project:
local mapFileNodes = RsContentTree.ContentTreeHelper.GetAllMapExportNodes()
local projExportRoot = this.GetProjExportRoot dlc:dlc
-- Get list of map-metafiles:
local MapXmlPaths = for mapMaxNode in mapFileNodes collect
(
local metafilepath = dontCollect
-- Only read certain maptypes:
local mapType = (RsContentTree.GetMapType mapMaxNode) as name
if (mapType == #map_container) do
(
local ExportZipNode = (RsContentTree.GetMapExportZipNode MapMaxNode)
local ProcessedZipNode = (RsContentTree.GetMapExportZipNode ExportZipNode)
if (ProcessedZipNode != undefined) do
(
local XmlNode = RsContentTree.GetMapExportSceneXMLNode ExportZipNode
local XmlPath = XmlNode.AbsolutePath
--if (not matchPattern XmlPath pattern:"*_prologue*") do
(
-- Find relative path from ProjExportRoot to this xml-file:
local XmlRelPath = pathConfig.convertPathToRelativeTo XmlPath ProjExportRoot
-- This pattern matches if xml is under ProjExportRoot, and the xml-file actually exists:
if (matchPattern XmlRelPath pattern:".\\*") and (doesFileExist XmlPath) do
(
-- Collect matching xml:
metafilepath = XmlPath
)
)
)
)
metafilepath
)
return MapXmlPaths
),
------------------------------------------------------------------------------------------
-- Load per-map position-lists for each prop used in game:
------------------------------------------------------------------------------------------
fn LoadPropData force:False dlc: =
(
if (dlc == Unsupplied) do
dlc = RsIsDLCProj()
-- Get list of 'Exterior' map-xmls:
local mapXmlPaths = this.GetMapXmlPaths()
if (mapXmlPaths.Count == 0) do
return #()
PushPrompt "Checking Perforce for updated XMLs..."
local ChangedXmls = gRsPerforce.ChangedFiles MapXmlPaths
PopPrompt()
-- Sync latest xml-files:
if (ChangedXmls.Count != 0) do
(
local queryText = stringstream ""
local singular = (ChangedXmls.count == 1)
format "% a newer version on Perforce.\n\nWould you like to sync % now?" (if singular then "This file has" else "These files have") (if singular then "it" else "them") to:queryText
local SyncChecked = #{1..ChangedXmls.Count}
local queryVal = RsQueryBoxMultiBtn (queryText as string) title:"Updated RSref-files found on Perforce:" timeout:15 width:540 \
labels:#("Yes", "No", "Cancel Process") defaultBtn:2 cancelBtn:3 \
tooltips:#("Update SceneXml files from Perforce", "Don't update SceneXml files from Perforce", "Cancel load/generation process") \
listCheckStates:SyncChecked listItems:ChangedXmls listTitles:#("Sync", "Filename")
case queryVal of
(
-- Sync checked filenames:
1:
(
local SyncFiles = for n = SyncChecked collect ChangedXmls[n]
if (SyncFiles.Count != 0) do
(
local success = gRsPerforce.Sync ChangedXmls clobberAsk:True silent:True showProgress:True progressTitle:"Syncing exterior-map sceneXml files..."
-- Abort if sync was cancelled:
if (not success) do
return False
)
)
-- Abort if 'Cancel' was pressed:
3:(return False)
)
)
local MapDataList
-- Load scenexml data (or cachefiles if valid)
(
local TimeStart = TimeStamp()
local Success = True
ProgressStart "Loading Prop Positions..."
local FileCount = MapXmlPaths.Count
local MapDataList = for n = 1 to FileCount while (Success = ProgressUpdate (100.0 * n / FileCount)) collect
(
local XmlPath = MapXmlPaths[n]
::RsMemRes_MapData Filename:XmlPath isDlc:dlc
)
ProgressEnd()
-- Return False if load was cancelled:
if (not Success) do
return False
)
format "Time taken to parse prop-positions: %s\n" (FormattedPrint ((TimeStamp() - TimeStart) / (1000.0)) Format:".3g")
return MapDataList
),
------------------------------------------------------------------------------------------
-- Returns wildcard-descriptor for area-zone metafiles:
------------------------------------------------------------------------------------------
fn GetAreaZoneMetaPath dlc: =
(
(this.GetMetafilePath dlc:dlc) + this.areaFilePrefix + "*.meta"
),
------------------------------------------------------------------------------------------
-- Get position-lists for each map-area:
------------------------------------------------------------------------------------------
fn GetPropsByArea =
(
-- Load prop-position data from SceneXmls:
local mapDataList = this.LoadPropData()
if (not IsKindOf mapDataList Array) do
return False
if (mapDataList.count == 0) do
return #()
PushPrompt "Compiling props per area..."
local AreaNames = #()
local AreaDataList = #()
struct MapAreaData (AreaName, PropNames = #(), PropPositions = #())
for MapItem in MapDataList do
(
local MapArea = MapItem.AreaName
local AreaIdx = FindItem AreaNames MapItem.AreaName
if (AreaIdx == 0) do
(
append AreaNames MapItem.AreaName
append AreaDataList (MapAreaData AreaName:MapItem.AreaName)
AreaIdx = AreaNames.Count
)
local AreaPropNames = AreaDataList[AreaIdx].PropNames
local AreaPropPositions = AreaDataList[AreaIdx].PropPositions
local MapPropNames = MapItem.PropNames
local MapPropPositions = MapItem.PropPositions
for n = 1 to MapPropNames.Count do
(
local PropIdx = FindItem AreaPropNames MapPropNames[n]
if (PropIdx == 0) do
(
append AreaPropNames MapPropNames[n]
append AreaPropPositions #()
PropIdx = AreaPropNames.Count
)
join AreaPropPositions[PropIdx] MapPropPositions[n]
)
)
PopPrompt()
return AreaDataList
),
------------------------------------------------------------------------------------------
-- Update Memory Resident area-zone metafiles, based on props found within:
------------------------------------------------------------------------------------------
fn UpdateAreaZones dlc: =
(
-- Load prop-position data from SceneXmls:
local mapDataList = this.LoadPropData()
if (not IsKindOf mapDataList Array) do
return False
if (mapDataList.count == 0) do
return #()
-- Compile master-list of prop-positions:
PushPrompt "Compiling prop-position lists..."
local PropNames = #()
local PropPositions = #()
for MapData in MapDataList do
(
for MapPropIdx = 1 to MapData.PropNames.Count do
(
local PropName = MapData.PropNames[MapPropIdx]
local PropIdx = FindItem PropNames PropName
if (PropIdx == 0) do
(
append PropNames PropName
append PropPositions #()
PropIdx = PropNames.Count
)
join PropPositions[PropIdx] MapData.PropPositions[MapPropIdx]
)
)
local PropDataList = for n = 1 to PropNames.Count collect (DataPair Name:PropNames[n] Positions:PropPositions[n])
PropNames.Count = 0
PropPositions.Count = 0
PopPrompt()
local metafilePath = (this.GetAreaZoneMetaPath dlc:dlc)
-- Sync latest Area-zone metafiles:
gRsPerforce.SyncChanged #(MetafilePath) clobberAsk:False silent:True
-- Checkout area-zone metafiles:
local AreaZoneFiles = GetFiles MetafilePath
gRsPerforce.Add_Or_Edit AreaZoneFiles
-- Import metafile boxes:
-- (don't both loading model-lists)
local AreaZones = for Filename in AreaZoneFiles collect
(
local LoadedArea = RsMemRes_Zone.Import Filename Models:False
if (LoadedArea == undefined) then DontCollect else LoadedArea
)
local AreaPropCounts = for AreaZone in AreaZones collect
(
DataPair Zone:AreaZone Props:#()
)
-- Run through each prop-list in turn, work out which prop is in each area, and how many of each:
for ThisProp in PropDataList do
(
local PropName = ThisProp.Name
for AreaItem in AreaPropCounts do
(
local AreaPropItem = (DataPair Name:PropName Count:0)
append AreaItem.Props AreaPropItem
local ThisZone = AreaItem.Zone
-- Check all positions to see if they're in the box:
for ThisPos in ThisProp.Positions do
(
if (ThisZone.IsInsideBox ThisPos) do
(
AreaPropItem.Count += 1
)
)
)
)
fn Sorter v1 v2 = (v2.Count - v1.Count)
-- Update area-metafiles:
for AreaItem in AreaPropCounts do
(
-- Filter out props with fewer than minimum number of instances in area:
AreaItem.Props = for PropItem in AreaItem.Props where (PropItem.Count > 1) collect PropItem
-- Sort props in ascending order of instance-counts:
qsort AreaItem.Props Sorter
-- Cut list down to maximum-allowed length:
if (AreaItem.Props.Count > MaxPropCount) do
(
AreaItem.Props = for n = 1 to MaxPropCount collect
(
AreaItem.Props[n]
)
)
format "%'s residents-list has % model-names:\n" AreaItem.Zone.ZoneName AreaItem.Props.Count
for PropItem in AreaItem.Props do
(
format " %: %\n" PropItem.Name PropItem.Count
)
-- Update zone's propname-list:
AreaItem.Zone.PropNames = for PropItem in AreaItem.Props collect PropItem.Name
)
-- Re-export area-metafiles with their updated model-lists:
for AreaItem in AreaPropCounts do
(
AreaItem.Zone.Export()
)
return AreaPropCounts
),
------------------------------------------------------------------------------------------
-- Finds exported Area zones that intersect BoxMin/BoxMax,
-- and returns list of resident models combined from each zone found:
------------------------------------------------------------------------------------------
fn GetAreaPropsForBox BoxMin BoxMax =
(
PushPrompt "Memory Residents: Searching for intersecting Area zones..."
-- Sync Area zone-metafiles:
local CheckPath = (GetAreaZoneMetaPath())
gRsPerforce.SyncChanged #(CheckPath) clobberAsk:True silent:True showProgress:True progressTitle:"Syncing Area Resident Lists..."
-- Get list of metafiles, and import zones:
local LoadFiles = (getFiles CheckPath)
local AreaZones = for ThisFilename in LoadFiles collect (::RsMemRes_Zone.Import ThisFilename)
local PropNames = #()
for ThisZone in AreaZones where (ThisZone != undefined) do
(
local BoxIntersects = True
-- Compare x/y/z values:
for n = 1 to 3 while BoxIntersects do
(
MinA = BoxMin[n]
MaxA = BoxMax[n]
MinB = ThisZone.MinPos[n]
MaxB = ThisZone.MaxPos[n]
-- False if boxes don't coincide on this axis:
BoxIntersects = not ((MaxA < MinB) or (MinA > MaxB))
)
-- Collect props from intersecting area-zone:
if BoxIntersects do
(
local LogMsg = StringStream ""
format "Box intersects area-zone: % (% resident models)" ThisZone.ZoneName ThisZone.PropNames.Count To:LogMsg
gRsUlog.LogMessage (LogMsg as String) context:"MemoryResidents"
join PropNames ThisZone.PropNames
)
)
-- Remove duplicate prop-names:
PropNames = (MakeUniqueArray PropNames)
PopPrompt()
gRsUlog.LogMessage ("PropNames loaded from Area-Zone Memory Resident lists: " + (PropNames.Count as String)) context:"MemoryResidents"
return PropNames
)
)
------------------------------------------------------------------------------------------
-- Defines information on props used in a particular map-scene:
-- (Must be instantiated with 'Filename' xml-path argument)
------------------------------------------------------------------------------------------
struct RsMemRes_MapData
(
PropNames = #(), PropPositions = #(),
Filename, AreaName, FileHash = 0,
isDlc = False,
fn GetCacheFilename =
(
gRsMemResidentLists.SceneXmlCachePath + (GetFilenameFile Filename) + ".txt"
),
------------------------------------------------------------------------------------------
-- Store data to XML cache-file:
------------------------------------------------------------------------------------------
fn StoreDataCache =
(
makeDir gRsMemResidentLists.SceneXmlCachePath
local CacheFilename = (GetCacheFilename())
if (DoesFileExist CacheFilename) do (SetFileAttribute CacheFilename #readOnly False)
local SaveStream = stringStream ""
-- Store basic details: file-hash, source-filename, and version-number:
format "%\n%\nVersion:%\n" FileHash Filename gRsMemResidentLists.VersionNum to:SaveStream
-- Store names and positions of each prop:
for n = 1 to PropNames.Count do
(
local PropName = PropNames[n]
local PosList = PropPositions[n]
format "%\n" PropName to:SaveStream
for ThisPos in PosList do
(
format "%\n" ThisPos to:SaveStream
)
)
try
(
local Fstream = CreateFile CacheFilename
format "%" (SaveStream as string) to:Fstream
close Fstream
gRsUlog.LogMessage ("Successfully saved Memory Resident list: " + CacheFilename) context:"MemoryResidents"
)
catch
(
gRsUlog.LogWarning ("Failed to save Memory Resident list! " + CacheFilename) context:"MemoryResidents"
messageBox ("Failed to save Memory Resident list!\n\n" + CacheFilename) title:"XML file-save failure"
)
),
------------------------------------------------------------------------------------------
-- Reload pre-processed data, if found:
------------------------------------------------------------------------------------------
fn LoadCachedData =
(
local CacheFilename = (GetCacheFilename())
if (not DoesFileExist CacheFilename) do return False
-- Reset lists:
PropNames.Count = 0
PropPositions.Count = 0
local FStream = openFile CacheFilename
local CachedHash = readLine FStream
-- Return if cached hash doesn't match file:
if (FileHash != CachedHash) do
(
return False
)
-- Skip sourcefile-path and cache's version-number, they're just intended for human debugging:
skipToNextLine FStream
skipToNextLine FStream
-- Return if file has no props named:
if (eof FStream) do return True
-- Get first prop-name...
local PropName = readLine FStream
-- Loop through the rest of the file:
while (not eof FStream) do
(
append PropNames PropName
local ThisPropPositions = #()
append PropPositions ThisPropPositions
PropName = undefined
while (not eof Fstream) and (PropName == undefined) do
(
local ThisLine = readLine Fstream
-- This line will either be a position for the current propname, or will be the next propname:
if (ThisLine[1] == "[") then
(
append ThisPropPositions (execute ThisLine)
)
else
(
PropName = ThisLine
)
)
)
close FStream
return True
),
------------------------------------------------------------------------------------------
-- Load prop-positions for 'Filename'
------------------------------------------------------------------------------------------
fn LoadPropsFromXml =
(
-- Reset lists:
PropNames.Count = 0
PropPositions.Count = 0
-- Get hashvalue from file-data/version:
FileHash = (GetHashValue (GetFileModDate Filename) gRsMemResidentLists.VersionNum) as String
-- Attempt to load cached prop-list for this map:
local ValidCache = LoadCachedData()
-- Return if cache was valid:
if ValidCache do return True
-- If not, load the map's latest scenexml:
local ObjectsOnly = (dotNetClass "RSG.SceneXml.LoadOptions").Objects
local SceneXml = dotnetobject "RSG.SceneXml.Scene" Filename ObjectsOnly True
-- Get flat list of scene's object-elements:
local SceneObjs = #()
join SceneObjs SceneXml.Objects
for ThisObj in SceneXml.Objects do
(
join SceneObjs (ThisObj.GetChildrenRecursive())
)
-- Filter out non-ref objects:
local RefObjs = for Obj in SceneObjs where (Obj.IsRefObject() and (not Obj.DontExport())) collect Obj
-- Collect positions of suitable props:
for Obj in RefObjs do
(
local ObjName = ToLower (Obj.GetObjectName())
local PropNum = findItem PropNames ObjName
if (PropNum == 0) do
(
append PropNames ObjName
append PropPositions #()
PropNum = PropNames.Count
)
(
-- Get prop's position:
local ObjXformPos = Obj.ObjectTransform.D
local ObjPos = [ObjXformPos.X, ObjXformPos.Y, ObjXformPos.Z]
append PropPositions[PropNum] ObjPos
)
--format "%: %\n" ObjName ObjPos
)
-- Store newly-loaded data to cache-file:
StoreDataCache()
return True
),
------------------------------------------------------------------------------------------
-- Automatically load data from Filename when this struct is instanced:
------------------------------------------------------------------------------------------
on Create do
(
if (Filename == undefined) or (not DoesFileExist Filename) do return False
-- Get AreaName from name of scenexml's off-the-root parent-folder:
(
-- Find xml's path relative to Project Export Root:
-- ('GetMapXmlPaths' will have already filtered path to ensure it's under here)
local projExportRoot = RsMemResidentLists.GetProjExportRoot dlc:this.isDlc
local XmlRelPath = (pathConfig.convertPathToRelativeTo Filename ProjExportRoot)
AreaName = pathConfig.stripPathToTopParent (pathConfig.removePathTopParent XmlRelPath)
)
LoadPropsFromXml()
)
)
------------------------------------------------------------------------------------------
-- Defines a Memory Resident Props zone, which is used to export/import data:
------------------------------------------------------------------------------------------
struct RsMemRes_Zone
(
ZoneName, -- Name of zone
Filename, -- Filename for zone's metafile
PropNames = #(), -- Names of models that will be made memory-resident when player is in this zone
MinPos, MaxPos, -- Zone's bounding-box
------------------------------------------------------------------------------------------
-- Returns 'True' if 'Pos' is within zone-box:
------------------------------------------------------------------------------------------
fn IsInsideBox Pos =
(
local IsInside = True
-- Test x/y/z values:
for n = 1 to 3 while IsInside do
(
IsInside = not ((Pos[n] < MinPos[n]) or (Pos[n] > MaxPos[n]))
)
return IsInside
),
------------------------------------------------------------------------------------------
-- Create box-object to show area-zone:
------------------------------------------------------------------------------------------
fn CreateBoxObj =
(
-- Set random-seed based on ZoneName, so boxes with same name will be same colour:
Seed (GetHashValue ZoneName 1)
local Clr = RsGetRandomColour()
local BoxSize = (MaxPos - MinPos)
local BoxPos = minPos + ([BoxSize.X, BoxSize.Y, 0] / 2)
Box name:ZoneName pos:BoxPos width:BoxSize.X length:BoxSize.Y height:BoxSize.Z WireColor:Clr
),
------------------------------------------------------------------------------------------
-- Initialise this zone-descriptor with values taken from 'MapAreaData' struct:
------------------------------------------------------------------------------------------
fn InitAreaBlock AreaData dlc:False =
(
-- Generate zone-name and metafile-export path from area-name:
ZoneName = (gRsMemResidentLists.AreaFilePrefix + AreaData.AreaName)
Filename = (gRsMemResidentLists.GetMetafilePath dlc:dlc + ZoneName + ".meta")
-- Pair off the prop-names/positions for models with enough instances:
local AreaPropNames = AreaData.PropNames
local AreaPropPositions = AreaData.PropPositions
local AreaProps = for n = 1 to AreaPropNames.Count collect
(
if (AreaPropPositions[n].Count < gRsMemResidentLists.MinInstances) then DontCollect else
(
DataPair Name:AreaPropNames[n] Positions:AreaPropPositions[n]
)
)
-- Sort props in ascending order of instance-counts:
fn Sorter v1 v2 = (v2.Positions.Count - v1.Positions.Count)
qsort AreaProps Sorter
format "%: % props\n" ZoneName AreaProps.Count
for item in AreaProps do
(
--format " %:%\n" Item.Name Item.Positions.Count
)
-- Find bounding-box for zone:
if (AreaProps.Count != 0) do
(
local PropPositions = #()
for Item in AreaProps do
(
append PropNames Item.Name
join PropPositions Item.Positions
)
RsGetBBox PropPositions &MinPos &MaxPos
-- Apply padding:
local Padding = 300
MinPos -= Padding
MaxPos += Padding
--CreateBoxObj()
)
return OK
),
------------------------------------------------------------------------------------------
-- Export this memory-resident zone to metafile:
------------------------------------------------------------------------------------------
fn Export =
(
gRsUlog.LogMessage ("Storing Memory Resident list: " + Filename) context:"MemoryResidents" quiet:False
print This
-- Init xml doc:
local xmlDoc = XmlDocument()
xmlDoc.init()
local xmlRoot = xmlDoc.createElement "CZonedAssets" appendTo:xmlDoc.Document
local xmlElem = xmlDoc.createElement "Name" appendTo:xmlRoot
xmlElem.innerText = ZoneName
-- Add map-extents:
(
local extentsElem = xmlDoc.createElement "Extents" appendTo:xmlRoot
local xmlElem = RsCreateXmlElement "min" #(dataPair name:"x" value:(MinPos.X), dataPair name:"y" value:(MinPos.Y), dataPair name:"z" value:(MinPos.Z)) xmlDoc
extentsElem.AppendChild(xmlElem)
local xmlElem = RsCreateXmlElement "max" #(dataPair name:"x" value:(MaxPos.X), dataPair name:"y" value:(MaxPos.Y), dataPair name:"z" value:(MaxPos.Z)) xmlDoc
extentsElem.AppendChild(xmlElem)
)
-- Add model-names:
local filesElem = xmlDoc.createElement "Models" appendTo:xmlRoot
for PropName in PropNames do
(
local xmlElem = xmlDoc.createElement "Item" appendTo:filesElem
xmlElem.innerText = PropName
)
-- Set version-number:
local xmlElem = RsCreateXmlElement "Version" #(dataPair name:"value" value:gRsMemResidentLists.VersionNum) xmlDoc
xmlRoot.AppendChild(xmlElem)
try
(
xmlDoc.save Filename
gRsUlog.LogMessage ("Successfully saved Memory Resident list " + Filename) context:"MemoryResidents"
)
catch
(
gRsUlog.LogWarning ("Failed to save Memory Resident list! " + Filename) context:"MemoryResidents"
messageBox ("Failed to save Memory Resident list!\n\n" + Filename) title:"XML file-save failure"
)
),
------------------------------------------------------------------------------------------
-- Import 'RsMemRes_Zone' instance from a metafile:
------------------------------------------------------------------------------------------
fn Import ImportFilename Models:True =
(
if (not DoesFileExist ImportFilename) do return undefined
local NewZone = RsMemRes_Zone Filename:ImportFilename
try
(
local XmlReader = dotNetObject "System.Xml.XmlTextReader" ImportFilename
while (XmlReader.Read()) do
(
if (XmlReader.IsStartElement()) do
(
case (XmlReader.Name as Name) of
(
#Item:
(
if Models do
(
XmlReader.Read()
local PropName = XmlReader.Value
append NewZone.PropNames PropName
)
)
#Name:
(
XmlReader.Read()
NewZone.ZoneName = XmlReader.Value
)
#Min:
(
NewZone.MinPos = [0,0,0]
for n = 1 to 3 do
(
local Val = XmlReader.GetAttribute (n - 1)
NewZone.MinPos[n] = (Val as Float)
)
)
#Max:
(
NewZone.MaxPos = [0,0,0]
for n = 1 to 3 do
(
local Val = XmlReader.GetAttribute (n - 1)
NewZone.MaxPos[n] = (Val as Float)
)
)
)
)
)
XmlReader.Close()
)
catch
(
return undefined
)
-- Return undefined if certain values weren't loaded:
if (NewZone.ZoneName == undefined) or (NewZone.MinPos == undefined) or (NewZone.MaxPos == undefined) do
(
NewZone = undefined
)
return NewZone
)
)
gRsMemResidentLists = RsMemResidentLists()
--gRsMemResidentLists.GetAreaPropsForBox [0,0,0] [100,100,100]
--global blah = gRsMemResidentLists.UpdateAreaZones()