C# - Fallout4's Four Dragon - Bypassing Unhandled Exceptions? - c#

Previous thread, in case y'all are curious.
Background info: Four Dragon is a C# wrapper for Fallout 4, allowing the use of C# scripts to modify the game, as well as allowing use of Papyrus (Skyrim and Fallout 4's scripting language) functions in the same C# script. The potential! THE POSSIBILITIES!
I concocted a script that runs the Papyrus functions GetPlayerGrabbedRef() and SetMotionType, which are used to make an in-game object freeze in place. Thanks to Metro Smurf, the script is much easier to read.
However, there is a rather...Blatant problem. The script registers for the F6 and F7 keys, but when F6 is pressed and the GetPlayerGrabbedRef() function is called, when the player has not grabbed a reference (a moveable in-game object), the following exception is outputted, causing the game to promptly exit:
FATAL ERROR Unhandled exception while executing FyTyTest.FreezeObject Void OnStaticTick()
Now, I've done some reading on how to handle unhandled exceptions, allowing the program (the Fallout 4 game in this case) to continue operation without closing via the try and catch functions, but I've not had any success; the exception still occurs, causing the game to exit when "OK" is clicked.
Alas, the various .log files that are outputted show no issue; it's as if everything functioned correctly.
Here is the latest incarnation of the script:
using System;
using System.Collections.Generic;
using Fallout;
public class FreezeObject : ScriptObject
{
public FreezeObject() { }
bool bGotObject = false;
ObjectReference ItemReference;
ObjectReference EmptyReference;
int itemValue;
public override void OnStaticTick()
{
base.OnStaticTick();
bool isF6 = Fallout.Keyboard.IsKeyJustUp(System.Windows.Forms.Keys.F6);
bool isF7 = Fallout.Keyboard.IsKeyJustUp(System.Windows.Forms.Keys.F7);
if(isF6)
{
try
{
ItemReference = Game.GetPlayerGrabbedRef();
itemValue = ItemReference.GetGoldValue();
if(ItemReference = EmptyReference)
{
// nothing else to do if we have a null reference
return;
}
}
catch
{
ItemReference = EmptyReference;
itemValue = -1;
return;
}
if (itemValue > -1)
{
bGotObject = true;
}
// nothing else to do; the next block is for F7
return;
}
if(isF7 && bGotObject && ItemReference != EmptyReference && itemValue > -1)
{
ItemReference.SetMotionType(2, true);
bGotObject = false;
}
}
}
So aye. How do I go about stopping an unhandled exception from crashing the game? Or is that just not possible?
Edit: As per Corey's suggestion, I put the try...catch functions around all the function-y code...No dice; the exception still appears, closing the game once the exception message is closed.
Here's the new script:
using System;
using System.Collections.Generic;
using Fallout;
public class FreezeObject : ScriptObject
{
public FreezeObject() { }
bool bGotObject = false;
ObjectReference ItemReference;
ObjectReference EmptyReference;
int itemValue;
public override void OnStaticTick()
{try
{
base.OnStaticTick();
bool isF6 = Fallout.Keyboard.IsKeyJustUp(System.Windows.Forms.Keys.F6);
bool isF7 = Fallout.Keyboard.IsKeyJustUp(System.Windows.Forms.Keys.F7);
if(isF6)
{
ItemReference = Game.GetPlayerGrabbedRef();
itemValue = ItemReference.GetGoldValue();
if(ItemReference == EmptyReference)
{
// nothing else to do if we have a null reference
return;
}
if (itemValue > -1)
{
bGotObject = true;
}
// nothing else to do; the next block is for F7
return;
}
if(isF7 && bGotObject && ItemReference != EmptyReference && itemValue > -1)
{
ItemReference.SetMotionType(2, true);
bGotObject = false;
}
}
catch
{
}
}
}

