#Toggle Notifications devlog
1 messages · Page 3 of 1
Like the lines to separate the window
I also plan on shifting the fill window to the togglenotifiationsui
Removing a bunch of stuff in that that I'm not using etc
For some their learning curve resembles a plane taking off and climbing, for some a rocket, and for a few special ones a submarine...
You've gone from nada to a mod that does something useful pretty quickly.
And there's a ton of things you had to learn along the way! Things that don't necessarily show up in the finished product, but impact your ability to develop it further.
I'm also glad I don't have to do math or calculate orbits or hohmann transfers 🤣
Me too!
I just turn button on and off
Oh... wait...
gone from YouTube videos covering mods to making mods!
Lol
I'll be making more videos just wanting to get this up and running and honestly having a blast modding
Youtube is fun and that's why I do it.
I have a theory about that. He must have run out of good mods to document, so he felt compelled to make some...
I'm not sure what you're showing here, but it seems like it might be broken. What does it mean for a thing to be both "Active" and also "Active"?
im taking screenshots so i can have a visual aid while i fix things
cause i have a terrible memory
ive made the buttons dynamic in how they calculate their width as well
they dont seem centered though
they seem centered to me (in the remaining space that they have next to the green rectangle)
Ahh, IC. What I do for that is to make an Images folder at the base level of the project and stuff things in there, then use GitHub to push them up to the repo. That way I can reference them easily in the README if I want to use them there. It also means they're posted online where I can use them for posts to KSP forums, or reference them from SpaceDock much like in the README
also this is being calculated every frame
so im making an updatewindow in the togglenotifUI that will do that in the background
and fillwindow will call it when the user changes the value
The Images folder is different from assets/images and doesn't ship with the game, but it's handy for other stuff
The wide buttons? Yes, definitely
but this is an option to pursue
i feel like it ssimple and it works with other mods
so theres familiarity
I like it this way
also moving everything to the UI and making the plugin skinnier
its almost as if I planned this all out
if this works ill be amazed
internal void OnGUI()
{
this.MainUI.OnGUI();
}
internal void FillWindow(int windowID)
{
MainUI.FillWindow(windowID);
}
}
@visual bone I just made the raw video for my first tutorial video. I'm sure it's far from ideal, but I've got the raw video captured from OBS Studio. This leaves me with a 141mb MKV file. What's the next step?
Is there a way in OBS Studio to make it smaller and suitable for uplaoding?
hm
mkv is a slippery slope
they're not the most stable files, ive had them get corrupted very easily
i record using mp4 because its reliable and doesnt get corrupted as easily as mkv
full views of the windows
with recording you want to jack up your bitrate
Well I can re-record it.
54000 Kbps works really well for 4k video
look up the spec ranges for the Kbps for whatever quality you're going for
this isnt for streaming
streaming is a whole other animal
simple but its different
ive got a stream pc that handles all of that
i stream on stream pc, and record 4k with my game pc
but once you have your settings all squared away, then you can test it
you wanna make sure you're getting the best quality your rig can get
no idea what specs you're running
I've got 2K monitors and the game is at 1920 x 1080 windowed
gpu and cpu?
My video card?
GPU high end
It's one that KSP2 recommended
thats what you want to use
that basically uses your GPU to do allt he work
x264 is for a good cpu
I can't use Nvida due to this being a dual boot hackintosh and OSX doesn't like those cards
ah
then you'll wanna rock x264
x264 will use your cpu
youll have to tweak your settings based off using the x264
its like coding, play with it til it works how you want on your rig
any other questions or way si can help?
obviously the recording tab shows you where you can have the video save the .mp4 to
wait one.
Lots more questions, and I'm completely new and most of what you've told me has gone right over my head.
How do you see your video card in stupid f-ing windows?
lol
not familiar with team red. havent used AMD since early 2000's
OK, so I think my next steps are in OBS studio, and I'm barely able to find the start recording button
Where do I tell it what format to capture in and all that other stuff you were telling me?
yeah like that
and the scene has your display that you're capturing
controls has the settings that change everything
so bottom right
start streaming, start recording... then settings
Settings > Output?
yup
so youll want to look at the streaming tab and recording tab within output
video tab lets you pick the resolution you record
For video encoder I've got options for Software (x264) and Hardware AMD H.264
so base is the native resolution your monitor is at
Should I go with HW?
oh try hardware amd h.264
thatll use your gpu
software x264 is going ot use your cpu and wont be as good as the gpu
the technical aspects im not sure
but the last thing i wanna learn is how a graphics card works and calculates things
found where to set it to mpeg-4
yup
itll be in output >> recording
you can change the pathing there and the format you record in
as well as select which audio tracks to record
What do you do with the audio tracks? I've got my mic disabled and the sound from the game is the only thing. Audi Track 1 is checked and the others are not
i use voicemeeter
im building a rack right now to takeover the mixer and audio interface so i have hardware instead of software
uh but for recording, it just depends
i record gameplay with only the game audio
most of the time i delete the audio from the game
yeah
if your computer shuts off
it wont save your mp4
but from 3 years of streaming and just starting on youtube, def have learned mp4s are the most stable
better quality and they work with every software
mkv will not be useable by premiere
Does this mean I might be able to take the MKV I've got now and "remux" it to MPEG-4?
youd have to convert the mkv to mp4 to use the footage in premiere
yup
you def can
may lose a bit of quality
I don't have premiere
blender?
i used blender when i started over again with youtube this year
all my 1080p videos are with blender
I've got some Adobe stuff, but only Ps and LrC
I'm mainly a stills guy
Is blender free?
Then I'll go get blender and use that
Oh fun...
yup
that's a new one for me, never heard of anyone using it for video editing
So OBS can't help me with that stuff and it just does capture?
I guess I was kinda hoping it was a one stop shop for this... 😛
lol
nope
obs just records
theres some cool plugins i use with obs
which eventually as i learn more coding i wanna make my own plugin for obs
it was painful
but it was free
and i wanted to see if i enjoyed youtube so before i spent money on premiere it made sense
then i found out i really enjoy youtube and streaming is more when i feel like it
wouldn't something like DaVinci Resolve be better?
resolve is really good
since it's actually made for the purpose of video editing
i just use premiere
ive also not used resolve personally but a lot of content creator friends use it
is it free?
i went with premiere because later this year im gonna get after effects
I like free!
and learn how that works
yep
also im starting to understand what a GUI will look like via code
weird that stuff uses the top left to adjust from
like who does that? why not be normal like all mathematics and use the bottom left?
^ dis is normal and it has sun
well it is the most intuitive thing
most people read from top left to bottom right
etc
so why not computers
There are 10 kinds of people...
well later today im going to think about how to make the GUI work and not on the plugin
because i can tell this is going to be a resource hog if it stays the way it is
dont need this being updated every frame
there's no other way, that's how IMGUI is designed to work
all you can do it use a different UI library
UITK or UGUI
(!radioButton3 && selectedRadioButton3 == 1) this prevents it from being updated every frame
IMGUI is mostly intended to be used for debugging purposes, but the KSP 1 (and because of that, KSP 2) community started using it for mods because it was the easiest to use
nice lol
toggle notifications im going to use IMGUI as its teaching me a lot of how this all works
oh I mean I guess you can get rid of some of the calls that your code does in the OnGUI method, for sure
but no matter what, the whole UI will keep getting re-rendered multiple times per frame
thats so weird
i tried to use a windowupdate method and call it from the MainUI.WindowUpdate()
i had everything on screen
but no buttons
and then i had buttons
but they didnt fit in the window
which "windowupdate" method?
and i couldnt figure out how to get the MainUI.windowUpdate to be called AND check the windowfill to fit within the window
a method i made up
private void FillWindow(int windowID)
{
MainUI.FillWindow(windowID);
}
This is totally fine, it's the same exact thing as if you put the code from MainUI.FillWindow inside the plugin's FillWindow method
so something else has to be going wrong
internal void UpdateWindow()
{
int buttonWidth = (int)(windowRect.width - 12); // Subtract 3 on each side for padding
// Check if the button state has changed
if (previousButtonState1 != isButtonSwitched)
{
bool radioButton1 = GUI.Toggle(new Rect(3, 56, buttonWidth, 20), selectedRadioButton == 1, "Game Pause", selectedRadioButton == 0 ? TNBaseStyle.ToggleError : TNBaseStyle.Toggle);
TNBaseStyle.ToggleError.normal.textColor = selectedRadioButton == 0 ? Color.red : ColorTools.ParseColor("#C0E2DC");
TNBaseStyle.Toggle.normal.textColor = selectedRadioButton == 1 ? ColorTools.ParseColor("#C0C1E2") : ColorTools.ParseColor("#C0E2DC");
if (radioButton1)
{
selectedRadioButton = 1;
isButtonSwitched = true;
}
else
{
selectedRadioButton = 0;
isButtonSwitched = false;
}
// Update the previous button state
previousButtonState1 = isButtonSwitched;
}
}
internal bool OnGUI()
{
UpdateWindow();
return true;
}```
thats what i had come up with
so it gets called
it generates a window but no buttons
can OnGUI even have a return value? Unity only ever uses it with a void type
and then it later on generated a window but the four buttons didnt fit inside the window
afaik
OnGUI has to have a return
that was the early thing i was trying
then i went to this
I'm pretty sure that (if that even works at all) it won't do anything
hm
what i did is i put everything from my FillWindow into the ToggleNotifidcationsUI
created my own FillWindow there,
yeah so now all you need to do is create an instance of this class and call its OnGUI method from the plugin class's OnGUI
hm
oh and since you have an Update method here, the same goes for that
i called both the update and the ongui in the plugins update
but what im working on should eventually work?
IMGUI code can only be called inside OnGUI, it doesn't work anywhere else
might explain why some stuff didnt work
this is what ive got currently
well im gonna relax for a bit and read this on my phone to see if i can see anything thats causing the gui to not show up
and what's on the line 125 in your plugin class?
Looking now
Reference for me later
internal void OnGUI()
{
this.MainUI.OnGUI();
}
thats line 125
well, then that means you've never assigned a value to MainUI
can you show me where/how?
if you mean something like private ToggleNotificationUI MainUI; then no, that only creates an empty variable of the type ToggleNotificationUI which has no value
namespace ToggleNotifications
{
internal class ToggleNotificationsUI
{
internal List<string> NotificationList = new List<string>();
internal static ToggleNotificationsUI instance;
internal static NotificationToggle toggleNotification;
internal ToggleNotificationsPlugin mainPlugin;
internal MessageCenterMessage Refreshing;
internal NotificationEvents RefreshingNotification;
internal static NotificationToggle notificationToggle;
private bool InitDone;
private bool isGUIVisible;
private TabsUI tabs;
internal bool interfaceEnabled;
private Rect windowRect = Rect.zero;
private int windowWidth = 250;
internal ToggleNotificationsUI MainUI;
Son of a
you need to do the same thing you do with the list in that code snippet
Oh
otherwise it's just null
Makes sense now
It has a way to check a value
When it's in a list
Otherwise it isn't doing anything
And what it checks is the contents of the OnGUI?
I'm not following
Thus is me trying to understand how that works
I'm gonna nod off as I need sleep. I appreciate the wisdom. I'll read up on more of this and get a better understanding later today 🤘🙏
class Person
{
private string _name;
public Person(string name)
{
_name = name;
}
public void SayHello()
{
Console.WriteLine($"Hello, {_name}!");
}
public static void SayHelloToAnyone()
{
Console.WriteLine("Hello there!");
}
}
class Greeter
{
private Person _person1 = new Person("John");
private Person _person2 = new Person("Kate");
private Person _person3;
public void GreetPeople()
{
_person1.SayHello(); // will output "Hello, John!"
_person2.SayHello(); // will output "Hello, Kate!"
_person3.SayHello(); // will throw a NullReferenceException because the variable is null (the person does not exist)
Person.SayHelloToAnyone(); // will output "Hello there!", is called on the class itself instead of on an instance of it because it's static, can't access any non-static information about a specific Person instance, such as "_name"
}
}
hopefully this will help a bit
@visual bone, I've got a video made. The file seem freaking huge as I started with a 141mb MKV, trimmed it just slightly, but otherwise did nothing to really edit it, and ended up with a 237mb MP4. Maybe that's normal.
I'm in the process of uploading it to YouTube and I've got s dumb questions.
YT want's to know if it's made for kids. Well... Not specifically, but it's age appropriate to anyone who might play KSP2 and want to perform an orbital rendezvous...
On the one hand, I don't expect kids to be particularly interested, but on the other I don't want to limit visibility
the only thing that does is flag the video to be available on the YouTube Kids app and disables comments and other stuff like that, afaik
Well, I don't think I want to disable comments and don't really give a crap about the YT kids app...
did you upload it @opal lagoon ?
i think i understood what the template you provided should be doing
whoops
It works! Got everything from plugin class migrated to the ui class
Decided to switch to transpilers instead of prefix. I think this will let me modify the patches to return to their original state
Yep, here: #1091863665134796880 message
2nd subscriber and watched it!
There are two videos. They are very basic! literally, the only editiing I did was to trim a bit off at the beginning of both and at the end of the second one. As Falki has pointed out I really ought to add some annotations.
Looks good!
You'll get it figured out. I've found having a pre-written script and reading it really helps
Literally a video essay
not sure why my button changed to that
figured it out
whats really annoying is I have to patch 3 things in the game for it to make pause not show up
Annoying for sure, but not really surprising. The user wants one effect and we need to do N things to realize it. That's what mods do!
private static IEnumerable<CodeInstruction> TranspilerLogic(IEnumerable<CodeInstruction> instructions)
{
var codes = new List<CodeInstruction>(instructions);
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Ldc_I4_0)
{
// Replace the false value with our local variable
codes[i].opcode = OpCodes.Ldsfld;
codes[i].operand = AccessTools.Field(typeof(AssistantToTheAssistantPatchManager), nameof(isGamePaused));
}
else if (codes[i].opcode == OpCodes.Ldc_I4_1)
{
// Replace the true value with the inverted local variable
codes[i].opcode = OpCodes.Ldsfld;
codes[i].operand = AccessTools.Field(typeof(AssistantToTheAssistantPatchManager), nameof(isGamePaused));
codes.Insert(i + 1, new CodeInstruction(OpCodes.Ldc_I4_0));
codes.Insert(i + 2, new CodeInstruction(OpCodes.Ceq));
}
}
// Add the isPauseVisible check here
codes.Insert(0, new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(AssistantToTheAssistantPatchManager), nameof(isPauseVisible))));
codes.Insert(1, new CodeInstruction(OpCodes.Brfalse_S, codes[codes.Count - 1].labels[0]));
return codes.AsEnumerable();
}
so im very intricately changing the harmony patch to use Transpilers instead of Prefixes
since transpilers modify the IL code instead of C#
and its working
but i need to completely disable all the dumb messages that game pause has, which is 3 separate ways it works, so i have to stop all 3
i cant just sto p one
dumb.
lol
but if i can get the game pause to toggle off and on and it works correctly with the GUI and the escape button works, ill release v0.2.2 today
First! 😛
sticks tongue out
Why you would want to subscribe to my videos is beyond me... You guys are nuts!
This is frankly amazing to me. I've heard Lux and Munix talk of transpilers and harmony patches, but I'm honestly clueless about those. Now here you are killing it! You're gonna put punters like me to shame...
and me
Honestly though, this is what makes the modding society great. I think any one of us on our own would be having less fun and getting less done than we do collaborating and learning from each other.
I secretly wish the KSP forum were like this... God, that place is overrun with whiners.
But here, when we find a problem with the game we turn it into an opportunity for a new mod!
lol
transpilers = hell BUT i have it functioning
its just not working how i thought because i keep getting null values returned
mainly my mainPlugin is returning null
I can figure out a transpiler but i cant undrerstand how to set a value to things
ArgumentException: Value does not fall within the expected range.
at ToggleNotifications.ToggleNotificationsPlugin.OnGUI () [0x00036] in C:\Users\nicho\source\repos\Toggle-Notifications\Toggle NotificationsProject\ToggleNotificationsPlugin.cs:116
this.windowRect = GUILayout.Window(
thats line 116
need to see all the arguments in that method call
private void OnGUI()
{
if (!isGUIVisible)
return;
TNStyles.Init();
WindowTool.CheckMainWindowPos(ref windowRect, windowWidth);
GUI.skin = TNBaseStyle.Skin;
this.windowRect = GUILayout.Window(
GUIUtility.GetControlID(FocusType.Passive),
this.windowRect,
MainUI.FillWindow, // Call the FillWindow method of the MainUI instance
"<color=#696DFF>TOGGLE NOTIFICATIONS</color>",
GUILayout.Height(0.0f),
GUILayout.Width((float)this.windowWidth),
GUILayout.MinHeight(400) // Adjust the value to your desired height
);
saverectpos();
}
also using transpilers and moving everything UI related to the UI class has dramatically imrpoved how smooth the mod runs
public override void OnInitialized()
{
TNBaseSettings.Init(SettingsPath);
base.OnInitialized();
Instance = this;
Logger = base.Logger;
Logger.LogInfo("Loaded");
///MainUI = new ToggleNotificationsUI(this, isGUIVisible);
game = GameManager.Instance.Game;
// Register Flight AppBar button
Appbar.RegisterAppButton(
its cause i commented out the MainUI in oninit
heh
[Info : Unity Log] Initial isWindowOpen value: True
[Info :Toggle Notifications] Update: Toggle Notifications UI toggled with hotkey
[Warning: Unity Log] UnityEngine.GUISkin must be instantiated using the ScriptableObject.CreateInstance method instead of new GUISkin.
[Info : Unity Log] custom styles is null
[Error : Unity Log] mainPlugin or mainPlugin.notificationToggle is null
[Info : Unity Log] [Simulation] [UniverseTime] Pause State changed to: True
[Info : Unity Log] [Simulation] [UniverseTime] Time Scale Changed to physics:0.000, multiplier:1.000, universe:0.000
notificationToggle = new NotificationToggle(this, new Dictionary<NotificationType, bool>()
{
{ NotificationType.GamePauseToggledMessage, true },
{ NotificationType.PauseStateChangedMessageToggle, true },
{ NotificationType.SolarPanelsIneffectiveMessage, false },
});
// configuration
tnConfig = Config.Bind("Notification Settings", "Toggle Notifications", defaultValue, "Toggle Notifications is a mod that allows you to enable or disable notifications");
defaultValue = tnConfig.Value;
tnConfig.Value = true;
AssistantToTheAssistantPatchManager.ApplyPatches(notificationToggle);
MainUI = new ToggleNotificationsUI(this, isGUIVisible);
see if that fixes it
GameInstance gameInstance = FindObjectOfType<GameInstance>(); // Get the GameInstance object
MessageCenter messageCenter = gameInstance.Messages; // Access the MessageCenter instance
THAT is how you can access the message center and get an INSTANCE of message center
noooo
holy crap I had to go hunting in the code to find that shit
don't do that
why not?
the plugin class literally gives you a GameInstance object
I mean the first line
doesnt work
so in order to find a gameinstance of message center thats how i have to do it
that's not how it works
cause i tried to do FindObjectOfType<MessageCenter>
you don't get a "gameinstance of message center"
Messages is a property on an object of type GameInstance
internal ToggleNotificationsUI(ToggleNotificationsPlugin mainPlugin, bool isGUIVisible, MessageCenter messageCenter)
{
if (mainPlugin != null && messageCenter != null)
{
instance = this;
this.mainPlugin = mainPlugin;
this.mainPlugin.isGUIVisible = isGUIVisible;
this.mainPlugin.messageCenter = messageCenter;
tabs = new TabsUI();
tabs.Init();
}
else
{
Debug.LogError("ToggleNotificationsPlugin instance or MessageCenter is null. ToggleNotificationUI");
}
}
public override void OnInitialized()
{
TNBaseSettings.Init(SettingsPath);
base.OnInitialized();
Instance = this;
Logger = base.Logger;
Logger.LogInfo("Loaded");
game = GameManager.Instance.Game;
MessageCenter messageCenter = game.Messages;
messageCenter = game.Messages;
MainUI = new ToggleNotificationsUI(this, isGUIVisible, messageCenter);
tahts what i have
don't even need to do GameManager.Instance.Game
your plugin class has an object called Game
that's the GameInstance object
as well
so all you need to get the messages is Game.Messages
internal ToggleNotificationsUI(
ToggleNotificationsPlugin mainPlugin,
bool isGUIVisible)
{
if (mainPlugin != null)
{
instance = this;
this.mainPlugin = mainPlugin;
this.mainPlugin.isGUIVisible = isGUIVisible;
// Find the MessageCenter component in the scene
MessageCenter messageCenter = GameObject.FindObjectOfType<MessageCenter>();
if (messageCenter != null)
{
this.mainPlugin.messageCenter = messageCenter;
tabs = new TabsUI();
tabs.Init();
}
else
{
Debug.LogError("MessageCenter component not found in the scene. ToggleNotificationUI");
}
}
else
{
Debug.LogError("ToggleNotificationsPlugin instance is null. ToggleNotificationUI");
}
}
I tried this, and it didnt work
which makes sense
now
yes, because MessageCenter is not a GameObject
yup
found that out
game = GameManager.Instance.Game;
messageCenter = game.Messages;
MainUI = new ToggleNotificationsUI(this, isGUIVisible, messageCenter);
thats what ive reduced it to
the issue is that this doesnt work
and like I said, you can reduce it to
messageCenter = Game.Messages;
MainUI = new ToggleNotificationsUI(this, isGUIVisible, messageCenter);
[Error : Unity Log] messageCenter is null
which part?
it comes up null
every way I've tried so far, messageCenter is null because I can't get access to it
so even though that compiles, it doesnt actualy work
internal ToggleNotificationsUI(ToggleNotificationsPlugin mainPlugin, bool isGUIVisible, MessageCenter messageCenter)
{
if (mainPlugin != null && messageCenter != null)
{
instance = this;
this.mainPlugin = mainPlugin;
this.mainPlugin.isGUIVisible = isGUIVisible;
this.mainPlugin.messageCenter = messageCenter;
tabs = new TabsUI();
tabs.Init();
}
else
{
Debug.LogError("ToggleNotificationsPlugin instance or MessageCenter is null. ToggleNotificationUI");
}
}
public override void OnInitialized()
{
TNBaseSettings.Init(SettingsPath);
base.OnInitialized();
Instance = this;
Logger = base.Logger;
Logger.LogInfo("Loaded");
game = GameManager.Instance.Game;
messageCenter = game.Messages;
MainUI = new ToggleNotificationsUI(this, isGUIVisible, messageCenter);
// Register Flight AppBar button
Appbar.RegisterAppButton(
"Toggle Notifications",
ToolbarFlightButtonID,
AssetManager.GetAsset<Texture2D>($"{this.SpaceWarpMetadata.ModID}/images/icon.png"),
isOpen =>
{
ToggleButton(isOpen, isOpen);
Debug.Log($"Initial isWindowOpen value: {interfaceEnabled}");
}
);
notificationToggle = new NotificationToggle(this, new Dictionary<NotificationType, bool>()
{
{ NotificationType.GamePauseToggledMessage, true },
{ NotificationType.PauseStateChangedMessageToggle, true },
{ NotificationType.SolarPanelsIneffectiveMessage, false },
});
// configuration
tnConfig = Config.Bind("Notification Settings", "Toggle Notifications", defaultValue, "Toggle Notifications is a mod that allows you to enable or disable notifications");
defaultValue = tnConfig.Value;
tnConfig.Value = true;
AssistantToTheAssistantPatchManager.ApplyPatches(notificationToggle);
}
now im going to run it and see what error pops up
I kinda don't understand why you're setting this.mainPlugin.messageCenter = messageCenter; inside the ToggleNotificationUI class, which you create from the plugin class itself
you can just do that directly in the plugin class before you create the ToggleNotificationUI object
still learning so if i do things that are weird thats why
im simply trying to get this to work and when i get it to compile and i get errors i try to fix them
later on i try to figure out how to shorten and clean up the code
but the priority i have is getting it to function
internal ToggleNotificationsUI(ToggleNotificationsPlugin mainPlugin, bool isGUIVisible, MessageCenter messageCenter)
{
if (mainPlugin != null && messageCenter != null)
{
instance = this;
tabs = new TabsUI();
tabs.Init();
}
else
{
Debug.LogError("ToggleNotificationsPlugin instance or MessageCenter is null. ToggleNotificationUI");
}
}
basically what you do now is:
- get an instance of MessageCenter and assign it to
yourPluginClassInstance.messageCenter - create an instance of ToggleNotificationUI and pass
yourPluginClassInstance.messageCenterto it - inside the constructor of ToggleNotificationUI, you assign
yourPluginClassInstance.messageCentertoyourPluginClassInstance.messageCenter
thats what i was trying to do is get an instance, i finaly got an instance which mean si can make it not null
i didnt realize i had wrote a bunch of redundant code
and it oculd be simplified
i just knew it was working and now i needed ot make the value not null
so i thought i would share how i got the instance for KSP.Messages to be created since it was a pain in the ass to get for me
which hindsight, probably very easy for experienced people to do
honestly, with most of these game-wide systems, you always want to look through the members of GameManager and GameInstance, and chances are you'll find it there
good to know
i went from the end and searched all the way back
also i hate how they designed the notification system
its like a spider web of doom
thats solved, thank you for the help
sorry if i came off as brash or whatever
also a few more nulls to remove and create instances for. seems to be a trend with my code. i never create an instance for things
UnityEngine.GUISkin must be instantiated using the ScriptableObject.CreateInstance method instead of new GUISkin.
custom styles is null
wait so how did you resolve MessageCenter coming up as null?
oh
haha
here
internal ToggleNotificationsUI(ToggleNotificationsPlugin mainPlugin, bool isGUIVisible, MessageCenter messageCenter)
{
if (mainPlugin != null && messageCenter != null)
{
instance = this;
this.messageCenter = messageCenter;
tabs = new TabsUI();
tabs.Init();
}
else
{
Debug.LogError("ToggleNotificationsPlugin instance or MessageCenter is null. ToggleNotificationUI");
}
}
then in the oninit in my plugin
tbh I just tested getting it in OnInitialized and got it just fine
public override void OnInitialized()
{
TNBaseSettings.Init(SettingsPath);
base.OnInitialized();
Instance = this;
Logger = base.Logger;
Logger.LogInfo("Loaded");
game = GameManager.Instance.Game;
messageCenter = game.Messages;
MainUI = new ToggleNotificationsUI(this, isGUIVisible, messageCenter);
// Register Flight AppBar button
Appbar.RegisterAppButton(
"Toggle Notifications",
ToolbarFlightButtonID,
AssetManager.GetAsset<Texture2D>($"{this.SpaceWarpMetadata.ModID}/images/icon.png"),
isOpen =>
{
ToggleButton(isOpen, isOpen);
Debug.Log($"Initial isWindowOpen value: {interfaceEnabled}");
}
);
notificationToggle = new NotificationToggle(this, new Dictionary<NotificationType, bool>()
{
{ NotificationType.GamePauseToggledMessage, true },
{ NotificationType.PauseStateChangedMessageToggle, true },
{ NotificationType.SolarPanelsIneffectiveMessage, false },
});
// configuration
tnConfig = Config.Bind("Notification Settings", "Toggle Notifications", defaultValue, "Toggle Notifications is a mod that allows you to enable or disable notifications");
defaultValue = tnConfig.Value;
tnConfig.Value = true;
AssistantToTheAssistantPatchManager.ApplyPatches(notificationToggle);
// Create an instance of ToggleNotificationsUI and pass the messageCenter instance to it
ToggleNotificationsUI toggleNotificationsUI = new ToggleNotificationsUI(this, isGUIVisible, messageCenter);
}
so I'm not sure where the issue was
so thats what i did and now i dont get the messagecenter is null
Is that the effect you're going for? Seems a bit off to me.
Also, unrelated question to this mod... Is there a way to pan/zoom/rotate camera view in mapview mode that doesn't involve using the mouse? Something with the keyboard perhaps?
yes
but i dont remember how but there are hotkeys binded in the game that let you mess with the camera
i could be compeltely wrong
its off because i need to fix the logic
so im finally able to control the notificaiton but i need to swap the logic
so that when its enabled it doesnt show and when its disabled it shows the notif
cause thats the whole point, Toggle Notifications
I've looked at the key bindings, and maybe I'm blind, but there seem to be none to change the map view camera orientation from they keyboard. Like seriously none. As in a major and completely perplexing oversight on the part of the KSP2 UI. You know, the kind we may need a mod for...
It's constantly erroring btw
Weird. I'm not getting errors with it.
I was in the VAB...yep I forgot to mention that
You may want to check the game state and prevent operating in the VAB or other places where the messages you're looking to disable are not possible.
you mean like this? 
happens every time I load into this save which is in VAB
Yeah, like that! Preciesely!
I mean the pause/unpause notification probably shouldn't be happening in the VAB
but I'd say that that's the only thing that is for sure
but the exception seems to be coming from the TN UI anyway
If a mod is throwing NREs in the VAB and not elsewhere, then I'd think look first at what the NREs are coming from, but consider if limiting based on games state makes sense.
yeah that was kinda my point, seems like they happen in the VAB, too
yup didnt check it in the vab
private void OnGUI()
{
_isGUIenabled = false;
GameState? state = BaseSpaceWarpPlugin.Game?.GlobalGameState?.GetState();
GameState? nullable = state;
GameState gameState1 = GameState.Map3DView;
if (nullable.GetValueOrDefault() == gameState1 & nullable.HasValue)
_isGUIenabled = true;
nullable = state;
GameState gameState2 = GameState.FlightView;
if (nullable.GetValueOrDefault() == gameState2 & nullable.HasValue)
_isGUIenabled = true;
//game.Messages = GameManager.Instance?.Game?.Messages?.Subscribe<DiscoverableMessage>(message =>
if (_isGUIenabled)
{
TNStyles.Init();
WindowTool.CheckMainWindowPos(ref windowRect, windowWidth);
GUI.skin = TNBaseStyle.Skin;
this._activeVessel = GameManager.Instance?.Game?.ViewController?.GetActiveVehicle(true)?.GetSimVessel();
if (!this._interfaceEnabled || !this._isGUIenabled || this._activeVessel == null)
return;
this.windowRect = GUILayout.Window(
GUIUtility.GetControlID(FocusType.Passive),
this.windowRect,
MainUI.FillWindow,
"<color=#696DFF>TOGGLE NOTIFICATIONS</color>",
GUILayout.Height(0.0f),
GUILayout.Width((float)this.windowWidth),
GUILayout.MinHeight(400) // Adjust the value to your desired height
);
saverectpos();
//tooltips
UIFields.CheckEditor();
}
}
ohh
okay yeah, that i havent figured out
i get a few notifications right away when i load in
thats on my "to fix list"
now i undersatnd what ya'll are talking about
bool gamePauseToggle = GUI.Toggle(new Rect(3, 56, buttonWidth, 20), isToggled, "Game Pause", selectedButton2 == 1 ? TNBaseStyle.Toggle : TNBaseStyle.ToggleError);
TNBaseStyle.Toggle.normal.textColor = selectedButton1 == 1 ? ColorTools.ParseColor("#C0C1E2") : ColorTools.ParseColor("#C0E2DC");
TNBaseStyle.ToggleError.normal.textColor = selectedButton1 == 0 ? Color.red : ColorTools.ParseColor("#C0E2DC");
if (gamePauseToggle != isToggled)
{
isToggled = gamePauseToggle;
ButtonToggle1(gamePauseToggle ? 1 : 0);
}
cool... glad I didn't review this
selectedButton2? KEKW
Right click maybe?
ive made four buttons, 3 of them dont do anything right now
so selectedButton2 is the placeholder for the solar notification
but it doesnt do anything
other than turn itself on and off
but its not controlling anything, its just UI
but now
when i click on my UI and toggle it on and off, i dont toggle the game pause on and off anymore
also do we need to do this?
[Warning:Space Warp] The swinfo.json "mod_id" property is deprecated and will be removed in a future version. Instead of ModID, use PluginClass.Info.Metadata.GUID in your code.
[Info :spacewarp/modlist/modlist.uss] registering path "spacewarp/modlist/modlist.uss"
PluginClass.Info.Metadata.GUID
Looking good!
Still can't turn the notification back on yet. 🤣
//Solar Panel Patches
[HarmonyPatch(typeof(NotificationEvents))]
internal static class SolarPanelsIneffectiveMessagePatch
{
[HarmonyTranspiler]
[HarmonyPatch("SolarPanelsIneffectiveMessage")]
internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
Logger.LogInfo("Transpiler Loaded for SolarPanelsIneffectiveMessage in NotificationEvents");
return TranspilerLogic(instructions);
}
}
got it working, so now solarpanelineffective is blocked. but i cant reenable them yet
that sokay, ill get it working slowly
0.2.3 is adding hopefully all of these. solar panels is working now
[Known Issues]
Game Pause Button:
Issue: The game pause button is always disabled regardless of whether you toggle it on or off.
Possible cause: The logic in the GamePauseButtonToggle method may not be correctly updating the relevant variables.
Solution: Review the implementation of the GamePauseButtonToggle method and ensure that it correctly updates the variables related to the game pause functionality. Make sure that the correct values are being assigned to mainPlugin.notificationToggle.CheckCurrentState and AssistantToTheAssistantPatchManager based on the toggle value.
Solar Panel Ineffective Button:
Issue: The solar panel ineffective button is always enabled regardless of whether you toggle it on or off.
Possible cause: The logic in the ButtonToggle2 method may not be correctly updating the relevant variables.
Solution: Review the implementation of the ButtonToggle2 method and ensure that it correctly updates the variables related to the solar panel ineffective functionality. Make sure that the correct values are being assigned to mainPlugin.notificationToggle.CheckCurrentState and AssistantToTheAssistantPatchManager based on the toggle value.
"I'm just going to organize and clean up the code a bit, and focus on functionality. I'm not going to add more features or buttons..."
Okay so now when you lose sunlight on your solar panels they don't display the part ineffective anymore. They autoadjust
[Info : HarmonyX] Running ILHook manipulator on void KSP.Game.NotificationEvents::SolarPanelsIneffectiveMessage(KSP.Messages.MessageCenterMessage msg)
[Info : HarmonyX] Transpiling void KSP.Game.NotificationEvents::SolarPanelsIneffectiveMessage(KSP.Messages.MessageCenterMessage msg)
[Info : HarmonyX] Running transpiler static System.Collections.Generic.IEnumerable<HarmonyLib.CodeInstruction> ToggleNotifications.AssistantToTheAssistantPatchManager+SolarPanelsIneffectiveMessagePatch::Transpiler(System.Collections.Generic.IEnumerable<HarmonyLib.CodeInstruction> instructions)
[Info :AssistantToTheAssistantPatchManager] Transpiler Loaded for SolarPanelsIneffectiveMessage in NotificationEvents
success
LOL, you and the dating sim...
I'd put that under experimental features if I were you.
LUL
i totally forgot about that
and i just pushed the 0.2.3 update
Toggle Notifications devlog [0.2.4-dev]
you can share mods in intercept again. probably a good idea to announce updates
thats the plan. but i added the wrong .DLL so im fixing that right now
lol rip
Really? All those? Fantastic dude!
Getting tricky testing these lol
out of comm range isnt functioning properly. but thats because it works how game pause does and has multiple ways it sends its notification
solar panel is straightforward and easy same as out of electricity
lost control im having issues getting properly patched but should ahve it all sorted out for 0.2.4
game pause will probably stay disabled by default until later on
once i figured out solar panel the other ones came easily
its just identifying if a notification has one route or multiple.
rule of thumb:
if it only uses notificationevents its pretty easy to patch
if it uses notificationevents and messagecenter
its a pain
but i finally undersatnd what im doing, which is super fun. also trying to get the windows to auto-space themselves. it works but only if every UI element is it's own OnGUI
GUILayout.BeginVertical();
GUILayout.FlexibleSpace();
GUILayout.BeginVertical(GUILayout.Height(60));
int buttonWidth = Mathf.RoundToInt(mainPlugin.windowRect.width - 12); // Subtract 3 on each side for padding
int buttonHeight = 20;
int buttonSpacing = 10;
int currentY = 56;
gamePauseButton.OnGUI();
currentY += buttonHeight + buttonSpacing;
GUILayout.EndVertical();
// Group 3: Version Number
GUIStyle nameLabelStyle = new GUIStyle()
{
border = new RectOffset(3, 3, 5, 5),
padding = new RectOffset(3, 3, 4, 4),
overflow = new RectOffset(0, 0, 0, 0),
normal = { textColor = ColorTools.ParseColor("#C0C1E2") },
alignment = TextAnchor.MiddleRight
};
GUILayout.FlexibleSpace();
GUILayout.Label("v0.2.4", nameLabelStyle);
GUILayout.Box(GUIContent.none, TNBaseStyle.Separator);
mainPlugin.windowRect.height = currentY + buttonHeight + buttonSpacing;```
GUI.DragWindow(new Rect(0.0f, 0.0f, 10000f, 500f));
if (Event.current.type == EventType.MouseUp)
{
mainPlugin.saverectpos();
}
mainPlugin.windowRect.height = currentY + buttonHeight + buttonSpacing;
this may work better
it helps if I'd enable these when i initialize the plugin
notificationToggle = new NotificationToggle(this, new Dictionary<NotificationType, bool>()
{
{ NotificationType.GamePauseToggledMessage, true },
{ NotificationType.SolarPanelsIneffectiveMessage, true },
{ NotificationType.CannotPlaceManeuverNodeWhileOutOfFuelMessage, true },
{ NotificationType.VesselOutOfElectricity, true },
{ NotificationType.VesselLostControlMessage, true },
{ NotificationType.VesselLeftCommunicationRangeMessage, true },
{ NotificationType.CannotChangeNodeWhileOutOfFuelMessage, true },
});
i only had gamepausetoggledmessage and solarpanelsineffective set. which is why none of the new notifications were working
now it works
I learned how to mod in 3 weeks. This is where it's at currenlty.
0.2.4 will be released this week sometime. Cheers
Excellent video! Really shows off the glorious absence of obtrusive notices. If you're gonna give your builds names, then ChatGPT suggested this... G.O.N.E. - "Gone, Obviating Numerous Entities"
LUL
Patch notes:
*added settings page to view status of notifications
**added these notifications:
-CannotPlaceManeuverNodeWhileOutOfFuelMessage
-VesselOutOfElectricity
-VesselLostControlMessage
-VesselLeftCommunicationRangeMessage
-CannotChangeNodeWhileOutOfFuelMessage
**reorganized mod and pathing
**removed unused code
0.2.5 Update:
**All Notifications are able to be enabled/disabled properly
[x] - Game Pause
[x] - Solar
[x] - Electricity
[x] - commrange
[ ] - outoffuel
[ ] - vessel lost control
two more to fix, then 0.2.5 is released
@junior iris when you get a chance, I wanted your help making sure I installed and setup unity correctly with thunderkit etc. Next mod I make I want to make a simple model to learn. It won't be a mod I release, just more of learning how to make something simple, add it into the game, and it function properly.
Obviously dw 🤞🤞 munix is making a template for that btw
Toggle Notifications 0.2.5 will be coming out in the next week or so. Still testing making sure the notifications are turned on and off properly and don't cause havoc
Cry havoc, and release the dogs of Toggle Notifications 0.2.5!
Who let the dogs out? Who? Who? Who?