public void Display(object data, bool isRowOdd) { SetupControls(); m_building = data as BuildingData; m_name.text = m_building.displayName; float maxLabelWidth = width - 120; if (m_building.hasAuthor) { m_author.spriteName = "AchievementCheckedTrue"; } else { m_author.spriteName = "AchievementCheckedFalse"; } if (m_building.hasLocal) { m_local.spriteName = "AchievementCheckedTrue"; } else { m_local.spriteName = "AchievementCheckedFalse"; } if (isRowOdd) { background.backgroundSprite = "UnlockingItemBackground"; background.color = new Color32(0, 0, 0, 128); } else { background.backgroundSprite = null; } }
public static bool Prefix(BuildingInfo __instance) { // Basic sanity check before proceeding; if failed, don't do anything here - just continue on to game method. if (__instance.name == null) { return(true); } // Create a new building record for this prefab and add it to our lists. BuildingData buildingData = new BuildingData { prefab = __instance, name = __instance.name, density = Loading.xmlManager.SetPrefabDensity(__instance), category = Loading.xmlManager.AssignCategory(__instance), }; Loading.xmlManager.prefabHash[__instance] = buildingData; // Add to broken prefabs list (will be removed later if it's not broken). Loading.brokenPrefabs.Add(__instance); // Search for PloppableRICODefinition.xml files with this asset. // Need to use FindAssetByName(string, AssetType) because FindAssetByName(string) doesn't catch all assets at this stage of initialisation // (those two methods are more different than you might think - discovered that the hard way). Package.Asset asset = PackageManager.FindAssetByName(__instance.name, Package.AssetType.Object); // Get custom asset filesystem location (if CRP pacakge). string crpPath = asset?.package?.packagePath; if (!string.IsNullOrEmpty(crpPath)) { // Look for RICO settings file. string ricoDefPath = Path.Combine(Path.GetDirectoryName(crpPath), "PloppableRICODefinition.xml"); if (File.Exists(ricoDefPath)) { // Parse the file. PloppableRICODefinition tempRicoDef = RICOReader.ParseRICODefinition(ricoDefPath); if (tempRicoDef != null) { foreach (RICOBuilding buildingDef in tempRicoDef.Buildings) { // Go through each building parsed and check to see if we've got a match for this prefab. if (MatchRICOName(buildingDef.Name, __instance.name, asset.package.packageName)) { // Match! Add these author settings to our prefab dictionary. Logging.Message("found author settings for ", buildingDef.Name); Loading.xmlManager.prefabHash[__instance].author = buildingDef; Loading.xmlManager.prefabHash[__instance].hasAuthor = true; } } } } } // Check for and add any local settings for this prefab to our list. if (Loading.localRicoDef != null) { // Step through our previously loaded local settings and see if we've got a match. foreach (RICOBuilding buildingDef in Loading.localRicoDef.Buildings) { if (buildingDef.Name.Equals(__instance.name)) { // Match! Add these author settings to our prefab dictionary. Loading.xmlManager.prefabHash[__instance].local = buildingDef; Loading.xmlManager.prefabHash[__instance].hasLocal = true; } } } // Check for any Workshop RICO mod settings for this prefab. if (Loading.mod1RicoDef != null) { // Step through our previously loaded local settings and see if we've got a match. foreach (RICOBuilding buildingDef in Loading.mod1RicoDef.Buildings) { if (buildingDef.Name.Equals(__instance.name)) { // Match! Add these author settings to our prefab dictionary. Loading.xmlManager.prefabHash[__instance].mod = buildingDef; Loading.xmlManager.prefabHash[__instance].hasMod = true; } } } // Check for Modern Japan CCP mod settings for this prefab. if (Loading.mod2RicoDef != null) { // Step through our previously loaded local settings and see if we've got a match. foreach (RICOBuilding buildingDef in Loading.mod2RicoDef.Buildings) { if (buildingDef.Name.Equals(__instance.name)) { // Match! Add these author settings to our prefab dictionary. Loading.xmlManager.prefabHash[__instance].mod = buildingDef; Loading.xmlManager.prefabHash[__instance].hasMod = true; } } } // Apply appropriate RICO settings to prefab. if (Loading.convertPrefabs != null) { // Start with local settings. if (Loading.xmlManager.prefabHash[__instance].hasLocal) { // If local settings disable RICO, dont convert. if (Loading.xmlManager.prefabHash[__instance].local.ricoEnabled) { Loading.convertPrefabs.ConvertPrefab(Loading.xmlManager.prefabHash[__instance].local, __instance); } } // If no local settings, apply author settings. else if (Loading.xmlManager.prefabHash[__instance].hasAuthor) { // If author settings disable RICO, dont convert. if (Loading.xmlManager.prefabHash[__instance].author.ricoEnabled) { Loading.convertPrefabs.ConvertPrefab(Loading.xmlManager.prefabHash[__instance].author, __instance); } } // If none of the above, apply mod settings. else if (Loading.xmlManager.prefabHash[__instance].hasMod) { // If mod settings disable RICO, dont convert. if (Loading.xmlManager.prefabHash[__instance].mod.ricoEnabled) { Loading.convertPrefabs.ConvertPrefab(Loading.xmlManager.prefabHash[__instance].mod, __instance); } } else { // No RICO settings; replicate game InitializePrefab checks overridden by transpiler. int privateServiceIndex = ItemClass.GetPrivateServiceIndex(__instance.m_class.m_service); if (privateServiceIndex != -1) { if (__instance.m_placementStyle == ItemClass.Placement.Manual) { throw new PrefabException(__instance, "Private building cannot have manual placement style"); } if (__instance.m_paths != null && __instance.m_paths.Length != 0) { throw new PrefabException(__instance, "Private building cannot include roads or other net types"); } } } } else { // This means that there's been a significant failure. Ploppable RICO settings can't be applied. Logging.Error("convertPrefabs not initialised"); } // Continue on to execute game InitializePrefab. return(true); }
/// <summary> /// Generates building thumbnail images (normal, focused, hovered, pressed and disabled) for the given building prefab. /// Thumbnails are no longer applied to the m_Thumbnail and m_Atlas fields of the prefab, but to the BuildingData record. /// </summary> /// <param name="prefab">The BuildingInfo prefab to generate thumbnails for</param> /// <param name="name">The display name of the prefab.</param> internal void CreateThumbnail(BuildingData building) { // Reset zoom. renderer.Zoom = 4f; // Don't do anything with null prefabs. if (building?.prefab == null) { return; } // Set mesh and material for render. if (!renderer.SetTarget(building.prefab)) { // Something went wrong - this isn't a valid rendering target; exit. Logging.Message("no thumbnail generated for null mesh ", building.prefab.name); return; } // If the selected building has colour variations, temporarily set the colour to the default for rendering. if (building.prefab.m_useColorVariations) { Color originalColor = building.prefab.m_material.color; building.prefab.m_material.color = building.prefab.m_color0; renderer.Render(true); building.prefab.m_material.color = originalColor; } else { // No temporary colour change needed. renderer.Render(true); } // Back up game's current active texture. RenderTexture gameActiveTexture = RenderTexture.active; // Convert the render to a 2D texture. Texture2D thumbnailTexture = new Texture2D(renderer.Texture.width, renderer.Texture.height); RenderTexture.active = renderer.Texture; thumbnailTexture.ReadPixels(new Rect(0f, 0f, (float)renderer.Texture.width, (float)renderer.Texture.height), 0, 0); thumbnailTexture.Apply(); // Temporary texture for resizing render to thumbnail size (109 x 100). RenderTexture resizingTexture = RenderTexture.GetTemporary(109, 100); // Resize 2D texture (to 109 x 100) using trilinear filtering. resizingTexture.filterMode = FilterMode.Trilinear; thumbnailTexture.filterMode = FilterMode.Trilinear; // Resize. Graphics.Blit(thumbnailTexture, resizingTexture); thumbnailTexture.Resize(109, 100); thumbnailTexture.ReadPixels(new Rect(0, 0, 109, 100), 0, 0); thumbnailTexture.Apply(); // Release temporary texture. RenderTexture.ReleaseTemporary(resizingTexture); // Restore game's current active texture. RenderTexture.active = gameActiveTexture; // Thumbnail texture name is the same as the building's displayed name. thumbnailTexture.name = building.DisplayName; // Create new texture atlas with thumnails. UITextureAtlas thumbnailAtlas = ScriptableObject.CreateInstance <UITextureAtlas>(); thumbnailAtlas.name = "RICOThumbnails_" + building.DisplayName; thumbnailAtlas.material = UnityEngine.Object.Instantiate <Material>(UIView.GetAView().defaultAtlas.material); thumbnailAtlas.material.mainTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false); AddTexturesToAtlas(thumbnailAtlas, GenerateThumbnailVariants(thumbnailTexture)); // Add atlas to our building data record. building.thumbnailAtlas = thumbnailAtlas; }
/// <summary> /// Generates and displays a building row. /// </summary> /// <param name="data">Object to list</param> /// <param name="isRowOdd">If the row is an odd-numbered row (for background banding)</param> public void Display(object data, bool isRowOdd) { // Perform initial setup for new rows. if (buildingName == null) { isVisible = true; canFocus = true; isInteractive = true; width = parent.width; height = 40; buildingName = AddUIComponent <UILabel>(); buildingName.width = 200; // Checkboxes to indicate which items have custom settings. hasModSettings = AddUIComponent <UISprite>(); hasModSettings.size = new Vector2(20, 20); hasModSettings.relativePosition = new Vector3(340, 10); hasModSettings.tooltip = Translations.Translate("PRR_SET_HASMOD"); hasAuthorSettings = AddUIComponent <UISprite>(); hasAuthorSettings.size = new Vector2(20, 20); hasAuthorSettings.relativePosition = new Vector3(340, 10); hasAuthorSettings.tooltip = Translations.Translate("PRR_SET_HASAUT"); hasLocalSettings = AddUIComponent <UISprite>(); hasLocalSettings.size = new Vector2(20, 20); hasLocalSettings.relativePosition = new Vector3(340, 10); hasLocalSettings.tooltip = Translations.Translate("PRR_SET_HASLOC"); } // Set selected building. buildingData = data as BuildingData; buildingName.text = buildingData.displayName; // Update custom settings checkboxes to correct state. if (buildingData.hasMod) { // Mod settings found. hasModSettings.spriteName = "AchievementCheckedTrue"; } else { // No mod settings. hasModSettings.spriteName = "AchievementCheckedFalse"; } if (buildingData.hasAuthor) { // Author settings found. hasAuthorSettings.spriteName = "AchievementCheckedTrue"; } else { // No mod settings. hasAuthorSettings.spriteName = "AchievementCheckedFalse"; } if (buildingData.hasLocal) { // Local settings found. hasLocalSettings.spriteName = "AchievementCheckedTrue"; } else { // No mod settings. hasLocalSettings.spriteName = "AchievementCheckedFalse"; } // Set initial background as deselected state. Deselect(isRowOdd); }
/// <summary> /// Updates the options panel when the building selection changes, including showing/hiding relevant controls. /// </summary> /// <param name="buildingData">RICO building data</param> internal void SelectionChanged(BuildingData buildingData) { // Disable the event logic while dropdowns are being updated. disableEvents = true; // Disable all input controls by default; activate them later if needed. ricoEnabled.Disable(); growable.Disable(); growable.parent.Hide(); service.Disable(); subService.Disable(); level.Disable(); uiCategory.Disable(); construction.Disable(); manual.Disable(); realityIgnored.Disable(); uneducated.Disable(); educated.Disable(); welleducated.Disable(); highlyeducated.Disable(); // Update option UI elements, in priority order (local, author, mod). if (buildingData.hasLocal) { currentSelection = buildingData.local; UpdateElements(buildingData.local.service); UpdateValues(buildingData.local); label.text = Translations.Translate("PRR_SET_HASLOC"); // If the building has local settings, enable input fields. ricoEnabled.Enable(); service.Enable(); subService.Enable(); level.Enable(); uiCategory.Enable(); construction.Enable(); manual.Enable(); realityIgnored.Enable(); uneducated.Enable(); educated.Enable(); welleducated.Enable(); highlyeducated.Enable(); // 'Growable' can only be set in local settings. // Only show growable checkbox where assets meet the prequisites: // Growables can't have any dimension greater than 4 or contain any net structures. if (buildingData.prefab.GetWidth() <= 4 && buildingData.prefab.GetLength() <= 4 && !(buildingData.prefab.m_paths != null && buildingData.prefab.m_paths.Length != 0)) { growable.Enable(); growable.parent.Show(); } } else if (buildingData.hasAuthor) { // If the building has author settings, then disable input fields. currentSelection = buildingData.author; UpdateElements(buildingData.author.service); UpdateValues(buildingData.author); label.text = Translations.Translate("PRR_SET_HASAUT"); } else if (buildingData.hasMod) { // If the building has mod settings, then disable input fields. currentSelection = buildingData.mod; label.text = Translations.Translate("PRR_SET_HASMOD"); UpdateElements(buildingData.mod.service); UpdateValues(buildingData.mod); } else { // Fallback - building has no Ploppable RICO data anywhere, disable Ploppable RICO. ricoEnabled.isChecked = false; ricoEnabled.Disable(); label.text = Translations.Translate("PRR_SET_HASNON"); } // Re-enable event logic now that dropdowns are up-to-date before returning. disableEvents = false; }
public void SelectionChanged(BuildingData buildingData) { currentSelection = buildingData; }
/// <summary> /// Generates a button for each ploppable building in the relevant panel as determined by UI category. /// </summary> /// <param name="buildingData">RICO building to add</param> /// <param name="uiCategory">UI category</param> internal void AddBuildingButton(BuildingData buildingData, string uiCategory) { // Set UI category index for this buildingData instance. buildingData.uiCategory = UICategoryIndex(uiCategory); // Don't do anything if UI category is set to 'none'. if (uiCategory.Equals("none")) { return; } try { // Add building button to relevant panel. buildingData.buildingButton = new UIButton(); buildingData.buildingButton = BuildingPanels[buildingData.uiCategory].AddUIComponent <UIButton>(); // Appearance. buildingData.buildingButton.size = new Vector2(109, 100); buildingData.buildingButton.horizontalAlignment = UIHorizontalAlignment.Center; buildingData.buildingButton.verticalAlignment = UIVerticalAlignment.Middle; buildingData.buildingButton.pivot = UIPivotPoint.TopCenter; // Assign prefab. buildingData.buildingButton.objectUserData = buildingData.prefab; // Thumbnail. Thumbnails.CreateThumbnail(buildingData); // Information label - building name. UILabel nameLabel = new UILabel(); nameLabel = buildingData.buildingButton.AddUIComponent <UILabel>(); nameLabel.textScale = 0.6f; nameLabel.useDropShadow = true; nameLabel.dropShadowColor = new Color32(80, 80, 80, 255); nameLabel.dropShadowOffset = new Vector2(2, -2); nameLabel.text = buildingData.displayName; nameLabel.autoSize = false; nameLabel.autoHeight = true; nameLabel.wordWrap = true; nameLabel.width = buildingData.buildingButton.width - 10; nameLabel.isVisible = true; nameLabel.relativePosition = new Vector3(5, 5); // Information label - building level. UILabel levelLabel = new UILabel(); levelLabel = buildingData.buildingButton.AddUIComponent <UILabel>(); levelLabel.textScale = 0.6f; levelLabel.useDropShadow = true; levelLabel.dropShadowColor = new Color32(80, 80, 80, 255); levelLabel.dropShadowOffset = new Vector2(2, -2); levelLabel.text = Translations.Translate("PRR_LVL") + " " + ((int)buildingData.prefab.m_class.m_level + 1); levelLabel.autoSize = true; levelLabel.isVisible = true; levelLabel.relativePosition = new Vector3(5, buildingData.buildingButton.height - levelLabel.height - 5); // Information label - building size. UILabel sizeLabel = new UILabel(); sizeLabel = buildingData.buildingButton.AddUIComponent <UILabel>(); sizeLabel.textScale = 0.6f; sizeLabel.useDropShadow = true; sizeLabel.dropShadowColor = new Color32(80, 80, 80, 255); sizeLabel.dropShadowOffset = new Vector2(2, -2); sizeLabel.text = buildingData.prefab.GetWidth() + "x" + buildingData.prefab.GetLength(); sizeLabel.autoSize = true; sizeLabel.isVisible = true; sizeLabel.relativePosition = new Vector3(buildingData.buildingButton.width - sizeLabel.width - 5, buildingData.buildingButton.height - sizeLabel.height - 5); // Tooltip. buildingData.buildingButton.tooltipAnchor = UITooltipAnchor.Anchored; buildingData.buildingButton.tooltip = BuildingTooltip(buildingData); buildingData.buildingButton.eventClick += (component, clickEvent) => BuildingBClicked(buildingData.prefab); buildingData.buildingButton.eventMouseHover += (component, mouseEvent) => { // Reset the tooltip before showing each time, as sometimes it gets clobbered either by the game or another mod. component.tooltip = BuildingTooltip(buildingData); }; // Ready to use! buildingData.buildingButton.isEnabled = true; } catch (Exception e) { Debugging.Message("BuildingButton creation exception with UI category '" + uiCategory); Debug.LogException(e); } }
public void SelectionChanged(BuildingData buildingData) { //When dropdowns are updated, this disables the event logic disableEvents = true; ricoEnabled.Enable(); service.Enable(); subService.Enable(); level.Enable(); uiCategory.Enable(); construction.Enable(); manual.Enable(); popBalanceEnabled.Enable(); //If selected asset has local settings, update option UI elements with those settings. if (buildingData.hasLocal) { currentSelection = buildingData.local; UpdateElements(buildingData.local.service); UpdateValues(buildingData.local); label.text = "Local Settings"; disableEvents = false; return; } else if (buildingData.hasAuthor) { currentSelection = buildingData.author; UpdateElements(buildingData.author.service); UpdateValues(buildingData.author); label.text = "Author Settings"; ricoEnabled.Disable(); service.Disable(); subService.Disable(); level.Disable(); uiCategory.Disable(); construction.Disable(); manual.Disable(); popBalanceEnabled.Disable(); disableEvents = false; return; } else if (buildingData.hasMod) { currentSelection = buildingData.mod; label.text = "Mod Settings"; UpdateElements(buildingData.mod.service); UpdateValues(buildingData.mod); ricoEnabled.Disable(); service.Disable(); subService.Disable(); level.Disable(); uiCategory.Disable(); construction.Disable(); manual.Disable(); popBalanceEnabled.Disable(); disableEvents = false; return; } else { ricoEnabled.isChecked = false; ricoEnabled.Disable(); label.text = "No Settings"; } disableEvents = false; }
/// <summary> /// Generates building thumbnail images (normal, focused, hovered, pressed and disabled) for the given building prefab. /// Thumbnails are applied to the m_Thumbnail and m_Atlas fields of the prefab. /// </summary> /// <param name="prefab">The BuildingInfo prefab to generate thumbnails for</param> /// <param name="name">The display name of the prefab.</param> internal static void CreateThumbnail(BuildingData building) { // Create the renderer if it hasn't already been set up. if (thumbnailRenderer == null) { // Use a unique GameObject name to help find it with ModTools. thumbnailRenderer = new GameObject("RICORevisitedThumbnailRenderer").AddComponent <UIPreviewRenderer>(); // Size and setting for thumbnail images: 109 x 100, doubled for anti-aliasing. thumbnailRenderer.Size = new Vector2(109, 100) * 2f; thumbnailRenderer.CameraRotation = 210f; } // Reset zoom. thumbnailRenderer.Zoom = 4f; // Don't do anything with null prefabs or prefabs without buttons. if (building == null || building.buildingButton == null) { return; } // Set mesh and material for render. thumbnailRenderer.SetTarget(building.prefab); if (thumbnailRenderer.Mesh == null) { // If the prefab itself has no mesh, see if there's any sub-buildings to render instead (e.g. Boston Residence Garage). if (building.prefab.m_subBuildings.Count() > 0) { // Use first sub-building as render target; set mesh and material. thumbnailRenderer.Mesh = building.prefab.m_subBuildings[0].m_buildingInfo.m_mesh; thumbnailRenderer.material = building.prefab.m_subBuildings[0].m_buildingInfo.m_material; } } // If we still haven't gotten a mesh after the above, then something's not right; exit. if (thumbnailRenderer.Mesh == null) { Debugging.Message("no thumbnail generated for null mesh " + building.prefab.name); return; } // If the selected building has colour variations, temporarily set the colour to the default for rendering. if (building.prefab.m_useColorVariations) { Color originalColor = building.prefab.m_material.color; building.prefab.m_material.color = building.prefab.m_color0; thumbnailRenderer.Render(true); building.prefab.m_material.color = originalColor; } else { // No temporary colour change needed. thumbnailRenderer.Render(true); } // Back up game's current active texture. RenderTexture gameActiveTexture = RenderTexture.active; // Convert the render to a 2D texture. Texture2D thumbnailTexture = new Texture2D(thumbnailRenderer.Texture.width, thumbnailRenderer.Texture.height); RenderTexture.active = thumbnailRenderer.Texture; thumbnailTexture.ReadPixels(new Rect(0f, 0f, (float)thumbnailRenderer.Texture.width, (float)thumbnailRenderer.Texture.height), 0, 0); thumbnailTexture.Apply(); // Temporary texture for resizing render to thumbnail size (109 x 100). RenderTexture resizingTexture = RenderTexture.GetTemporary(109, 100); // Resize 2D texture (to 109 x 100) using trilinear filtering. resizingTexture.filterMode = FilterMode.Trilinear; thumbnailTexture.filterMode = FilterMode.Trilinear; // Resize. Graphics.Blit(thumbnailTexture, resizingTexture); thumbnailTexture.Resize(109, 100); thumbnailTexture.ReadPixels(new Rect(0, 0, 109, 100), 0, 0); thumbnailTexture.Apply(); // Release temporary texture. RenderTexture.ReleaseTemporary(resizingTexture); // Restore game's current active texture. RenderTexture.active = gameActiveTexture; // Thumbnail texture name is the same as the building's displayed name. thumbnailTexture.name = building.displayName; // Create new texture atlas with thumnails. UITextureAtlas thumbnailAtlas = ScriptableObject.CreateInstance <UITextureAtlas>(); thumbnailAtlas.name = "RICOThumbnails_" + building.displayName; thumbnailAtlas.material = UnityEngine.Object.Instantiate <Material>(UIView.GetAView().defaultAtlas.material); thumbnailAtlas.material.mainTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false); AddTexturesToAtlas(thumbnailAtlas, GenerateThumbnailVariants(thumbnailTexture)); // Add atlas to building button. building.buildingButton.atlas = thumbnailAtlas; building.buildingButton.normalFgSprite = thumbnailTexture.name; // Variants. building.buildingButton.focusedFgSprite = thumbnailTexture.name + "Focused"; building.buildingButton.hoveredFgSprite = thumbnailTexture.name + "Hovered"; building.buildingButton.pressedFgSprite = thumbnailTexture.name + "Pressed"; building.buildingButton.disabledFgSprite = thumbnailTexture.name + "Disabled"; }