so i have tested the conversion across simple functions ,it works with no problem.
i am fully able to read the data like this with one instance of the application which
tells me my conversion is fine
heres example code i used :
//this is a packet to be send by send_data_to
[StructLayout(LayoutKind.Sequential)]
public class packet
{
public string message;
}
//test marshal packet to intptr
public IntPtr to_intptr(object obj)
{
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
Marshal.StructureToPtr(obj, ptr, false);
return ptr;
}
//test demarshal intptr to packet
public object to_struct(IntPtr ptr, Type t)
{
return Marshal.PtrToStructure(ptr, t);
}
//test recieve marshaled packet across function
public void recieve_packet(IntPtr ptr)
{
//get packet from intptr
packet my_packet = (packet)to_struct(ptr, typeof(packet));
Marshal.FreeHGlobal(ptr);
//a test message
network.network_events.mes = my_packet.message;
}
//test send packet across function
public void send_packet(packet ppacket)
{
//marshal packet to intptr
IntPtr ptr = to_intptr(ppacket);
//send intptr
recieve_packet(ptr);
}
.......
//inside my test loop
if (EngVar.key_3 && key3)
{
key3 = false;
//create packet
packet mypacket = new packet();
mypacket.message = "hello there";
//test send
send_packet(mypacket);
}
why do i convert ?
because the wrapper needs the conversion to intptr because
we do not use unsafe void* pointers in c# right.
in the wrapper ,the native engine function send_data_to is wrapped like:
public static double send_data_to(ENTITY entity, IntPtr data, int size)
{
IntPtr entityPointer = IntPtr.Zero;
if (entity != null)
{
entityPointer = entity.getIntPtr();
}
return Conversion.varToDouble(NativeEngFun.send_data_to(entityPointer,data,Conversion.doubleToVar(size)));
}
and the native send_data_to which calls the dll function is:
[DllImport("acknex.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int send_data_to(IntPtr param0, IntPtr param1, int param2);
now ,that that's obvious and out of the way to whom-ever is reading.
let me get to how i tried doing it across the network.
heres my network test class file.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using AcknexWrapper;
namespace network
{
//client information container
class client_info
{
public string player_name;
public int id;
}//client information container
//list of clients information containers
static class connected_clients
{
public static List<client_info> client_ids = new List<client_info>();
}//list of clients information containers
//the packet to be send
[StructLayout(LayoutKind.Sequential)]
public class packet
{
public string message;
}
//marshalling & demarshaling helper
static class packet_convert
{
public static IntPtr to_intptr(object obj)
{
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
Marshal.StructureToPtr(obj, ptr, false);
return ptr;
}
public static object to_struct(IntPtr ptr, Type t)
{
return Marshal.PtrToStructure(ptr, t);
}
}
//event handler for server & clients
static class network_events
{
public static string mes;
#region client_events
//client recieved an event
public static IEnumerable<int> on_client(IntPtr ptr)
{
//the server has send data to the client
if (EngVar.event_type == AcknexWrapper.Flags.EVENT_DATA)
{
//mes = AcknexWrapper.Native.Conversion.getStringFromIntPtr(ptr);
if (ptr != IntPtr.Zero)
{
packet my_packet = (packet)packet_convert.to_struct(ptr, typeof(packet));
network.network_events.mes = my_packet.message;
}
}
//client has joined session
if (EngVar.event_type == AcknexWrapper.Flags.EVENT_JOIN)
{
}
//client was dropped
if (EngVar.event_type == AcknexWrapper.Flags.EVENT_LEAVE)
{
}
yield return 1;
}//client recieved an event
#endregion
#region server_events
//server recieved an event
public static IEnumerable<int> on_server(IntPtr ptr,double id)
{
//the client has send data to the server
if (EngVar.event_type == AcknexWrapper.Flags.EVENT_DATA)
{
}
//client has joined session
if (EngVar.event_type == AcknexWrapper.Flags.EVENT_JOIN)
{
client_info this_client= new client_info();
this_client.id = (int)id;
this_client.player_name = AcknexWrapper.Native.Conversion.getStringFromIntPtr(ptr);
connected_clients.client_ids.Add(this_client);
}
//client was dropped
if (EngVar.event_type == AcknexWrapper.Flags.EVENT_LEAVE)
{
}
yield return 1;
}//server recieved an event
#endregion
}//event handler for server & clients
public class mp_session
{
//open a session on the server
public bool open_session(string session)
{
if (EngFun.session_open(session) > 0)
{
return true;
}
else return false;
}//open a session on the server
//connect to a session on the server
public bool connect_to_session(string session,string hostname)
{
if (EngFun.session_connect(session, hostname) > 0)
{
return true;
}
else return false;
}//connect to a session on the server
//close the session
public void close_session()
{
EngFun.session_close();
}//close the session
//send a string to client/s or server
//from client to server target must be null
//from server to all clients ,target must be null
//from server to the client that created the target entity
//The buffer size should not exceed about 1000 bytes - data packets above that size often get lost on transmission over the Internet
public void session_send_string(ENTITY target,string str)
{
if (str.Length > 0)
{
//The buffer size should not exceed about 1000 bytes
//data packets above that size often get lost on transmission over the Internet
if ((sizeof(char) * str.Length) < 1000)
{
EngFun.send_data_to(target, AcknexWrapper.Native.Conversion.getIntPtrForString(str), sizeof(char) * str.Length);
}
}
}
public void session_send_packet_to(ENTITY target, packet this_packet)
{
IntPtr ptr = packet_convert.to_intptr(this_packet);
int size=Marshal.SizeOf(this_packet);
//int size = Marshal.SizeOf(ptr);
EngFun.send_data_to(target,ptr,size);
Marshal.FreeHGlobal(ptr);
}
}
}
which i then call like this again in my main loop:
//test send string to clients
if (EngVar.key_3 && key3)
{
key3 = false;
//multiplayer_session.session_send_string(null, "hello there");
packet mypacket = new packet();
mypacket.message = "hello there";
multiplayer_session.session_send_packet_to(null, mypacket);
}
then i run one instance of the application in debug mode and the other from
the exe file , so that i can set one as the server ,the other as the client.
i then press 3 to send the packet to all clients ,then when the debugger breaks
in to the on_client event ,it breaks at the demarshalling code with an exception
of trying to read/write protected memmory at:
public static object to_struct(IntPtr ptr, Type t)
{
return Marshal.PtrToStructure(ptr, t);
}
which is taken from:
packet = (packet)packet_convert.to_struct(ptr, typeof(packet));
and i have tried everything i could think off , changing packing ,determining the size differently etc etc
i cannot figure out whats going wrong , i am not even sure if the events are of the correct parameters , but sending a string instead of a packet works fine so i
am assuming its correct , this is not to important but i would like to know whats wrong , although like i said i think its a memmory thing but i am not sure anymore .
help is welcome .