Four Dragon hosts its own AppDomain for the purpose of loading and executing user scripts. I haven't had many opportunities to work with custom hosts, so I don't know for sure, but I believe hosts have some control over the exception handling behavior. Assuming I'm right, I'd guess at that being the cause for your weird exception handling issues.
Your best best is to address the actual cause of the exceptions. In your code, you're checking for a null reference after you've already attempted to access a method on the object. You might want to try this:
if(isF6)
{
ItemReference = Game.GetPlayerGrabbedRef();
if(ItemReference != null && ItemReference.HandleExists())
{
itemValue = ItemReference.GetFormID();
if (itemValue != 0)
{
bGotObject = true;
}
}
// nothing else to do; the next block is for F7
return;
}
I changed your GetGoldValue() call to GetFormID() since you're using it to establish whether you've got a valid ObjectReference.
If you still have issues, I'd try to storing the form ID and using Game.GetForm(formid) to reacquire an object reference in the F7 block. You're relying on the assumption that the object reference remains valid between calls to OnStaticTick, which may not necessarily be the case. (still digging through Four Dragon's implementation, so I'm still unsure)
Edit: Disregard - object references apparently stay valid between events.

Related

How to restrict my code to only fire my methods once and not constantly if the condition is met?

so i have an adrduino that sends me data constantly, I made it Json data. so arduino sends me [0,0,0,0] constantly and the 0 changes depending on the condition in the arduino. My Issue is, in my c# im reading this arduino data and i'm using it, however my methods keeps on firing because the conditions are met. i want it to just fire once if the value is changed and that's all. for example if i get from arduino [0,2,0,0] i want it to update and if stays 2 i don't want my method to fire unless it's back to 0 again.
This is my c# code where i read the data
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) {
var str = serial.ReadLine();
outputStr = str;
//intvalue = int.Parse(str);
try{
var json = JSON.Parse(str);
FirstSet = int.Parse(json[0].Value); // can be either 0 or 1
SecondSet = int.Parse(json[1].Value);// can be either 0 or 2
ThirdSet = int.Parse(json[2].Value);// can be either 0 or 3
ForthSet = int.Parse(json[3].Value);// can be either 0 or 4
}catch(Exception ex){
VLog.Info("EXCEPTION!: " + ex.Message);
}
// Set 1
if (FirstSet == 1)
On1();
else if (FirstSet == 0)
Off1();
// Set 2
if (SecondSet == 2)
On2();
else if (SecondSet == 0)
Off2();
// Set 3
if (ThirdSet == 3)
On3();
else if (ThirdSet == 0)
Off3();
// Set 4
if (ForthSet == 4)
On4();
else if (ForthSet == 0)
Off4();
changed = true;
}
some basic validation?
above the class:
private string lastParsed;
inside the class start with:
if (lastParsed != null && lastParsed == str)
{
return;
}
else
{
lastParsed = str;
}
EDIT: looks like you deleted your original code, but if you want to check only one of the int values for each sensor perhaps you could try another approach
above method:
private bool[] sensorState = new bool[4];
I don't remember exactly how you called the On & Off methods but in each IF and ELSE IF you could add
if (first == 0 && sensorState[0]) // it means you should switch OFF and it's currently ON
else if (first == 1 && !sensorState[0]) // it means you should switch ON and it's currently OFF
EDIT:
after each if/else block you update the sensorState
if (first != 0)
sensorState[0] = true;
else
sensorState[0] = false;
and so on..
You probably want to look into Event Handlers. Specifically when properties change. You're already using event handlers for when data is received as a SerialDataReceivedEvent, now you're adding another layer on top of it to handle if the value changes.
The basic concept is you build a class that is responsible for reading your Arduino inputs. Use Task.Run() to monitor on another thread so it doesn't lock your main process. That class will have an event handler in it that you will call from within your monitor class.
When your app instantiates this monitoring object, it will then register an action to that event handler.
This answer lays out a modern version of a class with a PropertyChangedEventHandler. That class should be the monitor that is checking the sensor. Then if the property changes, it will fire the event handler that your main program has registered with.
If I use the example from that answer, here's what your program might look like:
class Program
{
public ISensorMonitor Sensor1 { get; }
public ISensorMonitor Sensor2 { get; }
public ISensorMonitor Sensor3 { get; }
public ISensorMonitor Sensor4 { get; }
static void Main(string[] args)
{
// In this example Sensor1Monitor would implement ISensorMonitor
Sensor1 = new Sensor1Monitor();
Sensor1.PropertyChanged += DoSomethingWithSensor1;
Sensor1.StartMonitoring();
// ... implement the other 3 sensors.
}
void DoSomethingWithSensor1(object sender, PropertyChangedEventArgs e)
{
// This ensures that only the SensorValue property will handled.
if (e.PropertyName != nameof(ISensorMonitor.SensorValue))
return;
// ... Do something with Sensor1.SensorValue
}
// ... implement the other 3 sensors.
}
This will ensure DoSomething() only is called when the value of the monitor's sensor property reading changes.
Consider changing your model first... there is no need to store numbers for an On/Off state, just make your properties bool. Then, if you want to signal changes to the state, just pack it into the property setter instead of trying to be smart in some other area:
class MyContainerIsNotPartOfTheQuestion
{
private bool m_FirstSet;
public bool FirstSet
{
get { return m_FirstSet; }
set
{
if (value != m_FirstSet)
{
m_FirstSet = value;
// handle On/Off where it belongs
if (value) On1();
else Off1();
}
}
}
// same for SecondSet etc.
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// ... your starting code
FirstSet = int.Parse(json[0].Value) != 0;
// set others
// Done, no handling of On/Off here
}
}

