AddCSLuaFile() local SligWolf_Addons = SligWolf_Addons if not SligWolf_Addons then return end if not SligWolf_Addons.LoadingLibraries then SligWolf_Addons.ReloadAllAddons() return end SligWolf_Addons.Rail = SligWolf_Addons.Rail or {} table.Empty(SligWolf_Addons.Rail) local LIB = SligWolf_Addons.Rail local LIBPosition = nil local LIBEntities = nil local LIBTracer = nil local g_maxRailCheckTraceAttachmentPairs = 4 LIB.ENUM_RAIL_CHECK_MODE_ALL = 0 LIB.ENUM_RAIL_CHECK_MODE_NONE = 1 LIB.ENUM_RAIL_CHECK_MODE_ANY = 2 function LIB.GetRailCheckAttachments(ent) if not IsValid(ent) then return nil end local entTable = ent:SligWolf_GetTable() local railCheckAttachmentsCache = entTable.railCheckAttachmentsCache if railCheckAttachmentsCache then return railCheckAttachmentsCache end railCheckAttachmentsCache = {} entTable.railCheckAttachmentsCache = railCheckAttachmentsCache for id = 0, g_maxRailCheckTraceAttachmentPairs - 1 do local attachmentNameA = string.format("railcheck_%ia", id) local attachmentNameB = string.format("railcheck_%ib", id) local attachmentA = LIBPosition.GetAttachmentId(ent, attachmentNameA) local attachmentB = LIBPosition.GetAttachmentId(ent, attachmentNameB) if not attachmentA then continue end if not attachmentB then continue end local line = {attachmentA, attachmentB} table.insert(railCheckAttachmentsCache, line) end return railCheckAttachmentsCache end function LIB.HasRailCheckAttachments(ent) local attachmentGroups = LIB.GetRailCheckAttachments(ent) if not attachmentGroups then return false end if table.IsEmpty(attachmentGroups) then return false end return true end local function doIsOnRailTrace(ent) local attachmentGroups = LIB.GetRailCheckAttachments(ent) if not attachmentGroups then return false end for i, attachments in ipairs(attachmentGroups) do local tr = LIBTracer.TracerAttachmentChain(ent, attachments) if not tr then continue end if not tr.Hit then continue end local hitEnt = tr.Entity if IsValid(hitEnt) and hitEnt.sligwolf_ignoreOnRailCheck then continue end return true end return false end function LIB.IsOnRail(ent, bypassCache) if not IsValid(ent) then return false end local entTable = ent:SligWolf_GetTable() local now = RealTime() local isOnRailResultCache = entTable.isOnRailResultCache or {} entTable.isOnRailResultCache = isOnRailResultCache if bypassCache ~= true and isOnRailResultCache.nextRefresh and isOnRailResultCache.nextRefresh > now then return isOnRailResultCache.result end local result = doIsOnRailTrace(ent) isOnRailResultCache.result = result isOnRailResultCache.nextRefresh = now + 0.05 return result end local function checkOnRailForEntListAny(entities, bypassCache, additionalBodyEnt) if LIB.HasRailCheckAttachments(additionalBodyEnt) and LIB.IsOnRail(additionalBodyEnt, bypassCache) then return true end if not entities then return false end for i, ent in ipairs(entities) do if not LIB.IsOnRail(ent, bypassCache) then continue end return true end return false end local function checkOnRailForEntListAll(entities, bypassCache, additionalBodyEnt) if LIB.HasRailCheckAttachments(additionalBodyEnt) and not LIB.IsOnRail(additionalBodyEnt, bypassCache) then return false end if not entities then return true end for i, ent in ipairs(entities) do if LIB.IsOnRail(ent, bypassCache) then continue end return false end return true end local function checkOnRailForEntListNone(entities, bypassCache, additionalBodyEnt) return not checkOnRailForEntListAny(entities, bypassCache, additionalBodyEnt) end local function checkOnRailForEntList(entities, bypassCache, checkMode, additionalBodyEnt) if not checkMode or checkMode == LIB.ENUM_RAIL_CHECK_MODE_ALL then return checkOnRailForEntListAll(entities, bypassCache, additionalBodyEnt) end if checkMode == LIB.ENUM_RAIL_CHECK_MODE_NONE then return checkOnRailForEntListNone(entities, bypassCache, additionalBodyEnt) end if checkMode == LIB.ENUM_RAIL_CHECK_MODE_ANY then return checkOnRailForEntListAny(entities, bypassCache, additionalBodyEnt) end error("unknown checkMode given") return nil end function LIB.IsSystemOnRail(ent, checkMode, bypassCache) local root = LIBEntities.GetSuperParent(ent) if not IsValid(root) then return false end local bogies = LIB.GetSystemBogies(root) return checkOnRailForEntList(bogies, bypassCache, checkMode, root) end function LIB.IsWagonOnRail(ent, checkMode, bypassCache) local body = LIBEntities.GetNearstBody(ent) if not IsValid(body) then return false end local bogies = LIB.GetWagonBogies(body) return checkOnRailForEntList(bogies, bypassCache, checkMode, body) end function LIB.IsBogieOnRail(ent, bypassCache) local body = LIBEntities.GetNearstBody(ent) if not IsValid(body) then return false end local bogie = LIB.GetBogie(body) if not IsValid(bogie) then if LIB.HasRailCheckAttachments(body) then bogie = body end end if not LIB.IsOnRail(bogie, bypassCache) then return false end return true end local function filterBogies(bogie) if not bogie.sligwolf_bogieEntity then return false end if not LIB.HasRailCheckAttachments(bogie) then return false end return true end function LIB.GetSystemBogies(ent) return LIBEntities.GetSystemEntitiesFiltered(ent, "bogies", filterBogies) end function LIB.GetWagonBogies(ent) local body = LIBEntities.GetNearstBody(ent) if not IsValid(body) then return nil end local cache = LIBEntities.GetEntityCache(body).children if cache.Bogies then return cache.Bogies end local subBodies = LIBEntities.GetSubBodies(body) if not subBodies then return nil end local bogies = {} for _, child in pairs(subBodies) do local bogie = LIB.GetBogie(child) table.insert(bogies, bogie) end cache.Bogies = bogies return bogies end function LIB.GetBogie(ent) local body = LIBEntities.GetNearstBody(ent) if not IsValid(body) then return nil end local cache = LIBEntities.GetEntityCache(body).children local cachedBogie = cache.Bogie if cachedBogie ~= nil then if cachedBogie == false then return nil end return cachedBogie end local bogies = LIBEntities.GetBodyEntitiesFiltered(body, "bogies", filterBogies) for i, bogie in ipairs(bogies) do cache.Bogie = bogie return bogie end cache.Bogie = false return nil end local g_switchModels = {} function LIB.AddSwitchModelStates(mainModel, states, printName) mainModel = tostring(mainModel or "") printName = tostring(printName or "") states = states or {} g_switchModels[mainModel] = g_switchModels[mainModel] or {} local statesOfModel = g_switchModels[mainModel] statesOfModel.ordered = statesOfModel.ordered or {} statesOfModel.indexed = statesOfModel.indexed or {} local ordered = statesOfModel.ordered local indexed = statesOfModel.indexed for name, item in pairs(states) do if not isstring(name) or name == "" then error(string.format("invalid model state name given for '%s'", mainModel)) return end if indexed[name] then continue end local model = tostring(item.model or "") if model == "" then error(string.format("model for state '%s' was not given for '%s'", name, mainModel)) return end local isDefault = name == "default" local order = tonumber(item.order or 0) or 0 if isDefault then order = 0 end item.order = order if not item.id or not isDefault then item.id = -1 end if not item.name or not isDefault then item.name = name end item.model = model if order ~= 0 then table.insert(ordered, item) end indexed[name] = item end table.SortByMember(ordered, "order", true) for i, item in ipairs(ordered) do item.id = i end statesOfModel.count = #ordered statesOfModel.printName = printName end function LIB.GetSwitchModelStates(mainModel) mainModel = tostring(mainModel or "") local statesOfModel = g_switchModels[mainModel] if not statesOfModel then return end local count = statesOfModel.count or 0 if count <= 0 then return end local ordered = statesOfModel.ordered local indexed = statesOfModel.indexed if not ordered then return end if not indexed then return end if table.IsEmpty(ordered) then return end if table.IsEmpty(indexed) then return end if not indexed["default"] then error(string.format("default state missing for '%s'", mainModel)) return end return statesOfModel end function LIB.Load() LIBPosition = SligWolf_Addons.Position LIBEntities = SligWolf_Addons.Entities LIBTracer = SligWolf_Addons.Tracer end return true