I am trying to convert C# source I used in Unity to a Visual Studio Windows forms app and I can't figure out why my onreceive part won't work.
What I'm doing is making a TCP connection to the server (works) then my server sends a welcome package that I do receive but can't handle.
Sometimes it does run completely but does not trigger the trigger (explained later).
Since the source is originally from a unity project there I can wait for the update and I think that is why it works in there.
The code:
private void OnReceive(IAsyncResult ar)
{
try
{
int byteAmt = myStream.EndRead(ar);
byte[] myBytes = new byte[byteAmt];
Buffer.BlockCopy(asyncBuff, 0, myBytes, 0, byteAmt);
if (byteAmt == 0) return;
//UnityThread.executeInUpdate(() =>
//{
ClientHandleData.HandleData(myBytes);
//});
myStream.BeginRead(asyncBuff, 0, 8192, OnReceive, null);
}
catch
{
Console.WriteLine("we have an error in onreceive");
}
}
the Handledata
public static void HandleData(byte[] data)
{
byte[] Buffer;
Buffer = (byte[])data.Clone();
if (playerBuffer == null) playerBuffer = new ByteBuffer();
playerBuffer.WriteBytes(Buffer);
if (playerBuffer.Count() == 0)
{
playerBuffer.Clear();
return;
}
if (playerBuffer.Length() >= 8)
{
pLength = playerBuffer.ReadLong(false);
if (pLength <= 0)
{
playerBuffer.Clear();
return;
}
}
if (playerBuffer.Length() >= 8)
{
pLength = playerBuffer.ReadLong(false);
if (pLength <= 0)
{
playerBuffer.Clear();
return;
}
}
while (pLength > 0 & pLength <= playerBuffer.Length() - 8)
{
if (pLength <= playerBuffer.Length() - 8)
{
playerBuffer.ReadLong();
data = playerBuffer.ReadBytes((int)pLength);
HandleDataPackets(data);
}
pLength = 0;
if (playerBuffer.Length() >= 8)
{
pLength = playerBuffer.ReadLong(false);
if (pLength < 0)
{
playerBuffer.Clear();
return;
}
}
}
}
and last the HandleDataPackets
public static void HandleDataPackets(byte[] data)
{
long packetnum; ByteBuffer buffer; Packet_ packet;
buffer = new ByteBuffer();
buffer.WriteBytes(data);
packetnum = buffer.ReadLong();
buffer = null;
Form1.label1.Text = "reading packetnum";
if (packetnum == 0) return;
Form1.label1.Text = "packetnum read and is not 0";
if (packets.TryGetValue(packetnum, out packet))
{
Form1.label1.Text = "trigger";
packet.Invoke(data);
}
}
sometimes it runs all the way to the Form1.label1.Text = "packetnum read and is not 0"; line in HandleDataPacket but then it does not trigger the trigger line :(.
Can someone please tell me why this is?
Ok i found the problem.
I was trying to initialize the packages in the unity way but had to trigger it from the program itself.
i created a Networkmanager class that initializes the different packages and then makes the connection. this fixed it!
all code above is working as intended.
Just realized that john was telling me this!..
To bad i did not see that a few hours ago.
Post it as an answer and ill mark it like one.
Related
I have a system in which I read the serial port from a X,Y,Z motion stage, meaning that I send a signal (via usb) to a function which reads the signal, moves a stepper motor accordingly, then reads the next stepper motor signal and so on. At the moment, this function looks like this:
public void SCPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
string sCurString = "";
//Loop to receive the data from serial port
System.Threading.Thread.Sleep(150);
sCurString = SCPort.ReadExisting();
if (sCurString != "")
StrReceiver = sCurString;
if (BlnSet == true)
{
if (StrReceiver.Length == 3)
{
if (StrReceiver.Substring(StrReceiver.Length - 3) == "OK\n")
BlnReadCom = true;
}
else if (StrReceiver.Length == 4)
{
if (StrReceiver.Substring(StrReceiver.Length - 3) == "OK\n" || StrReceiver.Substring(StrReceiver.Length - 4) == "OK\nS")
BlnReadCom = true;
}
else
{
if (StrReceiver.Substring(StrReceiver.Length - 3) == "OK\n" || StrReceiver.Substring(StrReceiver.Length - 4) == "OK\nS" ||
StrReceiver.Substring(StrReceiver.Length - 5) == "ERR1\n" || StrReceiver.Substring(StrReceiver.Length - 5) == "ERR3\n" ||
StrReceiver.Substring(StrReceiver.Length - 5) == "ERR4\n" || StrReceiver.Substring(StrReceiver.Length - 5) == "ERR5\n")
BlnReadCom = true;
}
}
else
{
if (StrReceiver.Substring(StrReceiver.Length - 1, 1) == "\n")
BlnReadCom = true;
}
}
catch (Exception ex)
{
MessageBox.Show("Failed to receive data", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
This function reads the serialport SCPort, every 150ms indicated by the Thread.Sleep. If I try to read the data any faster, I get the exception (which is likely an indication of the limitation of my system). Fine. However, this exception is not thrown immediately, but every once in a while. What I would like to do instead of waiting a fixed time between reading the signal, is to each time wait until the serialport is ready and then read it. This should speed up my system, as instead of waiting 150ms between every movement, I could wait exactly the amount of time the system requires.
The question is: how do I implement this behavior in the function?
I have not tried to solve it on my own, because I really have no idea about how to do this. Will be happy to implement this into my function, but at a bare minimum I need to be pointed in the right direction.
This function handles connection to the port SCPort.
public void ConnectPort(short sPort)
{
if (SCPort.IsOpen == true)
{
ClosePort();
buttonConnectStage.Text = "Connect stage";
}
else if (SCPort.IsOpen == false)
{
SCPort.PortName = comStage.SelectedItem.ToString(); //Set the serial port number
SCPort.BaudRate = 9600; //Set the bit rate
SCPort.DataBits = 8; //Set the data bits
SCPort.StopBits = StopBits.One; //Set the stop bit
SCPort.Parity = Parity.None; //Set the Parity
SCPort.ReadBufferSize = 2048;
SCPort.WriteBufferSize = 1024;
SCPort.DtrEnable = true;
SCPort.Handshake = Handshake.None;
SCPort.ReceivedBytesThreshold = 1;
SCPort.RtsEnable = false;
//This delegate should be a trigger event for fetching data asynchronously, it will be triggered when there is data passed from serial port.
SCPort.DataReceived += new SerialDataReceivedEventHandler(SCPort_DataReceived); //DataReceivedEvent delegate
try
{
SCPort.Open(); //Open serial port
if (SCPort.IsOpen)
{
StrReceiver = "";
BlnBusy = true;
BlnSet = false;
SendCommand("?R\r"); //Connect to the controller
Delay(250);
BlnBusy = false;
if (StrReceiver == "?R\rOK\n")
{
displayValues();
BlnConnect = true; //Connected successfully
ShrPort = sPort; //Setial port number
buttonConnectStage.Text = "Disconnect stage";
SendCommand("V" + sSpeed.ToString() + "\r"); //Set speed
}
else
{
BlnBusy = false;
BlnConnect = false;
buttonConnectStage.Text = "Failed to connect";
MessageBox.Show("Failed to connect", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
}
}
catch (Exception ex)
{
}
}
}
I'm working on a small project (http://www.instructables.com/id/Digispark-Volume-Control/) that uses a digispark and a rotary encoder to control media(volume,mute,pause,next,prev). The volume is controlled by the rotation of the rotary encoder and the other stuff are controlled by pressing the button in a specific way: 1 click is for pause, 2 clicks is for mute, short hold for previous song and long hold for next song.
I am asking how would i approach using c# and arduino together to control these stuff dynamically (setup and change what these events that i stated above do, and possibly if i get far with this, add something like a macro editor that uses patterns from the rotary encoders to do stuff).
example for the macro-editor like idea: if i do 2 short clicks for lets say max of 200ms and a turn to the left with the rotary encoder lock the computer.
I am trying to accomplish something like the griffin powermate(https://griffintechnology.com/us/powermate), have a software that sets up what the device does and the device to follow the software
This is the current code i got for the device, it only has the basic features for controling the media:
#include "TrinketHidCombo.h"
#define PIN_ENCODER_A 0
#define PIN_ENCODER_B 2
#define PIN_BUTTON 1
#define TRINKET_PINx PINB
static uint8_t enc_prev_pos = 0;
static uint8_t enc_flags = 0;
void setup()
{
// set pins as input with internal pull-up resistors enabled
pinMode(PIN_ENCODER_A, INPUT);
pinMode(PIN_ENCODER_B, INPUT);
pinMode(PIN_BUTTON, INPUT_PULLUP);
digitalWrite(PIN_ENCODER_A, HIGH);
digitalWrite(PIN_ENCODER_B, HIGH);
digitalWrite(PIN_BUTTON, HIGH);
TrinketHidCombo.begin(); // start the USB device engine and enumerate
// get an initial reading on the encoder pins
if (digitalRead(PIN_ENCODER_A) == LOW) {
enc_prev_pos |= (1 << 0);
}
if (digitalRead(PIN_ENCODER_B) == LOW) {
enc_prev_pos |= (1 << 1);
}
}
void loop()
{
int8_t enc_action = 0; // 1 or -1 if moved, sign is direction
// note: for better performance, the code will now use
// direct port access techniques
// http://www.arduino.cc/en/Reference/PortManipulation
uint8_t enc_cur_pos = 0;
// read in the encoder state first
if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_A)) {
enc_cur_pos |= (1 << 0);
}
if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_B)) {
enc_cur_pos |= (1 << 1);
}
// if any rotation at all
if (enc_cur_pos != enc_prev_pos)
{
if (enc_prev_pos == 0x00)
{
// this is the first edge
if (enc_cur_pos == 0x01) {
enc_flags |= (1 << 0);
}
else if (enc_cur_pos == 0x02) {
enc_flags |= (1 << 1);
}
}
if (enc_cur_pos == 0x03)
{
// this is when the encoder is in the middle of a "step"
enc_flags |= (1 << 4);
}
else if (enc_cur_pos == 0x00)
{
// this is the final edge
if (enc_prev_pos == 0x02) {
enc_flags |= (1 << 2);
}
else if (enc_prev_pos == 0x01) {
enc_flags |= (1 << 3);
}
// check the first and last edge
// or maybe one edge is missing, if missing then require the middle state
// this will reject bounces and false movements
if (bit_is_set(enc_flags, 0) && (bit_is_set(enc_flags, 2) || bit_is_set(enc_flags, 4))) {
enc_action = 1;
}
else if (bit_is_set(enc_flags, 2) && (bit_is_set(enc_flags, 0) || bit_is_set(enc_flags, 4))) {
enc_action = 1;
}
else if (bit_is_set(enc_flags, 1) && (bit_is_set(enc_flags, 3) || bit_is_set(enc_flags, 4))) {
enc_action = -1;
}
else if (bit_is_set(enc_flags, 3) && (bit_is_set(enc_flags, 1) || bit_is_set(enc_flags, 4))) {
enc_action = -1;
}
enc_flags = 0; // reset for next time
}
}
// Get button event and act accordingly
int b = checkButton();
if (b == 1) clickEvent();
if (b == 2) doubleClickEvent();
if (b == 3) holdEvent();
if (b == 4) longHoldEvent();
enc_prev_pos = enc_cur_pos;
if (enc_action > 0) {
TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_UP);
}
else if (enc_action < 0) {
TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_DOWN);
}
else {
TrinketHidCombo.poll(); // do nothing, check if USB needs anything done
}
}
//=================================================
// Events to trigger
void clickEvent() {
TrinketHidCombo.pressMultimediaKey(MMKEY_PLAYPAUSE);
}
void doubleClickEvent() {
TrinketHidCombo.pressMultimediaKey(MMKEY_MUTE);
}
void holdEvent() {
TrinketHidCombo.pressMultimediaKey(MMKEY_SCAN_PREV_TRACK);
}
void longHoldEvent() {
TrinketHidCombo.pressMultimediaKey(MMKEY_SCAN_NEXT_TRACK);
}
int debounce = 20; // ms debounce period to prevent flickering when pressing or releasing the button
int DCgap = 500; // max ms between clicks for a double click event
int holdTime = 1000; // ms hold period: how long to wait for press+hold event
int longHoldTime = 1500; // ms long hold period: how long to wait for press+hold event
// Button variables
boolean buttonVal = HIGH; // value read from button
boolean buttonLast = HIGH; // buffered value of the button's previous state
boolean DCwaiting = false; // whether we're waiting for a double click (down)
boolean DConUp = false; // whether to register a double click on next release, or whether to wait and click
boolean singleOK = true; // whether it's OK to do a single click
long downTime = -1; // time the button was pressed down
long upTime = -1; // time the button was released
boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered
boolean waitForUp = false; // when held, whether to wait for the up event
boolean holdEventPast = false; // whether or not the hold event happened already
boolean longHoldEventPast = false;// whether or not the long hold event happened already
int checkButton() {
int event = 0;
buttonVal = digitalRead(PIN_BUTTON);
// Button pressed down
if (buttonVal == HIGH && buttonLast == LOW && (millis() - upTime) > debounce)
{
downTime = millis();
ignoreUp = false;
waitForUp = false;
singleOK = true;
holdEventPast = false;
longHoldEventPast = false;
if ((millis() - upTime) < DCgap && DConUp == false && DCwaiting == true) DConUp = true;
else DConUp = false;
DCwaiting = false;
}
// Button released
// DOUBLE CLICK
else if (buttonVal == HIGH && buttonLast == HIGH && (millis() - downTime) > debounce)
{
if (not ignoreUp)
{
upTime = millis();
if (DConUp == false) DCwaiting = true;
else
{
event = 2;
DConUp = false;
DCwaiting = false;
singleOK = false;
}
}
}
// Test for normal click event: DCgap expired
if ( buttonVal == LOW && (millis() - upTime) >= DCgap && DCwaiting == true && DConUp == false && singleOK == true && event != 2)
{
event = 1;
DCwaiting = false;
}
// Test for hold
if (buttonVal == HIGH && (millis() - downTime) >= holdTime) {
// Trigger "normal" hold
if (not holdEventPast)
{
event = 3;
waitForUp = true;
ignoreUp = true;
DConUp = false;
DCwaiting = false;
//downTime = millis();
holdEventPast = true;
}
// Trigger "long" hold
if ((millis() - downTime) >= longHoldTime)
{
if (not longHoldEventPast)
{
event = 4;
longHoldEventPast = true;
}
}
}
buttonLast = buttonVal;
return event;
}
Since you cannot run C# code on the Arduino itself that code needs to be running on a PC (or Raspberry Pi or similar using .NET Core).
So that means you need a way to communicate between the two. Your options are:
Send messages back and forth over a serial port (serial over USB) (easiest since you are probably already using one to program your Arduino).
Use WIFI or Ethernet and create a WebAPI endpoint that the Arduino calls into to deliver messages and to get results.
Use some other communication mechanism like Bluetooth.
Alternatively, if you have a device like the Trinket that only supports keyboard emulation over USB you would need to pick some unused keycodes for it to send and then have your application hook into the global events to handle them (see https://blogs.msdn.microsoft.com/toub/2006/05/03/low-level-keyboard-hook-in-c/) - unless of course you application is in the foreground in which case you can just read input from the keyboard as the device sends it.
I have a library that returns CS:GO stats in real-time from the game. I'm making a program that stores the stats and analyse it.
I have this function:
private void UpdateKills(GameState gs)
{
int currentKills = -1;
if (lastKills == -1) // first time getting player info
{
int temp = gs.Player.MatchStats.Kills;
currentKills = temp;
lastKills = temp;
}
else
{
currentKills = gs.Player.MatchStats.Kills;
int dif = currentKills - lastKills;
if (currentKills == 0 && lastKills != 0) // maybe changed server/map/whatever
{
lastKills = -1;
}
else
{
if (dif != 0 && dif > 0) // player killed someone AND it was not teamkill
{
ps.Kills += dif; // add the kills to the main variable
lastKills = currentKills;
dif = 0;
playSimpleSound();
}
}
}
}
This is my function that handles the kills. The most of the time it works very well, but sometimes it just freaks out, and I don't know if the problem is my logic or if it is a library problem.
Note: I'm using this library: github.com/rakijah/CSGSI
My logic is:
Get the player kills
Increment those kills in the PlayerStats object.
Is my code logically correct? Can my code be more "correct"?
I'm still not entirely sure what this function is supposed to be doing, but I simplified it for you:
private void UpdateKills(GameState gs)
{
lastKills = currentKills;
int currentKills = gs.Player.MatchStats.Kills;
int diff = currentKills - lastKills;
if (currentKills == 0 && lastKills != 0) // maybe changed server/map/whatever
{
lastKills = -1;
}
else if (diff > 0) // player killed someone AND it was not teamkill
{
ps.Kills += diff; // add the kills to the main variable
playSimpleSound();
}
}
Well, after some research in finally undertand your problem. You DON'T have to do anything!, the API does all the work for you, watch the next image:
As you can see, the console app shows my steam name, the map and kills. I start with zero kills, then I kill a teammate and after that an enemy. The API created by #rakijah autoupdates those values.
Now the code:
static void Main(string[] args)
{
CsGoIntegration();
}
private static void CsGoIntegration()
{
var gsl = new GameStateListener(3000);
gsl.NewGameState += new NewGameStateHandler(OnNewGameState);
if (!gsl.Start())
{
Environment.Exit(0);
}
System.Console.WriteLine("Listening...");
}
private static void OnNewGameState(GameState gs)
{
System.Console.WriteLine("Map: {0}", gs.Map.Name);
System.Console.WriteLine("Player Name: {0}", gs.Player.Name);
System.Console.WriteLine("Player Kills: {0}", gs.Player.MatchStats.Kills);
}
UPDATE: The OP needs to store the total kills even when the map changes. I experimented with paper and pencil, please try running the program and tell me if it worked or not
private static void Main()
{
CsGoIntegration();
}
private static void CsGoIntegration()
{
var gsl = new GameStateListener(3000);
gsl.NewGameState += OnNewGameState;
if (!gsl.Start())
{
Environment.Exit(0);
}
Console.WriteLine("Listening...");
}
private static void OnNewGameState(GameState gameState)
{
SaveMatchsData(gameState);
}
private static int? _totalKillScore;
private static string _lastMapName;
private static int? _lastKillScore;
private static void SaveMatchsData(GameState gameState)
{
const string undefinedString = "Undefined";
// If the SaveMatchsData is running and the CSGO server is offline
if (gameState.Map.Name == undefinedString && string.IsNullOrEmpty(_lastMapName))
return;
// When the match is not started, the Round is -1
if (gameState.Map.Name != undefinedString && gameState.Map.Round > -1)
{
if (string.IsNullOrEmpty(_lastMapName))
{
UpdateData(gameState, true);
}
else
{
// Same map
if (_lastMapName == gameState.Map.Name)
{
// Check if the Score Changes
if (_lastKillScore == gameState.Player.MatchStats.Kills) return;
UpdateData(gameState);
}
// The Map Changes
else
{
UpdateData(gameState, true);
}
}
}
}
private static void UpdateData(GameState gameState, bool updateMap = false)
{
if (updateMap)
_lastMapName = gameState.Map.Name;
_lastKillScore = gameState.Player.MatchStats.Kills;
_totalKillScore += gameState.Player.MatchStats.Kills;
}
Cheers.
I am trying to download files through webclient and the code is like the one given below. The problem is that if I get continuous 404 response alot of times, my server reaches to 100% and viewing the event log tells that stack overflow happened. Here the "count" variable is to avoid 0 byte files and count404 is for 404 responses.
int count = 0; int count404 = 0;
public Stream DownloadFileThroughWebClient(string strFilePath)
{
try
{
if (count >= 120 || count404 >= 30)
{
count = 0;
count404 = 0;
return null;
}
System.Threading.Thread.Sleep(1000);
System.Net.WebClient wc = new System.Net.WebClient();
var v = wc.DownloadData(strFilePath);
Stream FileToSave = new MemoryStream(v);
byte[] bytes = new byte[FileToSave.Length];
int numBytesToRead = (int)FileToSave.Length;
if (numBytesToRead > 0)
{
count = 0;
count404 = 0;
return FileToSave;
}
else
{
count++;
count404 = 0;
return DownloadFileThroughWebClient(strFilePath);
}
}
catch (Exception ex)
{
count++;
count404++;
return DownloadFileThroughWebClient(strFilePath);
}
}
Thanks in advance.
Try this (without using recursion and counts the 404s correctly):
public Stream DownloadFileThroughWebClient(string strFilePath)
{
int count = 0;
int count404 = 0;
while (count < 120 && count404 < 30)
{
try
{
byte[] v;
using (var wc = new WebClient())
{
v = wc.DownloadData(strFilePath);
}
if (v.Length > 0)
{
return new MemoryStream(v);
}
count++;
count404 = 0;
}
catch (WebException ex)
{
count++;
var httpWebResponse = ex.Response as HttpWebResponse;
if (httpWebResponse != null && httpWebResponse.StatusCode == HttpStatusCode.NotFound)
{
count404++;
// you may wanna break out of the loop here since there's no point in continuing
}
}
catch (Exception ex)
{
}
}
return null;
}
You call:
return DownloadFileThroughWebClient(strFilePath);
If something goes wrong. If it keeps getting a 404 (or more likely: ip-blocked for abuseive querying), then of course you will stackoverflow. That is what happens if you call yourself recursively too many times. So: don't do that. Some kind of "while" loop (with a sanity exit condition for either success or persistent failure) seems more appropriate than recursion.
Ive got this problem:
Line 20 (LOOT_FromContainer(container) I need that to use as Invoke, because the process I want to exec takes some time, so ServerMessageHandler won't handle it...
If I just simply rewrite that line to LOOT_FromContainer.BeginInvoke(container); then I have this error:
error CS0119: 'LOOT.LOOT_FromContainer(Phoenix.Serial)' is a 'method',
which is not valid in the given context
I'm new to C#, came from PHP, and about Invoke I don't know much really. I've been trying to sort this out for a couple of days, not even google helped...
[ServerMessageHandler(0x3C)]
public CallbackResult ContainerContains(byte[] data, CallbackResult prevResult)
{
PacketReader reader = new PacketReader(data);
reader.Skip(3);
ushort len = reader.ReadUInt16();
for (int i = 0; i < len; i++)
{
Serial serial = (Serial)(reader.ReadUInt32());
ushort graphic = (ushort)(reader.ReadUInt16());
reader.Skip(7);
Serial container = (Serial)(reader.ReadUInt32());
ushort color = (ushort)(reader.ReadUInt16());
if (((int)graphic == 0x0E76) && ((int)color == 0x049A))
{
LOOT_FromContainer.BeginInvoke(container);
}
}
return CallbackResult.Normal;
}
[Command]
public static void LOOT_FromContainer(Serial target)
{
UOItem lootCorpse = new UOItem(target);
if (lootCorpse.Graphic == 0x2006)
{
if (((draw == 1) && (World.Player.Backpack.AllItems.Count(draw_knife[0], draw_knife[1]) > 0)) || (World.Player.Layers[Layer.RightHand].Exist))
{
if ((lootCorpse.Amount != 400) && (lootCorpse.Amount != 401))
{
if (draw == 0)
{
UO.WaitTargetObject(lootCorpse);
UO.UseObject(World.Player.Layers[Layer.RightHand].Serial);
}
else
{
UO.WaitTargetObject(lootCorpse);
UO.UseType(draw_knife[0], draw_knife[1]);
}
UO.Wait(500);
}
}
else
{
UO.Print("Neni cim rezat, pouze lootim");
}
for (int i = 0; i < loot.Length; i++)
{
if (lootCorpse.Items.Count(loot[i][0], loot[i][1]) > 0)
{
if (loot[i][2] == 1)
{
if (loot[i][4] == 1)
{
UO.MoveItem(lootCorpse.Items.FindType(loot[i][0], loot[i][1]), 0, Aliases.GetObject("loot_bag"), loot[i][5], loot[i][6]);
UO.Wait(200);
}
else
{
UO.MoveItem(lootCorpse.Items.FindType(loot[i][0], loot[i][1]), 0, World.Player.Backpack);
UO.Wait(200);
}
}
}
}
}
}
I think this is what you need. You need to declare a delegate with the same return type and input parameters as your method, instantiate this delegate pointing it at your method and then call BeginInvoke on it passing in your serial variable, followed by null, null:
public delegate void LFC(Serial target);
[ServerMessageHandler(0x3C)]
public CallbackResult ContainerContains(byte[] data, CallbackResult prevResult)
{
PacketReader reader = new PacketReader(data);
reader.Skip(3);
ushort len = reader.ReadUInt16();
for (int i = 0; i < len; i++)
{
Serial serial = (Serial)(reader.ReadUInt32());
ushort graphic = (ushort)(reader.ReadUInt16());
reader.Skip(7);
Serial container = (Serial)(reader.ReadUInt32());
ushort color = (ushort)(reader.ReadUInt16());
LFC = lootfromcontainer = new LFC(LOOT_FromContainer);
if (((int)graphic == 0x0E76) && ((int)color == 0x049A))
{
lootfromcontainer.BeginInvoke(container, null, null);
//LOOT_FromContainer.BeginInvoke(container);
}
}
return CallbackResult.Normal;
}
[Command]
public static void LOOT_FromContainer(Serial target)
{
UOItem lootCorpse = new UOItem(target);
if (lootCorpse.Graphic == 0x2006)
{
if (((draw == 1) && (World.Player.Backpack.AllItems.Count(draw_knife[0], draw_knife[1]) > 0)) || (World.Player.Layers[Layer.RightHand].Exist))
{
if ((lootCorpse.Amount != 400) && (lootCorpse.Amount != 401))
{
if (draw == 0)
{
UO.WaitTargetObject(lootCorpse);
UO.UseObject(World.Player.Layers[Layer.RightHand].Serial);
}
else
{
UO.WaitTargetObject(lootCorpse);
UO.UseType(draw_knife[0], draw_knife[1]);
}
UO.Wait(500);
}
}
else
{
UO.Print("Neni cim rezat, pouze lootim");
}
for (int i = 0; i < loot.Length; i++)
{
if (lootCorpse.Items.Count(loot[i][0], loot[i][1]) > 0)
{
if (loot[i][2] == 1)
{
if (loot[i][4] == 1)
{
UO.MoveItem(lootCorpse.Items.FindType(loot[i][0], loot[i][1]), 0, Aliases.GetObject("loot_bag"), loot[i][5], loot[i][6]);
UO.Wait(200);
}
else
{
UO.MoveItem(lootCorpse.Items.FindType(loot[i][0], loot[i][1]), 0, World.Player.Backpack);
UO.Wait(200);
}
}
}
}
}
}
If you simply need to run that in another thread you can use ThreadPool.
For this you would need few easy things:
Instead of:
LOOT_FromContainer.BeginInvoke(container);
You would use:
ThreadPool.QueueUserWorkItem(LOOT_FromContainer, container);
And slightly modify your LOOT_FromContainer method to:
public static void LOOT_FromContainer(object prm)
{
var target = (Serial)prm;
// ...
I'm assuming LOOT_FromCotainer is a control, and given the error your compiler returns, one can roughly guess the problem is that you're calling BeginInvoke with a non-delegate. BeginInvoke is called as follows:
LOOT_FromContainer.BeginInvoke(container); //where container is a delegate that maybe declared as follows
private delegate void container; //may also contain parameters eg container(string s);
So just rework your code to follow in this manner. See this document for example on how to use BeginInvoke.