Strange behaviour when communicating over serial from VS WPF to Arduino

A basic overview. I am sending serial data from an Arduino Due to WPF application. Up until now this has all been working perfectly. Today I implemented a loop into the Arduino code that looks for a "Y" (ascii 89) in the serial port, if received it leaves the loop and returns back into what I am calling offline mode and stops sending over data, via online = false.
Now what is strange about this is that...
It was working fine before this loop so it must be something to do with trying to resend new data once it has left the 'online loop'.
It works perfectly from the Arduino serial monitor, which suggests it's a WPF problem, although the code hasn't changed on the upload section.
The code for both of these programmes is pretty big so I will try and keep it concise whilst providing all the information necessary.
void loop() {
// Check to see if the testbench is in offline mode and run the respective code.
if (Online == false) {
OfflineMode();
}
// Check to see if the testbench is in online mode and run the respective code.
if (Online == true) {
OnlineMode();
}
}
void OfflineMode() {
while (Serial.available())
processlncomingByte(Serial.read());
}
I then have switch cases to handle incoming settings - I know this works fine as it will also upload after the Arduino is reset.
void processlncomingByte (const byte c) {
if (isdigit (c)) {
currentValue *= 10;
currentValue += c - '0';
} else {
// end of digit
// The end of the number signals a state change
handlePreviousState ();
// set the new state, if we recognize it
switch (c) {
case 'A':
state = GOT_A;
break;
etc...
Online Mode
void OnlineMode() {
CheckForStop();
SendSerialData();
}
void CheckForStop() {
//Serial.println("...");
if (Serial.available() > 0) {
//Serial.println("getting something");
ch = (char)Serial.read();
inputString = ch;
if (ch == 89) {
//Serial.end();
Online = false;
//Serial.begin(9600);
exit;
//return;
}
} else
delay(5);
}
SendSerialData() consists of just a range of serial.print, outputting into one large string for WPF to handle.
Here is a screenshot of the serial monitor working
As you will see from the link above the monitor spits out a load of data, stops when I send a Y and finally I send a Q to 'question' whether the Arduino is ready to receive settings and S signifies a Yes. Great stuff it works!
However as you can see from the link below this isn't the case in WPF. Sorry, I can only upload 2 images at the moment so had to combine them.
Combo of screenshots
Here is the loop it is currently getting stuck in
private bool checkArduinoisReady() {
Stopwatch Uploadtimer = new Stopwatch();
if (!myPort.IsOpen)
return false;
// Debug.Print("port is ready to be opened");
string tempdata;
Uploadtimer.Start();
myPort.DiscardInBuffer();
Start:
myPort.WriteLine("Q" + Environment.NewLine);
Debug.Print("sent Q");
tempdata = myPort.ReadExisting();
Debug.Print("tempdata_" + tempdata.ToString());
if (Uploadtimer.ElapsedMilliseconds > 5000)
return false;
if (tempdata.Contains("S"))
return true;
else
goto Start;
}
And on a separate page this is how I am stopping the incoming data.
private void StopTest(object sender, RoutedEventArgs e) {
MessageBoxResult StopConfirm = MessageBox.Show("Are you sure you want to stop the test?", "Stop the test", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (StopConfirm == MessageBoxResult.Yes) {
Timer.Stop();
Debug.Print("Timer Stopped");
myPort.DiscardInBuffer();
Start:
for (int i = 0; i < 100; i++) {
myPort.WriteLine("Y");
}
string tempData = myPort.ReadExisting();
Debug.Print("Checking...");
Debug.Print("tempData_" + tempData);
if (string.IsNullOrWhiteSpace(tempData)) {
Debug.Print("Its null!!");
comments_textbox.Text = comments_textbox.Text + "Test Aborted";
MessageBoxResult SaveCurrentData = MessageBox.Show("Would you like to save the data collected up until this point?", "Save", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (SaveCurrentData == MessageBoxResult.Yes) {
SaveFile();
}
if (SaveCurrentData == MessageBoxResult.No) {
myPort.Close();
NavigationService.Navigate(new Uri("testSettings.xaml", UriKind.RelativeOrAbsolute));
}
} else {
Debug.Print("Still going...");
goto Start;
}
}
}
The biggest stumbling block for me is why this works over the serial monitor but not within the application. And it also works as soon as I reset the Arduino. I have also tried the resetFunc() in Arduino but this didn't help either.
Thanks in advance.
It turns out i still had a resetFunc() in my switch case which was preventing the serial monitor from continuing to send data!

How to stop execution of if-statement

Hi I want to stop the execution of if-loop ,I have tried with 'return' statement but its exits from the function ,So how can I exit from the single if Statement.I have tried with following code...
Here I want to stop execution of if(CheckHorizontalSide(SourceMember)) and by stopping this I want to move towards the if(CheckTop(SourceMember))
void A()
{
if (CheckHorizontalSide(SourceMember))
{
if (lblHorizontalMember.Text == DestinationMember)
{
lsRelationPath.Add(lblHorizontalMember.Text);
lblRelationPath.Text = String.Join("-", lsRelationPath);
lblRelationPath.Visible = true;
return;
}
bool WhetherContains = lsRelationPath.Contains(SourceMember);
if (WhetherContains)
{
return;
}
//This below code is not related to the above 'WhetherContains '
lsMemberID1.Clear();
lsRelationPath.Add(lblHorizontalMember.Text);
Find_Route(lblHorizontalMember.Text, DestinationMember);
}
if(CheckTop(SourceMember))
{
//code here....
}
}
You put the rest of the block in a sub-block with { } and put else in front of that.
You can nest as deeply as you want but you might try factoring out blocks to helper functions to reduce the complexity and give statements a name.
if (WhetherContains)
{
// this is actually empty
}
else
{
lsMemberID1.Clear();
lsRelationPath.Add(lblHorizontalMember.Text);
}
Or,
if (!WhetherContains)
{
lsMemberID1.Clear();
lsRelationPath.Add(lblHorizontalMember.Text);
}

C# "ref" not Doing what I Think it Should

I have a class that talks to an external .exe. The class has a bunch of similar methods; they call a function of the .exe, wait for response, and then return true or false.
The response comes in the form of events that change the values of fields of this class.
Simplified code:
class Manager
{
private static bool connected = false;
public static bool Connect()
{
runtime.Connect();
int secondsWaited = 0;
while (!connected)
{
Thread.Sleep(1000);
if (secondsWaited++ == 10)
{
return false;
}
}
return true;
}
}
The other methods use the same call-wait-loop-return structure.
My goal is to make a single method to do this waiting for me, like so:
private static bool WaitReferenceEqualsValue<T>(ref T reference, T value)
{
int secondsWaited = 0;
while (!reference.Equals(value))
{
Thread.Sleep(1000);
if (secondsWaited++ == 10)
{
return false;
}
}
return true;
}
Then each method would do:
runtime.DoSomething();
return WaitReferenceEqualsValue<someType>(ref someField, someSuccessfulValue);
However, when I replace the wait-loop with this method call, the field "connected", even though passed in as a reference, always stays the same.
Any idea what's going on here, and how to get the desired functionality?
Thanks in advance.
EDIT:
public static bool Connect()
{
...
runtime.Connect();
// this code works
/*int secondsWaited = 0;
while (connected != true)
{
Thread.Sleep(1000);
if (secondsWaited++ == 10)
{
return false;
}
}*/
// this somehow blocks OnConnect from firing, so connected never gets set to true
lock (typeof(SkypeKitManager))
{
WaitReferenceEqualsValue<bool>(ref connected, true);
}
...
}
OnConnect:
private static void OnConnect(object sender, Events.OnConnectArgs e)
{
if (e != null && e.success)
{
lock (typeof(Manager))
{
connected = true;
}
}
}
You're not doing any synchronization on that field although you access it from multiple threads and one of them is writing. This is a race (no exception! this is a race even if it looks safe. It isn't safe.).
Probably the JIT enregistered it which is a common optimization. It just never gets read from memory, always from a register. Add synchronization (for example a lock, or Interlocked or Volatile methods).
Your usage of ref is correct.
The problem with your code is essentially compiler optimization. Fo optimization purpose compilers (or jits) necessarily take a pretty much single threaded view. The compiler/jit will then notice that you don't touch reference in your code at all, therefore it can move the comparison outside the loop. It is free to do so, since you basically create a race condition (no synchronization/atomic accesses).
Fixing it could either involve using synchronization mechanisms or add the volatile specifier to reference, thus telling the compiler/jit, that the variable can be changed from outside the method.

objects are not null and exception is still raised

Answer: it was in the else code, but I thought there is no reason that code wouldn't point to that line.
Can someone offer an idea how it could be possible that I get "Object reference not set to an instance of an object" on this at Invoke method:
delegate void t(tabdescriptor tab);
internal void AddItem(tabdesciptor tab)
{
if (InvokeRequired)
{
t inv = new t(AddItem);
if (inv != null && tab!= null)
Invoke(inv, tab);
}
else
{
....
}
}
I'm not exactly sure what the actual issue is considering your example cannot be the code that executes, but please try something like this:
internal void AddItem(tabdesciptor tab)
{
if (InvokeRequired)
{
Invoke(new Action<tabdescriptor>(AddItem), tab);
}
else
{
//...
}
}
Also please make sure that it's not actually whatever is in the else part that fails.
If I remember correctly, this exception could be coming from inside the invoked method. If you place a try/catch inside the else of the AddItem method and a breakpoint inside the catch, do you catch the exception?
internal void AddItem(tabdesciptor tab)
{
if (InvokeRequired)
{
t inv = new t(AddItem);
if (inv != null && tab!= null)
Invoke(inv, tab);
}
else
{
try
{
....
}
catch
{
// breakpoint here
}
}
}
It's unclear whether it's a mistake in the given example, or not, but tab is never checked for null, yet it is passed as the argument.
Either it's probably null, or:
Also, inv is checked for null right after creating it (Good in C/C++, but unnecessary in C# as it throws an OutOfMemoryException upon failure), but it is done before checking o for null.

Categories