Chinese smoke deflectors

master
t0stiman 2023-11-25 15:38:56 +01:00
parent ab8a42d98b
commit 757b9f21f7
12 changed files with 219 additions and 171 deletions

6
.gitignore vendored
View File

@ -398,3 +398,9 @@ FodyWeavers.xsd
# .nfs files are created when an open file is removed but is still being accessed # .nfs files are created when an open file is removed but is still being accessed
.nfs* .nfs*
# ======================================================
*.unitypackage
assetbundles/*.manifest
assetbundles/assetbundles

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2023 Derail Valley Modding Copyright (c) 2023 ÆUGH
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,7 +1,11 @@
<h1>Dumb S282 Tweaks</h1> # S282 Tweaks
<p>This is stupid</p>
## License Smoke deflectors and a streamlined boiler for the S282.
<p>
Source code is distributed under the MIT license. todo screenshot
</p>
## Credits
AEUGH: Streamlined boiler, Witte & Wagner smoke deflectors, code
Tostiman: code
Cypress: Chinese smoke deflectors

Binary file not shown.

View File

@ -10,63 +10,98 @@ namespace dumb282tweaks;
class CarPatch { class CarPatch {
static void Postfix(ref TrainCar __instance) static void Postfix(ref TrainCar __instance)
{ {
if(__instance != null && __instance.carType == TrainCarType.LocoSteamHeavy) if (__instance == null || __instance.carType != TrainCarType.LocoSteamHeavy)
{ {
string bodyPath = "LocoS282A_Body/Static_LOD0/s282_locomotive_body"; return;
Transform s282Body = __instance.transform.Find(bodyPath); }
if (s282Body == null)
string bodyPath = "LocoS282A_Body/Static_LOD0/s282_locomotive_body";
Transform s282Body = __instance.transform.Find(bodyPath);
if (s282Body == null)
{
Error($"Couldn't find S282 body on '{__instance.transform.gameObject.name}' -> {bodyPath}");
return;
}
Material s282Mat = s282Body.GetComponent<MeshRenderer>().material;
// Smoke Deflector
Log($"Applying {MySettings.smokeDeflectorType.ToString()}");
switch(MySettings.smokeDeflectorType) {
case Settings.SmokeDeflectorType.Witte:
{ {
Error($"Couldn't find S282 body on '{__instance.transform.gameObject.name}' -> {bodyPath}"); GameObject witteSmokeDeflector = Object.Instantiate(witteSmokeDeflectorsPrefab, __instance.transform);
return; witteSmokeDeflector.transform.localPosition = new Vector3(0.0f, 2.1f, 5f);
witteSmokeDeflector.transform.localRotation = Quaternion.identity;
foreach (var aMeshRenderer in witteSmokeDeflector.GetComponentsInChildren<MeshRenderer>())
{
aMeshRenderer.material = s282Mat;
}
break;
} }
case Settings.SmokeDeflectorType.Wagner:
Material s282Mat = s282Body.GetComponent<MeshRenderer>().material;
// Smoke Deflector
switch(Main.Settings.smokeDeflectorType) {
case Settings.SmokeDeflectorType.Witte:
Log("witte");
GameObject witteSmokeDeflector = Object.Instantiate(witteSmokeDeflectorsLoad, __instance.transform);
witteSmokeDeflector.transform.localPosition = new Vector3(0.0f, 2.1f, 5f);
witteSmokeDeflector.transform.localRotation = Quaternion.identity;
foreach (var aMeshRenderer in witteSmokeDeflector.GetComponentsInChildren<MeshRenderer>())
{
aMeshRenderer.material = s282Mat;
}
break;
case Settings.SmokeDeflectorType.Wagner:
Log("witten't");
GameObject wagnerSmokeDeflector = Object.Instantiate(wagnerSmokeDeflectorsLoad, __instance.transform);
wagnerSmokeDeflector.transform.localPosition = new Vector3(0.0f, 2.1f, 5f);
wagnerSmokeDeflector.transform.localRotation = Quaternion.identity;
foreach (var aMeshRenderer in wagnerSmokeDeflector.GetComponentsInChildren<MeshRenderer>())
{
aMeshRenderer.material = s282Mat;
}
break;
}
// Boiler
switch (Main.Settings.boilerType)
{ {
case Settings.BoilerType.Streamlined: GameObject wagnerSmokeDeflector = Object.Instantiate(wagnerSmokeDeflectorsPrefab, __instance.transform);
GameObject streamlinedBoiler = Object.Instantiate(streamlinedBoilerLoad, __instance.transform); wagnerSmokeDeflector.transform.localPosition = new Vector3(0.0f, 2.1f, 5f);
streamlinedBoiler.transform.localPosition = new Vector3(0.0f, 2.15f, 5.1f); wagnerSmokeDeflector.transform.localRotation = Quaternion.identity;
streamlinedBoiler.transform.localRotation = Quaternion.identity;
foreach (var aMeshRenderer in streamlinedBoiler.GetComponentsInChildren<MeshRenderer>()) foreach (var aMeshRenderer in wagnerSmokeDeflector.GetComponentsInChildren<MeshRenderer>())
{ {
aMeshRenderer.material = s282Mat; aMeshRenderer.material = s282Mat;
} }
break; break;
} }
case Settings.SmokeDeflectorType.Chinese:
ApplyChineseSmokeDeflector(ref __instance, s282Body);
break;
}
// Boiler
Log($"Applying {MySettings.boilerType.ToString()}");
switch (MySettings.boilerType)
{
case Settings.BoilerType.Streamlined:
GameObject streamlinedBoiler = Object.Instantiate(streamlinedBoilerPrefab, __instance.transform);
streamlinedBoiler.transform.localPosition = new Vector3(0.0f, 2.15f, 5.1f);
streamlinedBoiler.transform.localRotation = Quaternion.identity;
foreach (var aMeshRenderer in streamlinedBoiler.GetComponentsInChildren<MeshRenderer>())
{
aMeshRenderer.material = s282Mat;
}
break;
} }
} }
private static void ApplyChineseSmokeDeflector(ref TrainCar locomotive, Transform body)
{
//hide smoke box door
var smokeboxDoorPath = "LocoS282A_Body/Static_LOD0/s282_locomotive_smokebox_door";
Transform smokeBoxDoor = locomotive.transform.Find(smokeboxDoorPath);
if (smokeBoxDoor == null)
{
Error($"Couldn't find S282 smoke box door on '{locomotive.transform.gameObject.name}' -> {smokeboxDoorPath}");
return;
}
smokeBoxDoor.gameObject.SetActive(false);
//show deflector and stuff
GameObject chineseSmokeDeflector = Object.Instantiate(chineseSmokeDeflectorsPrefab, body);
chineseSmokeDeflector.transform.localPosition = smokeBoxDoor.localPosition;
//todo apply S282 material?
// foreach (var aMeshRenderer in chineseSmokeDeflector.GetComponentsInChildren<MeshRenderer>())
// {
// if (aMeshRenderer.material.name == "S282") //todo
// {
// aMeshRenderer.material = s282Mat;
// }
// }
}
} }

View File

@ -4,99 +4,72 @@ using System.Reflection;
using HarmonyLib; using HarmonyLib;
using UnityModManagerNet; using UnityModManagerNet;
using UnityEngine; using UnityEngine;
using System.Diagnostics.CodeAnalysis;
namespace dumb282tweaks; namespace dumb282tweaks
{
[EnableReloading]
public static class Main
{
public static UnityModManager.ModEntry MyModEntry { get; private set; }
public static Settings MySettings { get; private set; }
public static class Main { public static GameObject wagnerSmokeDeflectorsPrefab;
// Variables public static GameObject witteSmokeDeflectorsPrefab;
public static UnityModManager.ModEntry Instance { get; private set; } public static GameObject chineseSmokeDeflectorsPrefab;
public static dumb282tweaksSettings Settings { get; private set; }
// public static readonly string[] cabTypeTexts = new[] { public static GameObject streamlinedBoilerPrefab;
// "Default",
// "German"
// };
public static readonly string[] smokeDeflectorTypeTexts = new[] {
"None",
"Witte",
"Wagner"
};
public static readonly string[] boilerTypeTexts = new[] {
"Default",
"Streamlined"
};
// public static readonly string[] smokeStackTypeTexts = new[] {
// "Default",
// "Short",
// };
public static GameObject wagnerSmokeDeflectorsLoad; private static bool Load(UnityModManager.ModEntry modEntry)
public static GameObject witteSmokeDeflectorsLoad; {
public static GameObject streamlinedBoilerLoad; Harmony harmony = null;
// Load try
private static bool Load(UnityModManager.ModEntry modEntry) { {
Harmony? harmony = null; MyModEntry = modEntry;
MySettings = UnityModManager.ModSettings.Load<Settings>(MyModEntry);
try { MyModEntry.OnGUI = entry => MySettings.Draw(entry);
Instance = modEntry; MyModEntry.OnSaveGUI = entry => MySettings.Save(entry);
Settings = UnityModManager.ModSettings.Load<dumb282tweaksSettings>(Instance);
Instance.OnGUI = OnGUI; string assetPath = Path.Combine(MyModEntry.Path, "assetbundles\\");
Instance.OnSaveGUI = OnSaveGUI;
harmony = new Harmony(Instance.Info.Id); wagnerSmokeDeflectorsPrefab = AssetBundle.LoadFromFile(Path.Combine(assetPath, "wagnersmokedeflectors"))
harmony.PatchAll(Assembly.GetExecutingAssembly()); .LoadAsset<GameObject>("Assets/WagnerSmokeDeflectors.prefab");
witteSmokeDeflectorsPrefab = AssetBundle.LoadFromFile(Path.Combine(assetPath, "wittesmokedeflectors"))
.LoadAsset<GameObject>("Assets/WitteSmokeDeflectors.prefab");
chineseSmokeDeflectorsPrefab = AssetBundle.LoadFromFile(Path.Combine(assetPath, "chinesesmokedeflectors"))
.LoadAsset<GameObject>("Assets/Prefab/LocoS282A_Smokebox.prefab");
string assetPath = Path.Combine(Instance.Path, "assets\\"); streamlinedBoilerPrefab = AssetBundle.LoadFromFile(Path.Combine(assetPath, "streamline"))
.LoadAsset<GameObject>("Assets/Streamline.prefab");
wagnerSmokeDeflectorsLoad = AssetBundle.LoadFromFile(Path.Combine(assetPath, "wagnersmokedeflectors")).LoadAsset<GameObject>("Assets/WagnerSmokeDeflectors.prefab"); harmony = new Harmony(MyModEntry.Info.Id);
witteSmokeDeflectorsLoad = AssetBundle.LoadFromFile(Path.Combine(assetPath, "wittesmokedeflectors")).LoadAsset<GameObject>("Assets/WitteSmokeDeflectors.prefab"); harmony.PatchAll(Assembly.GetExecutingAssembly());
streamlinedBoilerLoad = AssetBundle.LoadFromFile(Path.Combine(assetPath, "streamline")).LoadAsset<GameObject>("Assets/Streamline.prefab"); }
catch (Exception ex)
{
MyModEntry.Logger.LogException($"Failed to load {MyModEntry.Info.DisplayName}:", ex);
harmony?.UnpatchAll(MyModEntry.Info.Id);
return false;
}
} catch(Exception ex) { return true;
Instance.Logger.LogException($"Failed to load {Instance.Info.DisplayName}:", ex);
harmony?.UnpatchAll(Instance.Info.Id);
return false;
} }
return true; // Logger Commands
} public static void Log(string message)
{
MyModEntry.Logger.Log(message);
}
// GUI Rendering public static void Warning(string message)
static void OnGUI(UnityModManager.ModEntry modEntry) { {
GUILayout.BeginVertical(); MyModEntry.Logger.Warning(message);
}
GUILayout.Label("These settings are applied on train spawn, meaning rejoining the game will refresh all 282 locos to the settings specified here, but if you don't unload the train it will keep whatever settings were there previously. This is a temporary solution until I have a proper GUI implemented."); public static void Error(string message)
GUILayout.Label("Also, reloading a save will currently break things and the tweaks won't load. This isn't good."); {
MyModEntry.Logger.Error(message);
GUILayout.Space(2f); }
//todo this is not implemented
// GUILayout.Label("Cab Type");
// Settings.cabType = (Settings.CabType) GUILayout.SelectionGrid((int) Settings.cabType, cabTypeTexts, 1, "toggle");
GUILayout.Label("Smoke Deflector Type");
Settings.smokeDeflectorType = (Settings.SmokeDeflectorType) GUILayout.SelectionGrid((int) Settings.smokeDeflectorType, smokeDeflectorTypeTexts, 1, "toggle");
GUILayout.Label("Boiler Type");
Settings.boilerType = (Settings.BoilerType) GUILayout.SelectionGrid((int) Settings.boilerType, boilerTypeTexts, 1, "toggle");
GUILayout.EndVertical();
}
static void OnSaveGUI(UnityModManager.ModEntry modEntry) {
Settings.Save(modEntry);
}
// Logger Commands
public static void Log(string message) {
Instance.Logger.Log(message);
}
public static void Warning(string message) {
Instance.Logger.Warning(message);
}
public static void Error(string message) {
Instance.Logger.Error(message);
} }
} }

View File

@ -1,39 +1,69 @@
using System;
using System.ComponentModel; using System.ComponentModel;
using UnityEngine;
using UnityModManagerNet; using UnityModManagerNet;
using static dumb282tweaks.Settings;
namespace dumb282tweaks; namespace dumb282tweaks
{
public static class Settings { public class Settings : UnityModManager.ModSettings
public enum CabType { {
[Description("Default 282 Cab")] // public enum CabType
Default, // {
[Description("German Cab")] // [Description("Default 282 Cab")] Default,
German // [Description("German Cab")] German
} // }
public enum BoilerType {
[Description("Default Boiler")] public enum BoilerType
Default, {
[Description("Streamlined Boiler")] [Description("Default Boiler")] Default,
Streamlined, [Description("Streamlined Boiler")] Streamlined,
} }
public enum SmokeDeflectorType {
[Description("No Smoke Deflectors")] public enum SmokeDeflectorType
None, {
[Description("Witte Smoke Deflectors")] [Description("No smoke deflectors")]
Witte, None,
[Description("Wagner Smoke Deflectors")]
Wagner, [Description("Witte smoke deflectors")]
Witte,
[Description("Wagner smoke deflectors")]
Wagner,
[Description("Chinese smoke deflectors and more")]
Chinese,
}
// public CabType cabType = CabType.Default;
public SmokeDeflectorType smokeDeflectorType = SmokeDeflectorType.Wagner;
public BoilerType boilerType = BoilerType.Default;
public void Draw(UnityModManager.ModEntry modEntry)
{
GUILayout.BeginVertical();
GUILayout.Label("These settings are applied on train spawn, meaning rejoining the game will refresh all 282 locos to the settings specified here, but if you don't unload the train it will keep whatever settings were there previously. This is a temporary solution until I have a proper GUI implemented.");
GUILayout.Label("Also, reloading a save will currently break things and the tweaks won't load. This isn't good.");
GUILayout.Space(2f);
//todo this is not implemented
// GUILayout.Label("Cab Type");
// Settings.cabType = (Settings.CabType) GUILayout.SelectionGrid((int) Settings.cabType, cabTypeTexts, 1, "toggle");
GUILayout.Label("Smoke Deflector Type");
smokeDeflectorType = (SmokeDeflectorType) GUILayout.SelectionGrid((int) smokeDeflectorType, Enum.GetNames(typeof(SmokeDeflectorType)), 1, "toggle");
GUILayout.Label("Boiler Type");
boilerType = (BoilerType) GUILayout.SelectionGrid((int) boilerType, Enum.GetNames(typeof(BoilerType)), 1, "toggle");
GUILayout.EndVertical();
}
public override void Save(UnityModManager.ModEntry modEntry)
{
Save(this, modEntry);
}
} }
} }
public class dumb282tweaksSettings : UnityModManager.ModSettings {
// public CabType cabType = CabType.Default;
public SmokeDeflectorType smokeDeflectorType = SmokeDeflectorType.Wagner;
public BoilerType boilerType = BoilerType.Default;
public override void Save(UnityModManager.ModEntry modEntry) {
Save(this, modEntry);
}
}

View File

@ -4,7 +4,7 @@ param (
) )
Set-Location "$PSScriptRoot" Set-Location "$PSScriptRoot"
$FilesToInclude = "info.json","build/*","LICENSE","assets" $FilesToInclude = "info.json","build/*","LICENSE","assetbundles"
$modInfo = Get-Content -Raw -Path "info.json" | ConvertFrom-Json $modInfo = Get-Content -Raw -Path "info.json" | ConvertFrom-Json
$modId = $modInfo.Id $modId = $modInfo.Id
@ -20,7 +20,7 @@ $ZipOutDir = "$ZipWorkDir/$modId"
New-Item "$ZipOutDir" -ItemType Directory -Force New-Item "$ZipOutDir" -ItemType Directory -Force
Copy-Item -Force -Path $FilesToInclude -Destination "$ZipOutDir" Copy-Item -Force -Path $FilesToInclude -Destination "$ZipOutDir"
Copy-Item -Force -Path "assets/*" -Destination "$ZipOutDir/assets" Copy-Item -Force -Path "assetbundles/*" -Destination "$ZipOutDir/assetbundles"
if (!$NoArchive) if (!$NoArchive)
{ {