Skip to content

Instantly share code, notes, and snippets.

@boformer
Last active April 3, 2020 14:00
Show Gist options
  • Save boformer/3a46518ec3fe224f4def to your computer and use it in GitHub Desktop.
Save boformer/3a46518ec3fe224f4def to your computer and use it in GitHub Desktop.
Cities: Skylines - Street Light Replacer Mod
using ICities;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
using UnityEngine;
using PrefabHook;
using ColossalFramework.UI;
using ColossalFramework.Plugins;
namespace StreetLightReplacer
{
public class StreetLightReplacerMod : LoadingExtensionBase, IUserMod
{
private const string configPath = "StreetLightReplacer.xml";
private StreetLightReplacerConfig _config;
public StreetLightReplacerConfig Config
{
get
{
if (_config == null)
{
_config = StreetLightReplacerConfig.Deserialize("StreetLightReplacer.xml");
if (_config == null)
{
_config = new StreetLightReplacerConfig();
_config.SetReplacement("Basic Road", "StreetLamp02");
_config.SetReplacement("Highway", "#None");
_config.SetReplacement("Highway Elevated", "#None");
_config.SetReplacement("HighwayRamp", "#None");
_config.SetReplacement("HighwayRampElevated", "#None");
_config.RemoveHighwaySuspensionBridgeLights = true;
}
}
return _config;
}
}
public string Name
{
get { return "Street Light Replacer"; }
}
public string Description
{
get { return "Requires the Prefab Hook mod"; }
}
// Note: There are better ways to solve this
public void OnSettingsUI(UIHelperBase group)
{
group.AddGroup("Note: Restart the game to apply the new options!");
group.AddDropdown("Two-Lane Road", new string[] { "Street Light (Default)", "Street Lamp", "None" },
Config.GetReplacement("Basic Road") == null ? 0 : (Config.GetReplacement("Basic Road").StreetLight == "#None" ? 2 : 1),
delegate(int sel)
{
switch (sel)
{
case 0:
Config.DeleteReplacement("Basic Road");
break;
case 1:
Config.SetReplacement("Basic Road", "StreetLamp02");
break;
case 2:
Config.SetReplacement("Basic Road", "#None");
break;
}
StreetLightReplacerConfig.Serialize(configPath, Config);
});
group.AddDropdown("Highway", new string[] { "Street Light (Default)", "None" },
Config.GetReplacement("Highway") == null ? 0 : 1,
delegate(int sel)
{
switch (sel)
{
case 0:
Config.DeleteReplacement("Highway");
Config.DeleteReplacement("Highway Elevated");
break;
case 1:
Config.SetReplacement("Highway", "#None");
Config.SetReplacement("Highway Elevated", "#None");
break;
}
StreetLightReplacerConfig.Serialize(configPath, Config);
});
group.AddDropdown("Highway Ramp", new string[] { "Street Light (Default)", "None" },
Config.GetReplacement("HighwayRamp") == null ? 0 : 1,
delegate(int sel)
{
switch (sel)
{
case 0:
Config.DeleteReplacement("HighwayRamp");
Config.DeleteReplacement("HighwayRampElevated");
break;
case 1:
Config.SetReplacement("HighwayRamp", "#None");
Config.SetReplacement("HighwayRampElevated", "#None");
break;
}
StreetLightReplacerConfig.Serialize(configPath, Config);
});
group.AddCheckbox("Remove lights from highway suspension bridge", Config.RemoveHighwaySuspensionBridgeLights, delegate(bool check)
{
Config.RemoveHighwaySuspensionBridgeLights = check;
StreetLightReplacerConfig.Serialize(configPath, Config);
});
}
public override void OnCreated(ILoading loading)
{
base.OnCreated(loading);
// cancel if Prefab Hook is not installed
if (!IsHooked()) return;
// register event handlers
NetInfoHook.OnPreInitialization += OnPreNetInit;
NetInfoHook.Deploy();
if (Config.RemoveHighwaySuspensionBridgeLights)
{
BuildingInfoHook.OnPreInitialization += OnPreBuildingInit;
BuildingInfoHook.Deploy();
}
}
public void OnPreNetInit(NetInfo prefab)
{
if (prefab == null || prefab.m_lanes == null) return;
var replacement = Config.GetReplacement(prefab.name);
if (replacement == null) return;
foreach (var lane in prefab.m_lanes)
{
if (lane == null || lane.m_laneProps == null || lane.m_laneProps.m_props == null) continue;
foreach (var prop in lane.m_laneProps.m_props)
{
if (prop.m_prop != null && (prop.m_prop.name.Contains("Street Light") || prop.m_prop.name.Contains("StreetLamp")))
{
if(replacement != null) Debug.Log("Replace street light " + prefab.name + ": " + replacement.StreetLight);
if (replacement.StreetLight == "#None")
{
prop.m_prop = null;
prop.m_finalProp = null;
}
else
{
PropInfo lightProp = PrefabCollection<PropInfo>.FindLoaded(replacement.StreetLight);
if (lightProp == null)
{
foreach (var col in GameObject.FindObjectsOfType<PropCollection>())
{
if (col == null || col.m_prefabs == null) continue;
foreach (var prop2 in col.m_prefabs)
{
if (prop2 != null && prop2.name == replacement.StreetLight)
{
lightProp = prop2;
break;
}
}
}
}
if (lightProp != null)
{
prop.m_prop = lightProp;
prop.m_finalProp = lightProp;
}
else
{
Debug.Log("Prop " + replacement.StreetLight + " not found!");
}
}
}
}
}
}
//HighwayBridgeSuspensionPillar
// Flood Light Down White
// Flood Light Blue
public void OnPreBuildingInit(BuildingInfo prefab)
{
if (prefab == null || prefab.m_props == null) return;
if (prefab.name != "HighwayBridgeSuspensionPillar") return;
foreach (var prop in prefab.m_props)
{
if (prop.m_prop != null && prop.m_prop.name.Contains("Flood Light"))
{
prop.m_prop = null;
prop.m_finalProp = null;
}
}
}
public override void OnLevelLoaded(LoadMode mode)
{
base.OnLevelLoaded(mode);
// display warning when level is loaded if Prefab Hook is not installed
if (!IsHooked())
{
UIView.library.ShowModal<ExceptionPanel>("ExceptionPanel").SetMessage(
"Missing dependency",
"Street Light Replacer requires the 'Prefab Hook' mod to work properly. Please subscribe to the mod and restart the game!",
false);
return;
}
}
public override void OnReleased()
{
base.OnReleased();
if (!IsHooked()) return;
// revert on release
NetInfoHook.Revert();
BuildingInfoHook.Revert();
}
// checks if the player subscribed to the Prefab Hook mod
private bool IsHooked()
{
foreach (PluginManager.PluginInfo current in PluginManager.instance.GetPluginsInfo())
{
if (current.publishedFileID.AsUInt64 == 530771650uL) return true;
}
return false;
}
}
public class StreetLightReplacerConfig
{
public Boolean RemoveHighwaySuspensionBridgeLights { get; set; }
public List<Replacement> Replacements {get; private set;}
public StreetLightReplacerConfig()
{
Replacements = new List<Replacement>();
}
public class Replacement
{
public string NetInfo { get; set; }
public string StreetLight { get; set; }
}
public Replacement GetReplacement(string netInfo)
{
foreach (var r in Replacements)
{
if (r.NetInfo == netInfo)
{
return r;
}
}
return null;
}
public void SetReplacement(string netInfo, string streetLight)
{
foreach (var r in Replacements)
{
if (r.NetInfo == netInfo)
{
r.StreetLight = streetLight;
return;
}
}
Replacements.Add(new Replacement { NetInfo = netInfo, StreetLight = streetLight });
}
public void DeleteReplacement(string netInfo)
{
foreach (var r in Replacements)
{
if (r.NetInfo == netInfo)
{
Replacements.Remove(r);
return;
}
}
}
public static StreetLightReplacerConfig Deserialize(string filename)
{
if (!File.Exists(filename)) return null;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(StreetLightReplacerConfig));
try
{
using (System.IO.StreamReader streamReader = new System.IO.StreamReader(filename))
{
return (StreetLightReplacerConfig)xmlSerializer.Deserialize(streamReader);
}
}
catch (Exception e)
{
Debug.Log("Couldn't load configuration (XML malformed?)");
throw e;
}
}
public static void Serialize(string filename, StreetLightReplacerConfig config)
{
var xmlSerializer = new XmlSerializer(typeof(StreetLightReplacerConfig));
try
{
using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(filename))
{
xmlSerializer.Serialize(streamWriter, config);
}
}
catch (Exception e)
{
Debug.Log("Couldn't create configuration file at \"" + Directory.GetCurrentDirectory() + "\"");
throw e;
}
}
}
}
@mjm92150
Copy link

mjm92150 commented Apr 3, 2020

Hello,
I would like to get in French language in the full game, even in game option before to start a a new game.
Is it possible for me to translate ? I do not know where is the xml file for translating or should I translate this file where all the sentences are in " " ?
Thanks for your reply.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment