private static bool TryGetEntityOrigin(VmfEntity entity, out Vector3 result) { result = default; if (entity.TryGetProperty("origin", out VmfVector3 v)) { result = new Vector3(v.X * inchesInMeters, v.Z * inchesInMeters, v.Y * inchesInMeters); return(true); } return(false); }
private static bool TryGetEntityRotation(VmfEntity entity, out Quaternion result) { result = new Quaternion(); bool success = false; if (entity.TryGetProperty("angles", out VmfVector3 angles)) { result = Quaternion.Euler(-angles.X, -angles.Y + 90, angles.Z); success = true; } if (entity.TryGetProperty("pitch", out float pitch)) { if (pitch != 0.0f) { result.eulerAngles = new Vector3(-pitch, result.eulerAngles.y, result.eulerAngles.z); } success = true; } return(success); }
/// <summary> /// Imports the entities and attaches them to the specified parent. /// </summary> /// <param name="parent">The parent to attach entities to.</param> /// <param name="world">The world to be imported.</param> public static void Import(Transform parent, VmfWorld world) { #if COM_AETERNUMGAMES_CHISEL_DECALS // optional decals package: https://github.com/Henry00IS/Chisel.Decals // create a material searcher to associate materials automatically. MaterialSearcher materialSearcher = new MaterialSearcher(); HashSet <string> materialSearcherWarnings = new HashSet <string>(); #endif // iterate through all entities. for (int e = 0; e < world.Entities.Count; e++) { #if UNITY_EDITOR UnityEditor.EditorUtility.DisplayProgressBar("Chisel: Importing Source Engine Map (3/3)", "Converting Hammer Entities To Unity Objects (" + (e + 1) + " / " + world.Entities.Count + ")...", e / (float)world.Entities.Count); #endif VmfEntity entity = world.Entities[e]; switch (entity.ClassName) { // https://developer.valvesoftware.com/wiki/Light // light is a point entity available in all Source games. it creates an invisible, static light source that shines in all directions. case "light": { // create a new light object: GameObject go = new GameObject("Light"); go.transform.parent = GetLightingGroupOrCreate(parent); // set the object position: if (TryGetEntityOrigin(entity, out Vector3 origin)) { go.transform.position = origin; } // add a light component: Light light = go.AddComponent <Light>(); light.type = LightType.Point; #if UNITY_EDITOR light.lightmapBakeType = LightmapBakeType.Baked; #endif light.range = 25.0f; // set the light color: if (entity.TryGetProperty("_light", out VmfVector4 color)) { light.intensity = color.W * lightBrightnessScalar; light.color = new Color(color.X / 255.0f, color.Y / 255.0f, color.Z / 255.0f); } break; } // https://developer.valvesoftware.com/wiki/Light_spot // light_spot is a point entity available in all Source games. it is a cone-shaped, invisible light source. case "light_spot": { // create a new light object: GameObject go = new GameObject("Spot Light"); go.transform.parent = GetLightingGroupOrCreate(parent); // set the object position: if (TryGetEntityOrigin(entity, out Vector3 origin)) { go.transform.position = origin; } // set the object rotation: if (TryGetEntityRotation(entity, out Quaternion rotation)) { go.transform.rotation = rotation; } // add a light component: Light light = go.AddComponent <Light>(); light.type = LightType.Spot; #if UNITY_EDITOR light.lightmapBakeType = LightmapBakeType.Mixed; #endif light.range = 10.0f; // set the light color: if (entity.TryGetProperty("_light", out VmfVector4 color)) { light.intensity = color.W * lightBrightnessScalar; light.color = new Color(color.X / 255.0f, color.Y / 255.0f, color.Z / 255.0f); } // approximate the light cookie cone shape and the spot angle. if (entity.TryGetProperty("_inner_cone", out int inner_cone) && entity.TryGetProperty("_cone", out int cone)) { float lightInnerCone = Mathf.Min(inner_cone * 2, 175); float lightCone = Mathf.Min(cone * 2, 175); if (lightInnerCone > lightCone) { float t = lightCone; lightInnerCone = lightCone; lightCone = t; } // set the spot angle: light.spotAngle = lightCone; // generate and set the light cookie: float coneFactor = Mathf.Max(0, lightInnerCone / lightCone); light.cookie = BuildLightCookieTexture(coneFactor); } // backup approach for the spot angle. else if (entity.TryGetProperty("_cone", out int cone2)) { // set the spot angle: float lightCone = Mathf.Min(cone2 * 2, 175); light.spotAngle = lightCone; } break; } #if COM_AETERNUMGAMES_CHISEL_DECALS // optional decals package: https://github.com/Henry00IS/Chisel.Decals case "infodecal": { // create a new decal object: GameObject go = new GameObject("Decal"); go.transform.parent = GetDecalsGroupOrCreate(parent); // set the object position: if (TryGetEntityOrigin(entity, out Vector3 origin)) { go.transform.position = origin; } // add the decal component: ChiselDecal decal = go.AddComponent <ChiselDecal>(); // assign the material: if (entity.TryGetProperty("texture", out string texture)) { Material material = FindMaterial(materialSearcher, materialSearcherWarnings, texture); if (material != null) { go.GetComponent <MeshRenderer>().sharedMaterial = material; var mainTexture = material.mainTexture; if (mainTexture != null) { // use the texture size to determine the size of the decal. go.transform.localScale = new Vector3(mainTexture.width * 0.008f, mainTexture.height * 0.008f, 0.1f); } } } // it should be snug against a surface- so we try to find it. RaycastHit raycastHit = default; bool hit = false; Vector3 r = Vector3.right * 0.1f; Vector3 f = Vector3.forward * 0.1f; Vector3 u = Vector3.up * 0.1f; // try a ray cast in all world axis to find a hit. if (hit = Physics.Raycast(go.transform.position - r, r, out RaycastHit hitInfo1, 0.2f)) { raycastHit = hitInfo1; } if (!hit && (hit = Physics.Raycast(go.transform.position + r, -r, out RaycastHit hitInfo2, 0.2f))) { raycastHit = hitInfo2; } if (!hit && (hit = Physics.Raycast(go.transform.position - f, f, out RaycastHit hitInfo3, 0.2f))) { raycastHit = hitInfo3; } if (!hit && (hit = Physics.Raycast(go.transform.position + f, -f, out RaycastHit hitInfo4, 0.2f))) { raycastHit = hitInfo4; } if (!hit && (hit = Physics.Raycast(go.transform.position - u, u, out RaycastHit hitInfo5, 0.2f))) { raycastHit = hitInfo5; } if (!hit && (hit = Physics.Raycast(go.transform.position + u, -u, out RaycastHit hitInfo6, 0.2f))) { raycastHit = hitInfo6; } // shouldn't not hit unless the level designer actually messed up. if (hit) { // now we have the normal of the surface to "face align" the decal. go.transform.rotation = Quaternion.LookRotation(-raycastHit.normal); } break; } #endif } } }