public static void Message(string text) { if (VehicleMod.settings.debug.debugLogging) { SmashLog.Message(text); } }
static VehicleHarmony() { //harmony.PatchAll(Assembly.GetExecutingAssembly()); //Harmony.DEBUG = true; Log.Message($"{LogLabel} version {Assembly.GetExecutingAssembly().GetName().Version}"); IEnumerable <Type> patchCategories = GenTypes.AllTypes.Where(t => t.GetInterfaces().Contains(typeof(IPatchCategory))); foreach (Type patchCategory in patchCategories) { IPatchCategory patch = (IPatchCategory)Activator.CreateInstance(patchCategory, null); try { patch.PatchMethods(); } catch (Exception ex) { SmashLog.Error($"Failed to Patch <type>{patch.GetType().FullName}</type>. Method=\"{methodPatching}\""); throw ex; } } SmashLog.Message($"{LogLabel} <success>{Harmony.GetPatchedMethods().Count()} patches successfully applied.</success>"); ResolveAllReferences(); //Will want to be added via xml FillVehicleLordJobTypes(); LoadedModManager.GetMod <VehicleMod>().InitializeTabs(); VehicleMod.settings.Write(); }
public static void Error(string text) { if (VehicleMod.settings.debug.debugLogging) { SmashLog.Error(text); } }
public static void Warning(string text) { if (VehicleMod.settings.debug.debugLogging) { SmashLog.Warning(text); } }
public void InitializeUpgradeTree() { upgradeList = new List <UpgradeNode>(); foreach (UpgradeNode node in Props.upgrades) { try { UpgradeNode permanentNode = (UpgradeNode)Activator.CreateInstance(node.GetType(), new object[] { node, Vehicle }); permanentNode.OnInit(); upgradeList.Add(permanentNode); } catch (Exception ex) { SmashLog.Error($"Exception thrown while generating <text>{node.upgradeID}</text> of type <type>{node.GetType()}</type> for {Vehicle.LabelShort}\nException=\"{ex}\""); upgradeList.Add(UpgradeNode.BlankUpgrade(node, Vehicle)); } } if (upgradeList.Select(x => x.upgradeID).GroupBy(y => y).Where(y => y.Count() > 1).Select(z => z.Key).NotNullAndAny()) { Log.Error(string.Format("Duplicate UpgradeID's detected on def {0}. This is not supported.", parent.def.defName)); Debug.Message("====== Duplicate UpgradeID's for this Vehicle ======"); foreach (UpgradeNode errorNode in upgradeList.GroupBy(grp => grp).Where(g => g.Count() > 1)) { Debug.Message($"UpgradeID: {errorNode.upgradeID} UniqueID: {errorNode.GetUniqueLoadID()} Location: {errorNode.gridCoordinate}"); } Debug.Message("==========================================="); } }
private static void CheckFieldLocked(XmlNode node, string value, FieldInfo field) { if (value.ToUpperInvariant() == "TRUE") { XmlNode defNode = node.SelectSingleNode("defName"); while (defNode is null) { XmlNode parentNode = node.ParentNode; if (parentNode is null) { Log.Error($"Cannot use LockSetting attribute on {field.Name} since it is not nested within a Def."); return; } defNode = parentNode.SelectSingleNode("defName"); } string defName = defNode.InnerText; if (!field.HasAttribute <PostToSettingsAttribute>()) { SmashLog.Error($"Cannont use LockSetting attribute on <field>{field.Name}</field> since related field does not have PostToSettings attribute in <type>{field.DeclaringType}</type>"); } if (!lockedFields.ContainsKey(defName)) { lockedFields.Add(defName, new HashSet <FieldInfo>()); } lockedFields[defName].Add(field); } }
public static void DrawAltitudeMeter(AerialVehicleInFlight aerialVehicle) { try { Rect rect = new Rect(AltitudeScreenPos, MeterSize); Rect windowRect = new Rect(rect) { width = rect.width * 3 + 10, height = WindowHeight + InfoWindoHeight }; float elevation = (MeterSize.y - (aerialVehicle.Elevation / MaximumAltitude * MeterSize.y)).Clamp(MaxAltitudeScreenHeight, MeterSize.y - MinAltitudeScreenHeight); Find.WindowStack.ImmediateWindow(aerialVehicle.GetHashCode(), windowRect, WindowLayer.GameUI, delegate() { var anchor = Text.Anchor; var font = Text.Font; var color = GUI.color; Rect viewRect = rect.AtZero(); windowRect.x = rect.width + 5; windowRect.y = 5; windowRect.height = WindowHeight; GUI.BeginScrollView(windowRect, new Vector2(windowRect.x, elevation - WindowHeight / 2), viewRect, GUIStyle.none, GUIStyle.none); GUI.DrawTexture(viewRect, VehicleTex.AltitudeMeter); if (elevation <= MaximumAltitude) { Rect lineRect = new Rect(0, windowRect.y + elevation, viewRect.width, 1f); GUI.DrawTexture(lineRect, elevation >= MeterSize.y / 2 ? BaseContent.BlackTex : BaseContent.WhiteTex); } GUI.color = WindowBGBorderColor; Widgets.DrawLineHorizontal(0, windowRect.y + elevation + MeterSize.y / 2, viewRect.width); Widgets.DrawLineVertical(viewRect.width, windowRect.y, MeterSize.y); GUI.color = color; Text.Font = GameFont.Small; float textHeight = Text.CalcHeight(aerialVehicle.Elevation.ToString(), viewRect.width); Rect labelRect = new Rect(viewRect.width + 5, windowRect.y + elevation - textHeight / 2, viewRect.width - 5, textHeight); Widgets.DrawMenuSection(labelRect); Text.Font = GameFont.Tiny; Text.Anchor = TextAnchor.MiddleCenter; int elevationRounded = Mathf.RoundToInt(aerialVehicle.Elevation); GUI.Label(labelRect, elevationRounded.ToString(), Text.CurFontStyle); GUI.EndScrollView(false); Text.Anchor = anchor; Text.Font = font; GUI.color = color; }, true, false, 0); } catch (Exception ex) { SmashLog.Error($"Exception thrown while trying to draw <type>AltitudeMeter</type> for {aerialVehicle?.Label ?? "NULL"}. Exception=\"{ex.Message}\""); } }
public void RecacheTextures() { patterns = new Texture2D[Graphic_RGB.MatCount]; patterns[0] = ContentFinder<Texture2D>.Get(path, false); patterns[0] ??= ContentFinder<Texture2D>.Get(path + "_north", false); if (patterns[0] is null) { SmashLog.Error($"Unable to find Texture2D for <field>path</field> at {path}."); return; } if (IsDefault) { patterns[1] = patterns[0]; patterns[2] = patterns[0]; patterns[3] = patterns[0]; patterns[4] = patterns[0]; patterns[5] = patterns[0]; patterns[6] = patterns[0]; patterns[7] = patterns[0]; return; } patterns[1] = ContentFinder<Texture2D>.Get(path + "_east", false); patterns[2] = ContentFinder<Texture2D>.Get(path + "_south", false); patterns[3] = ContentFinder<Texture2D>.Get(path + "_west", false); patterns[4] = ContentFinder<Texture2D>.Get(path + "_northEast", false); patterns[5] = ContentFinder<Texture2D>.Get(path + "_southEast", false); patterns[6] = ContentFinder<Texture2D>.Get(path + "_southWest", false); patterns[7] = ContentFinder<Texture2D>.Get(path + "_northWest", false); if (patterns[1] is null) { patterns[1] = patterns[0].Rotate(270); } if (patterns[2] is null) { patterns[2] = patterns[0].Rotate(180); } if (patterns[3] is null) { patterns[3] = patterns[0].Rotate(90); } if (patterns[4] is null) { patterns[4] = patterns[0]; } if (patterns[5] is null) { patterns[5] = patterns[2]; } if (patterns[6] is null) { patterns[6] = patterns[2]; } if (patterns[7] is null) { patterns[7] = patterns[2]; } }
public virtual void InitTurretMotes(Vector3 loc, float angle) { if (!VerbProps.motes.NullOrEmpty()) { foreach (AnimationProperties moteProps in VerbProps.motes) { Vector3 moteLoc = loc; if (loc.ShouldSpawnMotesAt(caster.Map)) { try { float altitudeLayer = Altitudes.AltitudeFor(moteProps.moteDef.altitudeLayer); moteLoc += new Vector3(VerbProps.shootOffset.x + moteProps.offset.x, altitudeLayer + moteProps.offset.y, VerbProps.shootOffset.y + moteProps.offset.z).RotatedBy(angle); Mote mote = (Mote)ThingMaker.MakeThing(moteProps.moteDef); mote.exactPosition = moteLoc; mote.exactRotation = moteProps.exactRotation.RandomInRange; mote.instanceColor = moteProps.color; mote.rotationRate = moteProps.rotationRate; mote.Scale = moteProps.scale; if (mote is MoteThrown thrownMote) { float thrownAngle = angle + moteProps.angleThrown.RandomInRange; thrownMote.SetVelocity(thrownAngle, moteProps.speedThrown.RandomInRange); if (thrownMote is MoteThrownExpand expandMote) { if (expandMote is MoteThrownSlowToSpeed accelMote) { accelMote.SetDecelerationRate(moteProps.deceleration.RandomInRange, moteProps.fixedAcceleration, thrownAngle); } expandMote.growthRate = moteProps.growthRate.RandomInRange; } } if (mote is Mote_CannonPlume cannonMote) { cannonMote.cyclesLeft = moteProps.cycles; cannonMote.animationType = moteProps.animationType; cannonMote.angle = angle; } mote.def = moteProps.moteDef; mote.PostMake(); GenSpawn.Spawn(mote, moteLoc.ToIntVec3(), caster.Map, WipeMode.Vanish); } catch (Exception ex) { SmashLog.Error($"Failed to spawn mote at {loc}. MoteDef = <field>{moteProps.moteDef?.defName ?? "Null"}</field> Exception = {ex.Message}"); } } } } }
/// <summary> /// Explode projectile on water with modified effects /// </summary> /// <param name="proj"></param> public static void Explode(Projectile proj) { Map map = proj.Map; proj.Destroy(DestroyMode.Vanish); if (proj.def.projectile.explosionEffect != null) { Effecter effecter = proj.def.projectile.explosionEffect.Spawn(); effecter.Trigger(new TargetInfo(proj.Position, map, false), new TargetInfo(proj.Position, map, false)); effecter.Cleanup(); } IntVec3 position = proj.Position; Map map2 = map; int waterDepth = map.terrainGrid.TerrainAt(proj.Position).IsWater ? map.terrainGrid.TerrainAt(proj.Position) == TerrainDefOf.WaterOceanShallow || map.terrainGrid.TerrainAt(proj.Position) == TerrainDefOf.WaterShallow || map.terrainGrid.TerrainAt(proj.Position) == TerrainDefOf.WaterMovingShallow ? 1 : 2 : 0; if (waterDepth == 0) { SmashLog.Error("<field>waterDepth</field> is 0, but terrain is water."); } float explosionRadius = (proj.def.projectile.explosionRadius / (2f * waterDepth)); if (explosionRadius < 1) { explosionRadius = 1f; } DamageDef damageDef = proj.def.projectile.damageDef; Thing launcher = null; int damageAmount = proj.DamageAmount; float armorPenetration = proj.ArmorPenetration; SoundDef soundExplode; soundExplode = SoundDefOf_Ships.Explode_BombWater; //Changed for current issues SoundStarter.PlayOneShot(soundExplode, new TargetInfo(proj.Position, map, false)); ThingDef equipmentDef = null; ThingDef def = proj.def; Thing thing = null; ThingDef postExplosionSpawnThingDef = proj.def.projectile.postExplosionSpawnThingDef; float postExplosionSpawnChance = 0.0f; float chanceToStartFire = proj.def.projectile.explosionChanceToStartFire * 0.0f; int postExplosionSpawnThingCount = proj.def.projectile.postExplosionSpawnThingCount; ThingDef preExplosionSpawnThingDef = proj.def.projectile.preExplosionSpawnThingDef; GenExplosion.DoExplosion(position, map2, explosionRadius, damageDef, launcher, damageAmount, armorPenetration, soundExplode, equipmentDef, def, thing, postExplosionSpawnThingDef, postExplosionSpawnChance, postExplosionSpawnThingCount, proj.def.projectile.applyDamageToExplosionCellsNeighbors, preExplosionSpawnThingDef, proj.def.projectile.preExplosionSpawnChance, proj.def.projectile.preExplosionSpawnThingCount, chanceToStartFire, proj.def.projectile.explosionDamageFalloff); }
protected override bool TryCastShot() { if (base.TryCastShot()) { if (caster is Building_RecoiledTurret turret) { turret.Notify_Recoiled(); } else { SmashLog.Error($"Unable to produce recoil to {caster.Label} of type <type>{caster.GetType()}</type>. Type should be <type>Building_RecoiledTurret</type>"); } return(true); } return(false); }
public static VehicleJobLimitations FromString(string entry) { entry = entry.TrimStart(new char[] { '(' }).TrimEnd(new char[] { ')' }); string[] data = entry.Split(new char[] { ',' }); try { CultureInfo invariantCulture = CultureInfo.InvariantCulture; string defName = Convert.ToString(data[0], invariantCulture); int workers = Convert.ToInt32(data[1], invariantCulture); return(new VehicleJobLimitations(defName, workers)); } catch (Exception ex) { SmashLog.Error($"{entry} is not a valid <struct>VehicleJobLimitations</struct> format. Exception: {ex}"); return(Invalid); } }
public static VehicleDamageMultipliers FromString(string entry) { entry = entry.TrimStart(new char[] { '(' }).TrimEnd(new char[] { ')' }); string[] data = entry.Split(new char[] { ',' }); try { CultureInfo invariantCulture = CultureInfo.InvariantCulture; float meleeDamageMultiplier = Convert.ToSingle(data[0], invariantCulture); float rangedDamageMultiplier = Convert.ToSingle(data[1], invariantCulture); float explosiveDamageMultiplier = Convert.ToSingle(data[2], invariantCulture); return(new VehicleDamageMultipliers(meleeDamageMultiplier, rangedDamageMultiplier, explosiveDamageMultiplier)); } catch (Exception ex) { SmashLog.Error($"{entry} is not a valid <struct>VehicleDamageMultipliers</struct> format. Exception: {ex}"); return(Default); } }
public static void IterateTypeFields(VehicleDef def, Type type, object obj, ref Dictionary <SaveableField, SavedField <object> > currentDict) { if (VehicleMod.cachedFields.TryGetValue(type, out var fields)) { var dict = VehicleMod.settings.vehicles.fieldSettings[def.defName]; foreach (FieldInfo field in fields) { if (field.TryGetAttribute <PostToSettingsAttribute>(out var settings) && settings.ParentHolder) { object value = field.GetValue(obj); if (field.FieldType.IsGenericType) { MethodInfo method = field.DeclaringType.GetMethod("ResolvePostToSettings", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); if (method != null) { object[] arguments = new object[] { def, currentDict }; method.Invoke(obj, arguments); currentDict = (Dictionary <SaveableField, SavedField <object> >)arguments[1]; } else { SmashLog.Error($"Unable to generate customizable setting <field>{field.Name}</field> for <text>{def.defName}</text>. Fields of type <type>Dictionary<T></type> must implement ResolvePostToSettings method to be manually resolved."); } } else { IterateTypeFields(def, field.FieldType, value, ref currentDict); } } else { SaveableField saveField = new SaveableField(def, field); if (!dict.TryGetValue(saveField, out var _)) { dict.Add(saveField, new SavedField <object>(field.GetValue(obj))); } } }
static AssetBundleDatabase() { string version = $"{VersionControl.CurrentMajor}.{VersionControl.CurrentMinor}"; if (bundleBuildVersionManifest.TryGetValue(version, out string currentVersion)) { if (currentVersion != Application.unityVersion) { Log.Warning($"{VehicleHarmony.LogLabel} Unity Version {Application.unityVersion} does not match registered version for AssetBundles being loaded. You may encounter problems."); } } string folderChecking = "default"; List <string> loadFolders = FilePaths.LoadFolderLocalFilePath(VehicleMod.settings.Mod.Content); try { foreach (string folder in loadFolders) { string versionFilePath = Path.Combine(VehicleMod.settings.Mod.Content.RootDir, folder, ShaderAssetBundlePath); folderChecking = versionFilePath; if (File.Exists(versionFilePath)) { ShaderBundle = AssetBundle.LoadFromFile(versionFilePath); if (ShaderBundle is null) { throw new NullReferenceException(); } CutoutComplexRGB = LoadAssetBundleShader("Assets/Shaders/ShaderRGB.shader"); CutoutComplexPattern = LoadAssetBundleShader("Assets/Shaders/ShaderRGBPattern.shader"); } goto CursorLoading; } throw new IOException(); } catch (Exception ex) { SmashLog.Error($"Unable to load AssetBundle at <text>{folderChecking}</text>\nException = {ex.Message}"); } CursorLoading :; try { foreach (string folder in loadFolders) { string versionFilePath = Path.Combine(VehicleMod.settings.Mod.Content.RootDir, folder, CursorAssetBundlePath); folderChecking = versionFilePath; if (File.Exists(versionFilePath)) { CursorBundle = AssetBundle.LoadFromFile(versionFilePath); if (CursorBundle is null) { throw new NullReferenceException(); } MouseHandOpen = LoadAssetBundleTexture("Assets/Textures/MouseHandOpen.png"); MouseHandClosed = LoadAssetBundleTexture("Assets/Textures/MouseHandClosed.png"); } } } catch (Exception ex) { SmashLog.Error($"Unable to load AssetBundle at <text>{CursorAssetBundlePath}</text>\nException = {ex.Message}"); } }
/// <summary> /// Draws UI element for lister in ModSettings /// </summary> /// <param name="lister"></param> /// <param name="def"></param> /// <param name="field"></param> public void DrawLister(Listing_Settings lister, VehicleDef def, FieldInfo field) { string label = Translate ? Label.Translate().ToString() : Label; string tooltip = Translate ? Tooltip.Translate().ToString() : Tooltip; SaveableField saveable = new SaveableField(def, field); string disabledTooltip = string.Empty; if (VehicleType != VehicleType.Undefined && VehicleType != def.vehicleType) { disabledTooltip = "VehicleSaveableFieldDisabledTooltip".Translate(); } bool locked = false; if (ParsingHelper.lockedFields.TryGetValue(def.defName, out HashSet <FieldInfo> lockedFields)) { if (lockedFields.Contains(field)) { locked = true; disabledTooltip = "VehicleSaveableFieldLockedTooltip".Translate(); } } if (field.HasAttribute <DisableSettingAttribute>()) { disabledTooltip = "VehicleDebugDisabledTooltip".Translate(); } switch (UISettingsType) { case UISettingsType.None: return; case UISettingsType.Checkbox: lister.CheckboxLabeled(def, saveable, label, tooltip, disabledTooltip, locked); break; case UISettingsType.IntegerBox: { if (field.TryGetAttribute <NumericBoxValuesAttribute>(out var inputBox)) { lister.IntegerBox(def, saveable, label, tooltip, disabledTooltip, Mathf.RoundToInt(inputBox.MinValue), Mathf.RoundToInt(inputBox.MaxValue)); } else { lister.IntegerBox(def, saveable, label, tooltip, disabledTooltip, 0, int.MaxValue); } break; } case UISettingsType.FloatBox: { if (field.TryGetAttribute <NumericBoxValuesAttribute>(out var inputBox)) { lister.FloatBox(def, saveable, label, tooltip, disabledTooltip, inputBox.MinValue, inputBox.MaxValue); } else { lister.FloatBox(def, saveable, label, tooltip, disabledTooltip, 0, float.MaxValue); } break; } case UISettingsType.ToggleLabel: break; case UISettingsType.SliderEnum: lister.EnumSliderLabeled(def, saveable, label, tooltip, disabledTooltip, field.FieldType, Translate); break; case UISettingsType.SliderInt: { if (field.TryGetAttribute <SliderValuesAttribute>(out var slider)) { lister.SliderLabeled(def, saveable, label, tooltip, disabledTooltip, slider.EndSymbol, (int)slider.MinValue, (int)slider.MaxValue, (int)slider.EndValue, slider.MaxValueDisplay, slider.MinValueDisplay, Translate); } else { SmashLog.WarningOnce($"Slider declared for SaveableField {field.Name} in {field.DeclaringType} with no SliderValues attribute. Slider will use default values instead.", field.GetHashCode()); lister.SliderLabeled(def, saveable, label, tooltip, disabledTooltip, string.Empty, 0, 100, -1, string.Empty, string.Empty, Translate); } } break; case UISettingsType.SliderFloat: { if (field.TryGetAttribute <SliderValuesAttribute>(out var slider)) { lister.SliderLabeled(def, saveable, label, tooltip, disabledTooltip, slider.EndSymbol, slider.MinValue, slider.MaxValue, slider.RoundDecimalPlaces, slider.EndValue, slider.Increment, slider.MaxValueDisplay, Translate); } else { SmashLog.WarningOnce($"Slider declared for SaveableField {field.Name} in {field.DeclaringType} with no SliderValues attribute. Slider will use default values instead.", field.GetHashCode()); lister.SliderLabeled(def, saveable, label, tooltip, disabledTooltip, string.Empty, 0f, 100f, 0, -1, -1, string.Empty, Translate); } } break; case UISettingsType.SliderPercent: { if (field.TryGetAttribute <SliderValuesAttribute>(out var slider)) { lister.SliderPercentLabeled(def, saveable, label, tooltip, disabledTooltip, slider.EndSymbol, slider.MinValue, slider.MaxValue, slider.RoundDecimalPlaces, slider.EndValue, slider.MaxValueDisplay, Translate); } else { SmashLog.WarningOnce($"Slider declared for SaveableField {field.Name} in {field.DeclaringType} with no SliderValues attribute. Slider will use default values instead.", field.GetHashCode()); lister.SliderPercentLabeled(def, saveable, label, tooltip, disabledTooltip, string.Empty, 0f, 100f, 0, -1, string.Empty, Translate); } } break; default: Log.ErrorOnce($"{VehicleHarmony.LogLabel} {UISettingsType} has not yet been implemented for PostToSettings.DrawLister. Please notify mod author.", UISettingsType.ToString().GetHashCode()); break; } }
static VehicleTex() { StringBuilder tasks = new StringBuilder(); foreach (VehicleDef vehicleDef in DefDatabase <VehicleDef> .AllDefs) { tasks.Clear(); tasks.AppendLine($"Generating TextureCache for {vehicleDef.defName}"); try { tasks.Append("Creating icon..."); string iconFilePath = vehicleDef.properties.iconTexPath; if (iconFilePath.NullOrEmpty()) { switch (vehicleDef.vehicleType) { case VehicleType.Land: iconFilePath = DefaultVehicleIconTexPath; break; case VehicleType.Sea: iconFilePath = DefaultBoatIconTexPath; break; case VehicleType.Air: iconFilePath = DefaultShuttleIconTexPath; break; } } tasks.AppendLine("Icon created"); tasks.AppendLine("Creating BodyGraphicData and cached graphics..."); if (vehicleDef.graphicData is GraphicDataRGB graphicDataRGB) { Texture2D tex; var graphicData = new GraphicDataRGB(); graphicData.CopyFrom(graphicDataRGB); Graphic_Vehicle graphic = graphicData.Graphic as Graphic_Vehicle; tasks.AppendLine("Setting TextureCache..."); SetTextureCache(vehicleDef, graphicData); tasks.AppendLine("Finalized TextureCache"); if (cachedTextureFilepaths.ContainsKey(iconFilePath)) { tex = cachedTextureFilepaths[iconFilePath]; } else { tex = ContentFinder <Texture2D> .Get(iconFilePath); cachedTextureFilepaths.Add(iconFilePath, tex); } tasks.AppendLine("Finalizing caching"); CachedGraphics.Add(vehicleDef, graphic); CachedTextureIcons.Add(vehicleDef, tex); } else { SmashLog.Error($"Unable to create GraphicData of type <type>{vehicleDef.graphicData?.GetType().ToStringSafe() ?? "Null"} for {vehicleDef.defName}.\n{tasks}"); } } catch (Exception ex) { Log.Error($"Exception thrown while trying to generate cached textures. Exception=\"{ex.Message}\"\n-----------------Tasks-----------------\n{tasks}"); } } }