Background
I am writing a program, which collects different events (key press, mouse position, and others) and sends a single string to a serial port.
There is a small part of the program, where a key is pressed, to control movement (forward - W key; left - A key, Forward-left - WA key).
When an event happens, a method is invoked, which grabs a numeric string and processes in the FinalStringClass Class. On the main form , there is a method, which assigns collected value to a label.
However, I am encountering a problem with code due to lack of experience in programming :(
Main Form:
Serial port;
FinalStringClass fstr;
public Form1()
{
InitializeComponent();
//... Serial port settings
timer.Start();
fstr = new FinalStringClass(UpdateLabel2);
}
public void UpdateLabel2(string x, string y, string speed, string mvm) //
{
label2.Text = "x: " + x + "y: " + y + "speed: " + speed + "mvm: " + mvm;
}
private void timer_Tick(object sender, EventArgs e)
{
var up = KeyboardInfo.GetKeyState(Keys.W);
var down = KeyboardInfo.GetKeyState(Keys.S);
var left = KeyboardInfo.GetKeyState(Keys.A);
var right = KeyboardInfo.GetKeyState(Keys.D);
if (left.IsPressed)
{
if (up.IsPressed == true) // if W and A keys are pressed, ->
{
fstr.mvmMethod("7"); // this method is triggered
return;
}
if (down.IsPressed)
{
fstr.mvmMethod("9");
return;
}
if (right.IsPressed)
{
fstr.mvmMethod("1");
return;
}
fstr.mvmMethod("4"); //if W key is pressed, then this method is triggered
}
//... (other if condition statements)
label2.Text = fstr.FinalStringBuilder();
port.Write(fstr.FinalStringBuilder());
}
External Class:
class FinalStringClass
{
private Action<string, string, string, string> updateLabel2;
Action<String> _x, _y, _speed, _mvm;
string xF, yF, speedF, mvmF;
public FinalStringClass(Action<string, string, string, string> updateLabel2)
{
this.updateLabel2 = updateLabel2;
}
public FinalStringClass(Action<String> x, Action<String> y, Action<String> speed, Action<String> mvm)
{
_x = x;
_y = y;
_speed = speed;
_mvm = mvm;
}
public void xMethod(string x)
{
_x(x);
xF = x;
}
public void yMethod(string y)
{
_y(y);
yF = y;
}
public void speedMethod(string speed)
{
_speed(speed);
speedF = speed;
}
public void mvmMethod(string mvm)
{
_mvm(mvm);
mvmF = mvm;
}
public string FinalStringBuilder()
{
return xF + yF + speedF + mvmF;
}
}
When working with a single parameter, everything works fine. But dealing with multiple parameters causes a problem :(
Example of working with a single parameter (full working code):
Main Form
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace FFApp
{
public partial class Form1 : Form
{
SerialPort port;
MyClass outside;
public Form1()
{
InitializeComponent();
timer.Start();
outside = new MyClass(UpdateLabel);
}
public void UpdateLabel(string str)
{
label1.Text = str;
}
private void init()
{
port = new SerialPort();
port.PortName = "COM1";
port.BaudRate = 115200;
try
{
port.Open();
}
catch (Exception e1)
{
MessageBox.Show(e1.Message);
}
}
public struct KeyStateInfo
{
private Keys key;
private bool isPressed;
private bool isToggled;
public KeyStateInfo(Keys key, bool ispressed, bool istoggled)
{
this.key = key;
isPressed = ispressed;
isToggled = istoggled;
}
public static KeyStateInfo Default
{
get
{
return new KeyStateInfo(Keys.None, false, false);
}
}
public Keys Key
{
get { return key; }
}
public bool IsPressed
{
get { return isPressed; }
}
public bool IsToggled
{
get { return isToggled; }
}
}
private void timer_Tick(object sender, EventArgs e)
{
var up = KeyboardInfo.GetKeyState(Keys.W);
var down = KeyboardInfo.GetKeyState(Keys.S);
var left = KeyboardInfo.GetKeyState(Keys.A);
var right = KeyboardInfo.GetKeyState(Keys.D);
Keyboard kb = new Keyboard();
if (left.IsPressed)
{
if (up.IsPressed == true)
{
outside.MyMethod("7");
return;
}
if (down.IsPressed)
{
outside.MyMethod("9");
return;
}
if (right.IsPressed)
{
outside.MyMethod("1");
return;
}
outside.MyMethod("4");
}
if (right.IsPressed)
{
if (up.IsPressed)
{
outside.MyMethod("6");
return;
}
if (down.IsPressed)
{
outside.MyMethod("8");
return;
}
if (left.IsPressed)
{
outside.MyMethod("1");
return;
}
outside.MyMethod("5");
}
if (up.IsPressed)
{
if (left.IsPressed)
{
outside.MyMethod("7");
return;
}
if (right.IsPressed)
{
outside.MyMethod("6");
return;
}
if (down.IsPressed)
{
outside.MyMethod("1");
return;
}
outside.MyMethod("2");
}
if (down.IsPressed)
{
if (left.IsPressed)
{
outside.MyMethod("9");
return;
}
if (right.IsPressed)
{
outside.MyMethod("8");
return;
}
if (up.IsPressed)
{
outside.MyMethod("9");
return;
}
outside.MyMethod("3");
}
if (!right.IsPressed && !left.IsPressed && !up.IsPressed && !down.IsPressed)
{
outside.MyMethod("1");
}
}
public class KeyboardInfo
{
[DllImport("user32")]
private static extern short GetKeyState(int vKey);
private KeyboardInfo()
{
}
public static KeyStateInfo GetKeyState(Keys key)
{
short keyState = GetKeyState((int)key);
int low = Low(keyState), high = High(keyState);
bool toggled = low == 1;
bool pressed = high == 1;
return new KeyStateInfo(key, pressed, toggled);
}
private static int High(int keyState)
{
return keyState > 0 ? keyState >> 0x10
: (keyState >> 0x10) & 0x1;
}
private static int Low(int keyState)
{
return keyState & 0xffff;
}
}
}
}
Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFApp
{
class MyClass
{
Action<String> labelSetter;
public MyClass(Action<String> labelSetter)
{
this.labelSetter = labelSetter;
}
public string MyProperty { get; set; }
public void MyMethod(string text)
{
labelSetter(text);
MyProperty = text;
}
}
}
Or is it possible within this code, to get changing values (store in a variable), when pressed W/A/D/S/W+A/W+D etc keys in order to allow building final string? ex: string finalstring = x + y + speed + pressed_key;
Related
I am trying to create a Regular Expression system as part of my program. When I pass emailSub (which is a String version of an InputField for the user's email) into other functions within the program, the emailSub goes from the email address (e.g: emailaddress#emailprovider.com) to null (I know this because the output of a Debug.Log before being passed is the email address and Debug.Log-ing it after passing it comes back with " ". This means that when it reaches the length check (IsEmailValid) it is less than 6 characters so all email addresses are rejected as invalid.
How can I fix this problem?
Thanks.
using System.Text.RegularExpressions;
using System.Globalization;
using UnityEngine;
using UnityEngine.UI;
using System;
public class RegEx : MonoBehaviour
{
public InputField emailField;
public Button acceptSubmissionButton;
public string emailSub;
public void Start()
{
var input = gameObject.GetComponent<InputField>();
var se = new InputField.SubmitEvent();
se.AddListener(SubmitName);
input.onEndEdit = se;
}
private void SubmitName(string arg0)
{
Debug.Log(arg0);
emailSub = arg0;
Debug.Log(emailSub);
}
public void Sequencer(string emailSub)
{
Debug.Log(emailSub);
IsEmailValid(emailSub);
Main(emailSub);
}
public static bool IsEmailValid(string emailSub)
{
if (emailSub.Length <= 6)
{
Debug.Log(emailSub + "1");
return false;
}
if (string.IsNullOrWhiteSpace(emailSub))
{
Debug.Log(emailSub + "2");
return false;
}
try
{
emailSub = Regex.Replace(emailSub, #"(#)(.+)$", DomainMapper, RegexOptions.None,
TimeSpan.FromMilliseconds(200));
string DomainMapper(Match match)
{
var idnConversion = new IdnMapping();
var processDomainName = idnConversion.GetAscii(match.Groups[2].Value);
Debug.Log(emailSub + "3");
return match.Groups[1].Value + processDomainName;
}
}
catch (RegexMatchTimeoutException e)
{
return false;
}
catch (ArgumentException e)
{
return false;
}
try
{
Debug.Log(emailSub + "4");
return Regex.IsMatch(emailSub, #"^(([0-9a-z]((\.(?!\.))(?<=[0-9a-z])#))" + #"(([0-9a-z][-0-
9a-z]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$", RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(250));
}
catch (RegexMatchTimeoutException)
{
return false;
}
}
public static void Main(string emailSub)
{
if (RegEx.IsEmailValid(emailSub))
{
Debug.Log($"Valid: {emailSub}");
Debug.Log(emailSub + "5");
}
else
{
Debug.Log($"Invalid: {emailSub}");
Debug.Log(emailSub + "6");
}
}
}
The answer below was written by the person who asked the original question, but they wrote it as a replacement of the question, not in answer.
I fixed the problem, the program takes the contents of a text field and decides whether the text is in a valid email format or not. The problem was that the functions were running before the SubmitName() had updated the contents of arg0. Here is the working code:
using System.Text.RegularExpressions;
using System.Globalization;
using UnityEngine;
using UnityEngine.UI;
using System;
public class RegEx : MonoBehaviour
{
public InputField emailField;
public Button acceptSubmissionButton;
public string emailSub;
public void Start()
{
var input = gameObject.GetComponent<InputField>();
var se = new InputField.SubmitEvent();
se.AddListener(SubmitName);
input.onEndEdit = se;
}
private void SubmitName(string arg0)
{
Debug.Log(arg0);
IsEmailValid(arg0);
ValidCheck(arg0);
}
public void Sequencer(string emailSub)
{
Debug.Log(emailSub);
IsEmailValid(emailSub);
ValidCheck(emailSub);
}
public static bool IsEmailValid(string arg0)
{
if (arg0.Length <= 6)
{
return false;
}
try
{
return Regex.IsMatch(arg0, #"^(?("")("".+?(?<!\\)""#)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])#))" + #"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-0-9a-z]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250)); // The pattern is taken from an article written by Microsoft. https://learn.microsoft.com/en-us/dotnet/standard/base-types/how-to-verify-that-strings-are-in-valid-email-format
}
catch (RegexMatchTimeoutException)
{
return false;
}
}
public static void ValidCheck(string arg0)
{
if (IsEmailValid(arg0))
{
Debug.Log($"Valid: {arg0}");
}
else
{
Debug.Log($"Invalid: {arg0}");
}
}
}
I'm fairly new to C# and am trying to create a web browser for a specific function
I have Form1 (An invisible form) that calls Form2 (The browser) and monitor to make sure Form2 is always running and if it goes idle close and reopen Form2
I think I'm having an issue with threading, which I setup to run the timer (It's the only way I could work out)
I have determined that it only fails to launch Form2 when I try to call the function from inside the thread
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using Browselite;
using System.Diagnostics;
using System.Threading;
namespace BrowseLite
{
public partial class Form1 : Form
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();
public static Boolean IdleTimeoutEnabled { get; private set; }
public static int IdleTimeout { get; private set; }
public static Boolean ClearRunning { get; private set; }
public Form2 Browser { get; private set; }
public static Boolean programmaticClose { get; set; }
public static Boolean Form2Open { get; set; }
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll")]
public static extern Boolean GetLastInputInfo(ref tagLASTINPUTINFO plii);
public struct tagLASTINPUTINFO
{
public uint cbSize;
public Int32 dwTime;
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
using (RegistryKey RootKey = Registry.CurrentUser.OpenSubKey("Software\\Policies\\BrowseLite"))
{
try
{
Form1.IdleTimeout = Int32.Parse(RootKey.GetValue("IdleTimeout", -1, RegistryValueOptions.None).ToString());
if (Form1.IdleTimeout <= 0)
{
Form1.IdleTimeoutEnabled = false;
}
else
{
Form1.IdleTimeoutEnabled = true;
}
}
catch
{
Form1.IdleTimeout = 0;
Form1.IdleTimeoutEnabled = false;
}
}
}
catch
{
Form1.IdleTimeout = 0;
Form1.IdleTimeoutEnabled = false;
}
Thread Timer = new Thread(new ThreadStart(MyTimer));
Browser = new Form2();
OpenBrowser();
Timer.Start();
}
private void MyTimer()
{
while (true)
{
FormCollection OpenForms = Application.OpenForms;
foreach (Form OpenForm in OpenForms)
{
if (OpenForm.Name.Contains("Form2"))
{
Form1.Form2Open = true;
}
}
if (!Form1.Form2Open)
{
Browser.ShowDialog();
Form1.Form2Open = true;
}
tagLASTINPUTINFO LastInput = new tagLASTINPUTINFO();
Int32 IdleTime;
LastInput.cbSize = (uint)Marshal.SizeOf(LastInput);
LastInput.dwTime = 0;
if (GetLastInputInfo(ref LastInput))
{
IdleTime = System.Environment.TickCount - LastInput.dwTime;
int IdleTimeSet = IdleTimeout * 60 * 1000;
if (Form1.IdleTimeoutEnabled)
{
if (IdleTime >= IdleTimeSet)
{
if (Form1.ClearRunning == false)
{
CloseBrowser();
OpenBrowser();
}
}
else
{
Form1.ClearRunning = false;
}
}
}
Thread.Sleep(1000 * 30); //Time in seconds (30)
}
}
private void CloseBrowser()
{
Form1.programmaticClose = true;
Browser.Close();
}
private void OpenBrowser()
{
Form1.programmaticClose = false;
Form1.Form2Open = true;
Browser.ShowDialog();
}
}
}
Any help would be appreciated, but as I said... I'm not good with this.
For anyone else that stumbles onto this, I found the answer myself
If setting a variable in the thread. Instead of using
Form1.Running = true;
instead use
BeginInvoke(new Action(() => Form1.Running = true), null);
And if calling a function from within the thread use
BeginInvoke(new InvokeDelegate(FUNCTION));
This seems to have completely fixed my issue
I have created a test app for my first Windows IoT project with raspberry pi and an ultrasonic sensor.
I have placed some sample code in it. Visual Studio tells me that I am missing a curly bracket in "public void run…", but that doesn't seem to be the problem.
Is it because of the public class within the BackgroundTaskInstance?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Http;
using Windows.ApplicationModel.Background;
using Windows.Devices.Gpio;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409
namespace IoTtest
{
public sealed class StartupTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
public class HCSR04
{
private GpioPin triggerPin { get; set; }
private GpioPin echoPin { get; set; }
private Stopwatch timeWatcher;
public HCSR04(int triggerPin, int echoPin)
{
GpioController controller = GpioController.GetDefault();
timeWatcher = new Stopwatch();
//initialize trigger pin.
this.triggerPin = controller.OpenPin(triggerPin);
this.triggerPin.SetDriveMode(GpioPinDriveMode.Output);
this.triggerPin.Write(GpioPinValue.Low);
//initialize echo pin.
this.echoPin = controller.OpenPin(echoPin);
this.echoPin.SetDriveMode(GpioPinDriveMode.Input);
}
public double GetDistance()
{
ManualResetEvent mre = new ManualResetEvent(false);
mre.WaitOne(500);
timeWatcher.Reset();
//Send pulse
this.triggerPin.Write(GpioPinValue.High);
mre.WaitOne(TimeSpan.FromMilliseconds(0.01));
this.triggerPin.Write(GpioPinValue.Low);
return this.PulseIn(echoPin, GpioPinValue.High);
}
private double PulseIn(GpioPin echoPin, GpioPinValue value)
{
var t = Task.Run(() =>
{
//Recieve pusle
while (this.echoPin.Read() != value)
{
}
timeWatcher.Start();
while (this.echoPin.Read() == value)
{
}
timeWatcher.Stop();
//Calculating distance
double distance = timeWatcher.Elapsed.TotalSeconds * 17000;
return distance;
});
bool didComplete = t.Wait(TimeSpan.FromMilliseconds(100));
if (didComplete)
{
return t.Result;
}
else
{
return 0.0;
}
}
}
}
}
I took the code and reformatted it for you. Please change the namespace to the value you would like
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace MyIotNamespace
{
public sealed class StartupTask :IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
}
}
public class HCSR04
{
private GpioPin triggerPin { get; set; }
private GpioPin echoPin { get; set; }
private Stopwatch timeWatcher;
public HCSR04(int triggerPin, int echoPin)
{
GpioController controller = GpioController.GetDefault();
timeWatcher = new Stopwatch();
//initialize trigger pin.
this.triggerPin = controller.OpenPin(triggerPin);
this.triggerPin.SetDriveMode(GpioPinDriveMode.Output);
this.triggerPin.Write(GpioPinValue.Low);
//initialize echo pin.
this.echoPin = controller.OpenPin(echoPin);
this.echoPin.SetDriveMode(GpioPinDriveMode.Input);
}
public double GetDistance()
{
ManualResetEvent mre = new ManualResetEvent(false);
mre.WaitOne(500);
timeWatcher.Reset();
//Send pulse
this.triggerPin.Write(GpioPinValue.High);
mre.WaitOne(TimeSpan.FromMilliseconds(0.01));
this.triggerPin.Write(GpioPinValue.Low);
return this.PulseIn(echoPin, GpioPinValue.High);
}
private double PulseIn(GpioPin echoPin, GpioPinValue value)
{
var t = Task.Run(() =>
{
//Recieve pusle
while(this.echoPin.Read() != value)
{
}
timeWatcher.Start();
while(this.echoPin.Read() == value)
{
}
timeWatcher.Stop();
//Calculating distance
double distance = timeWatcher.Elapsed.TotalSeconds * 17000;
return distance;
});
bool didComplete = t.Wait(TimeSpan.FromMilliseconds(100));
if(didComplete)
{
return t.Result;
}
else
{
return 0.0;
}
}
}
}
Nested class can't exist inside functions. Place HCSR04 inside StartupTask instead.
See https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/nested-types
So, I am working on a Unity project in which I need to implement client/server functionality.
The client has its own "scene" and the server has its own scene as well. The server code and a networkView are attached to the Main Camera in their scene. The code is as follows:
using UnityEngine;
using System.Collections;
using System.Net;
using System.Collections.Generic;
public class NetworkManagerCS : MonoBehaviour {
public int loadlevel;
public int connectPort = 25000;
public string hostname;
public string GameName = "Historical Grounds";
private bool refreshing;
private HostData[] hostData;
private Dictionary<string, string> playerList = new Dictionary<string, string>();
string textToEdit = "Type text here";
// This is for debuggin purposes only!! Will be deprecated
public void OnGUI() {
if (Network.peerType == NetworkPeerType.Disconnected) {
GUILayout.Label("Connection status: Disconnected");
GUILayout.BeginVertical();
if (GUILayout.Button("Connect as client"))
{
ConnectToServer();
}
if (GUILayout.Button("Start Server"))
{
Network.InitializeServer(4, connectPort, true);
MasterServer.RegisterHost(GameName, "Tutorial Game", "This is a turn based shooter");
//Network.Instantiate(camera, transform.position, transform.rotation, 0);
}
GUILayout.EndVertical();
}
else
{
// Connecting...
if (Network.peerType == NetworkPeerType.Connecting)
{
GUILayout.Label("Connection status: Connecting");
}
// Clientside buttons
else if (Network.peerType == NetworkPeerType.Client)
{
GUILayout.Label("Connection status: Client!");
GUILayout.Label("Ping to server: " + Network.GetAveragePing(Network.connections[0]));
textToEdit = GUILayout.TextField(textToEdit, 25);
if( GUILayout.Button("Attack Server")) {
float[] args = new float[3];
args[0] = float.Parse(textToEdit);
args[1] = 4.123f;
args[2] = 23.2f;
networkView.RPC("AttackServer", RPCMode.AllBuffered, args);
}
}
// Serverside
else if (Network.peerType == NetworkPeerType.Server)
{
GUILayout.Label("Connection status: Server!");
GUILayout.Label("Hostname is:" + System.Net.Dns.GetHostName() );
GUILayout.Label("Connections: " + Network.connections.Length);
}
// Disconnect happens in both server and client
if (GUILayout.Button("Disconnect"))
{
Network.Disconnect(200);
}
}
}
// AKA While(true)
public void Update() {
/*
* If we have a "refreshing" flag, then we poll the master server
* until we get a length larger than 0. Then, we connect to server.
*/
if(refreshing) {
if (MasterServer.PollHostList().Length > 0) {
refreshing = false;
Debug.Log(MasterServer.PollHostList().Length);
hostData = MasterServer.PollHostList();
ConnectToServer();
}
}
}
/*
* If hostData does not exist, refresh
* Otherwise, connect to the first game you see.
*
* This is the "dumb" approach, but I assume that there are not going to be more
* than one game running at a time...
*/
public void ConnectToServer() {
if (hostData == null) {
MasterServer.RequestHostList(GameName);
refreshing = true;
} else {
Network.Connect(hostData[0]);
}
}
/*
* Keeping this here so that I will remember to add system info sends
*/
public void OnConnectedToServer()
{
//Application.LoadLevel(loadlevel);
}
/*
* DEBUG FUNCTION!!! This will be called when someone disconnected from
* the msater server
*/
public void OnDisconnectedFromServer(NetworkDisconnection info) {
if (info == NetworkDisconnection.LostConnection) {
if (Network.peerType == NetworkPeerType.Client) {
Debug.Log ("Client has lost connection");
} else {
Debug.Log ("Server has lost connection");
}
} else {
Debug.Log ("Disconnected Successfully");
}
}
/*
* Lawl, fail....
*/
public void OnFailedToConnect(NetworkConnectionError error)
{
Debug.LogError(error.ToString());
Network.Disconnect(400);
}
/*
* The purpose of this function is to assign a monster to a player
* Once all monsters have been assigned, I guess the Update() function will
* RPC to the phones that they are ready to play.
*/
public void OnPlayerConnected(NetworkPlayer player) {
networkView.RPC("assignPlayer", RPCMode.All, player);
}
/*
* Not interesting... Server initialized..
*/
public void OnServerInitialized()
{
//Application.LoadLevel(loadlevel);
Debug.Log("Server Started");
}
void OnMasterServerEvent(MasterServerEvent msg) {
if (msg == MasterServerEvent.RegistrationSucceeded){
Debug.Log("Registered Server!");
Network.isMessageQueueRunning = true;
}
}
/*void OnPlayerDisconnected(NetworkPlayer player) {
Transform playerTransform = GameObject.Find("Player_" + player.guid);
if (playerTransform != null) {
Destroy (playerTransform.gameObject);
}
Network.RemoveRPCs(player);
Network.DestroyPlayerObjects(player);
}*/
// Testers - Should deprecate
/*[RPC]
public void AttackServer(float[] args) {
foreach (float value in args) {
Debug.Log ("Server is under attack with force " + value);
}
}*/
// RPC's Server Side
[RPC]
public void sendLifeCount(NetworkPlayer player) {
Debug.Log("Sending Life Count to " + player.ipAddress);
}
[RPC]
public void isDead(NetworkPlayer player) {
Debug.Log("You're dead! " + player.ipAddress);
}
[RPC]
public void unlockScreen(NetworkPlayer player) {
Debug.Log("Unlocking screen for.." + player.ipAddress);
}
[RPC]
public void assignPlayer(NetworkPlayer player) {
playerList.Add(player.guid, "1");
Debug.Log(playerList[player.guid]);
Debug.Log("Player connected from: " + player.ipAddress + ":" + player.port);
Debug.Log("The player on IP " + player.ipAddress + " has been assigned the x monster");
}
public Object networkprefab { get; set; }
}
The client on the other hand, is in another scene and its code is here: (no networkView attached, due to problems...
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Text.RegularExpressions;
public center code herelass InputField : MonoBehaviour {
// Client-server bullshit
private int loadlevel;
private HostData[] hostData;
private bool refreshing;
public string GameName = "Historical Grounds";
private bool connected;
public Canvas mainCanvas;
public Canvas gameCanvas;
public Button Connect;
public Text nameFieldInput;
public Text nameField;
public Text Error;
private string userName;
void Awake()
{
if (connected)
{
mainCanvas.enabled = false;
gameCanvas.enabled = true;
}
else {
mainCanvas.enabled = true;
gameCanvas.enabled = false;
}
Debug.Log(connected);
}
public void Update()
{
/*
* If we have a "refreshing" flag, then we poll the master server
* until we get a length larger than 0. Then, we connect to server.
*/
if (refreshing)
{
if (MasterServer.PollHostList().Length > 0)
{
refreshing = false;
Debug.Log(MasterServer.PollHostList().Length);
hostData = MasterServer.PollHostList();
ConnectToServer();
}
}
}
public void onConnect()
{
ConnectToServer();
}
public void OnConnectedToServer()
{
var viewID = Network.AllocateViewID();
}
public void ConnectToServer()
{
if (hostData == null)
{
MasterServer.RequestHostList(GameName);
refreshing = true;
}
else
{
if (Switch())
{
connected = true;
Network.Connect(hostData[0]);
}
}
}
private bool Switch(){
userName = nameFieldInput.text;
Debug.Log(userName);
if(Validate(userName)){
nameField.text = userName;
mainCanvas.enabled = false;
gameCanvas.enabled = true;
connected = true;
return true;
} else {
Error.text = "Invalid name!" + "\n" + "Name should be 2-8 characters and start with a capital letter";
return false;
}
}
private bool Validate(string input){
string pattern = #"^[A-Z][A-Za-z0-9][A-Za-z0-9]+";
Match match = Regex.Match(input, pattern);
if (match.Success)
{
return true;
}
return false;
}
public void OnDisconnectedFromServer(NetworkDisconnection info)
{
if (info == NetworkDisconnection.LostConnection)
{
if (Network.peerType == NetworkPeerType.Client)
{
Debug.Log("Client has lost connection");
}
else
{
Debug.Log("Server has lost connection");
}
}
else
{
Debug.Log("Disconnected Successfully");
}
}
public void OnFailedToConnect(NetworkConnectionError error)
{
Debug.LogError(error.ToString());
Debug.Log("FAIL!");
}
public void OnDisconnectedFromServer()
{
connected = false;
Debug.Log("Lawl Disconnected");
}
}
TL;DR: I keep getting that error message when trying to invoke an RPC ( fire() ) from the client to the server. Anyone know why?
Thanks!!
Instance X of a class register to the change event of instances Y of the same class.
I want to update X if Y is changed, but i dont want to use the static keyword all over the class. Is there a way to transmit the recipient of the event in the eventargs?
Here is some example code with an NUnit tests to illustrate where my problem lies exactly. I compiled and ran it. Two tests just verify the programming. The failing test illustrates my problem.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
namespace Eventtest
{
public class DependencyChain
{
public static int demonstrationcount = 0;
private String hiddenstring = "";
public String visiblestring
{
get { return hiddenstring; }
set
{
hiddenstring = value;
NotifyOnStringChanged();
}
}
private void NotifyOnStringChanged()
{
if (changed != null)
{
changed(this, EventArgs.Empty);
}
}
public EventHandler changed;
private EventHandler Observer = new EventHandler((o, e) => {
DependencyChain sender = (o as DependencyChain);
demonstrationcount++;
//THE FOLLOWING DOES NOT WORK SINCE "this" IS NOT STATIC
//DependencyChain recipient = this;
//recipient.visiblestring = sender.visiblestring;
});
public DependencyChain(string initialstring)
{
this.visiblestring = initialstring;
}
public DependencyChain(DependencyChain other)
{
this.visiblestring = other.visiblestring;
other.changed += Observer;
}
public override string ToString()
{
return visiblestring;
}
}
[TestFixture]
class Eventtest
{
[SetUp]
public void ResetStaticCounter()
{
DependencyChain.demonstrationcount = 0;
}
[Test]//PASS
public void ShouldInitialiseAndCopyValues()
{
DependencyChain Y = new DependencyChain("initial");
DependencyChain X = new DependencyChain(Y);
Assert.AreEqual(X.ToString(), Y.ToString());
}
[Test]//PASS
public void ShouldCallObserverOnChange()
{
DependencyChain Y = new DependencyChain("initial");
DependencyChain X = new DependencyChain(Y);
Assert.AreEqual(0, DependencyChain.demonstrationcount);
Y.visiblestring = "changed";
Assert.AreEqual(1, DependencyChain.demonstrationcount);
}
[Test]//FAIL
public void ShouldChangeStringOnChange()
{
DependencyChain Y = new DependencyChain("initial");
DependencyChain X = new DependencyChain(Y);
Y.visiblestring = "changed";
Assert.AreEqual(X.ToString(), Y.ToString());
}
}
}
I think you only have to move the initialization of Observer to a constructor of DependencyChain, so you can capture this.