using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace NetworkSocket
{
public class BasicClient
{
/// <summary>
/// The base socket.
/// </summary>
private Socket baseSocket;
/// <summary>
/// A boolean indicating whether or not the connection was accepted.
/// </summary>
private bool wasAccepted;
/// <summary>
/// Gets a boolean indicating whether or not the connection was accepted.
/// </summary>
public bool Accepted
{
get
{
return wasAccepted;
}
}
/// <summary>
/// Creates a new instance of BasicClient.
/// </summary>
/// <param name="serverSocket">The server socket.</param>
/// <param name="asyncResult">The async result.</param>
internal BasicClient(Socket serverSocket, IAsyncResult asyncResult)
{
try
{
baseSocket = serverSocket.EndAccept(asyncResult);
wasAccepted = true;
}
catch
{
wasAccepted = false;
}
}
/// <summary>
/// An event raised when the client is disconnected.
/// </summary>
internal ConnectionEvent onDisconnection;
/// <summary>
/// An event raised a packet is received.
/// </summary>
internal BufferEvent onReceive;
/// <summary>
/// Creates a new instance of BasicClient.
/// </summary>
/// <param name="addressFamily">The address family.</param>
/// <param name="socketType">The socket type.</param>
/// <param name="protocolType">The protocol type.</param>
public BasicClient(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType,
ConnectionEvent onDisconnection = null,
BufferEvent onReceive = null)
{
baseSocket = new Socket(addressFamily, socketType, protocolType);
if (onDisconnection != null)
this.onDisconnection = onDisconnection;
if (onReceive != null)
this.onReceive = onReceive;
}
/// <summary>
/// Begins to receive the header.
/// </summary>
public void ReceiveHeader()
{
receiveBuffer = new byte[4];
baseSocket.BeginReceive(receiveBuffer, 0, 4, SocketFlags.None, new AsyncCallback(ReceiveHeader_Callback), null);
}
/// <summary>
/// Begins to receive the body.
/// </summary>
public void ReceiveBody()
{
receiveBuffer = new byte[size - 4];
baseSocket.BeginReceive(receiveBuffer, 0, (size - 4), SocketFlags.None, new AsyncCallback(ReceiveBody_Callback), null);
}
/// <summary>
/// The size of the received packet.
/// </summary>
private ushort size;
/// <summary>
/// The type of the received packet.
/// </summary>
private ushort type;
/// <summary>
/// The buffer holding all data received.
/// </summary>
private byte[] receiveBuffer;
/// <summary>
/// The callback from ReceiveHeader.
/// </summary>
/// <param name="asyncResult">The async result.</param>
private void ReceiveHeader_Callback(IAsyncResult asyncResult)
{
try
{
SocketError err;
int hSize = baseSocket.EndReceive(asyncResult, out err);
if (err == SocketError.Success)
{
if (hSize == 4)
{
byte[] rBuffer = new byte[4];
System.Buffer.BlockCopy(receiveBuffer, 0, rBuffer, 0, 4);
DataPacket header = new DataPacket(rBuffer);
size = header.Size;
type = header.Type;
ReceiveBody();
}
else
Disconnect();
}
else
Disconnect();
}
catch
{
Disconnect();
}
}
/// <summary>
/// The callback from ReceiveBody.
/// </summary>
/// <param name="asyncResult">The async result.</param>
private void ReceiveBody_Callback(IAsyncResult asyncResult)
{
try
{
SocketError err;
int bSize = baseSocket.EndReceive(asyncResult, out err);
if (err == SocketError.Success)
{
if (bSize == (size - 4))
{
if (onReceive != null)
{
byte[] rBuffer = new byte[size];
System.Buffer.BlockCopy(receiveBuffer, 0, rBuffer, 4, bSize);
DataPacket dPacket = new DataPacket(rBuffer);
dPacket.Size = size;
dPacket.Type = type;
onReceive.Invoke(this, dPacket);
}
ReceiveHeader();
}
else
Disconnect();
}
else
Disconnect();
}
catch
{
Disconnect();
}
}
/// <summary>
/// A boolean indicating whether or not the client is disconnected.
/// </summary>
private bool alreadyDisconnected = false;
/// <summary>
/// Disconnecting the client.
/// </summary>
public void Disconnect()
{
if (alreadyDisconnected)
return;
alreadyDisconnected = true;
try
{
if (baseSocket.Connected)
baseSocket.Disconnect(false);
}
catch
{
}
if (onDisconnection != null)
onDisconnection.Invoke(this);
}
/// <summary>
/// Sends a packet.
/// </summary>
/// <param name="buffer">The packet to send.</param>
public void Send(byte[] buffer)
{
bool PacketSend = false;
try
{
if (PacketSend = Monitor.TryEnter(this, 50))
{
if (baseSocket.Connected)
{
baseSocket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Send_Callback), null);
}
else
Disconnect();
}
}
finally
{
if (!PacketSend)
Disconnect(); // lag
else
Monitor.Exit(this);
}
}
/// <summary>
/// Sends a packet.
/// </summary>
/// <param name="packet">The packet to send.</param>
public void Send(DataPacket packet)
{
bool PacketSend = false;
try
{
byte[] buffer = packet;
if (PacketSend = Monitor.TryEnter(this, 50))
{
if (baseSocket.Connected)
{
baseSocket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Send_Callback), null);
}
else
Disconnect();
}
}
finally
{
if (!PacketSend)
Disconnect(); // lag
else
Monitor.Exit(this);
}
}
/// <summary>
/// The callback from Send.
/// </summary>
/// <param name="asyncResult">The async result.</param>
private void Send_Callback(IAsyncResult asyncResult)
{
try
{
int send = baseSocket.EndSend(asyncResult);
if (send < 4)
Disconnect();
}
catch
{
}
}
/// <summary>
/// Connects the client to an end point.
/// </summary>
/// <param name="endPoint">The end point to connect to.</param>
/// <returns>Returns true if the client was connected.</returns>
public bool Connect(EndPoint endPoint)
{
try
{
int tries = 0;
while (!baseSocket.Connected && tries < 3)
{
baseSocket.Connect(endPoint);
Thread.Sleep(3000);
}
}
catch
{
}
return baseSocket.Connected;
}
/// <summary>
/// Connects the client to an end point from a specific IP Address and port.
/// </summary>
/// <param name="ip">The IP Address.</param>
/// <param name="port">The port.</param>
/// <returns>Returns true if the client was connected.</returns>
public bool Connect(string ip, int port)
{
try
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(ip), port);
int tries = 0;
while (!baseSocket.Connected && tries < 3)
{
baseSocket.Connect(endPoint);
Thread.Sleep(3000);
}
}
catch
{
}
return baseSocket.Connected;
}
}
}
BasicServerSocket.cs
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace NetworkSocket
{
public delegate void ConnectionEvent(BasicClient basicClient);
public delegate void BufferEvent(BasicClient basicClient, DataPacket buffer);
/// <summary>
/// A basic class for a server socket.
/// </summary>
public class BasicServerSocket
{
/// <summary>
/// The header socket.
/// </summary>
private Socket baseSocket;
/// <summary>
/// Creates a new instance of BasicServerSocket.
/// </summary>
/// <param name="addressFamily">The address family.</param>
/// <param name="socketType">The socket type.</param>
/// <param name="protocolType">The protocol type.</param>
/// <param name="onConnection">An event raised when a connection is accepted.</param>
/// <param name="onDisconnection">An event raised when a connection is dropped.</param>
/// <param name="onReceive">An event raised when a packet is received.</param>
/// <param name="onDeclined">An event raised when a connection was not accepted.</param>
public BasicServerSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType,
ConnectionEvent onConnection = null,
ConnectionEvent onDisconnection = null,
BufferEvent onReceive = null,
ConnectionEvent onDeclined = null)
{
baseSocket = new Socket(addressFamily, socketType, protocolType);
if (onConnection != null)
this.onConnection = onConnection;
if (onDisconnection != null)
this.onDisconnection = onDisconnection;
if (onReceive != null)
this.onReceive = onReceive;
if (onDeclined != null)
this.onDeclined = onDeclined;
}
/// <summary>
/// An event raised when a client is connected.
/// </summary>
private ConnectionEvent onConnection;
/// <summary>
/// An event raised when a client is disconnected.
/// </summary>
private ConnectionEvent onDisconnection;
/// <summary>
/// An event raised when a connection was not accepted.
/// </summary>
private ConnectionEvent onDeclined;
/// <summary>
/// An event raised when a packet is received.
/// </summary>
private BufferEvent onReceive;
/// <summary>
/// Tells the socket to be put in a listening state.
/// </summary>
/// <param name="backlog">The backlog queue.</param>
public void Listen(int backlog)
{
baseSocket.Listen(backlog);
}
/// <summary>
/// Binds the socket to an end point.
/// </summary>
/// <param name="endPoint">The end point the socket should be bound to.</param>
public void Bind(EndPoint endPoint)
{
baseSocket.Bind(endPoint);
}
/// <summary>
/// Binds the socket to an end point from a specific IP Address and port.
/// </summary>
/// <param name="ip">The IP Address.</param>
/// <param name="port">The port.</param>
public void Bind(string ip, int port)
{
baseSocket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
}
/// <summary>
/// Tells the socket to start accept connections.
/// </summary>
public void AcceptConnections()
{
baseSocket.BeginAccept(new AsyncCallback(Accept_CallbacK), null);
}
/// <summary>
/// The callback from AcceptConnections.
/// </summary>
/// <param name="asyncResult">The async result.</param>
private void Accept_CallbacK(IAsyncResult asyncResult)
{
BasicClient client = new BasicClient(baseSocket, asyncResult);
if (client.Accepted)
{
if (onConnection != null)
{
if (onReceive != null)
client.onReceive = onReceive;
if (onDisconnection != null)
client.onDisconnection = onDisconnection;
onConnection.Invoke(client);
}
client.ReceiveHeader();
}
else if (onDeclined != null)
onDeclined.Invoke(client);
AcceptConnections();
}
}
}
DataPacket.cs
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NetworkSocket
{
public unsafe class DataPacket
{
public DataPacket(byte[] buffer)
{
this.buffer = new byte[buffer.Length];
System.Buffer.BlockCopy(buffer, 0, this.buffer, 0, buffer.Length);
}
public DataPacket(ushort size, ushort type)
{
buffer = new byte[size];
WriteUInt16(size, 0);
WriteUInt16(type, 2);
}
private byte[] buffer;
protected byte[] Buffer
{
get
{
return buffer;
}
}
public byte* Ptr
{
get
{
fixed (byte* ptr = Buffer)
return ptr;
}
}
public ushort Size
{
get
{
return ReadUInt16(0);
}
set
{
WriteUInt16(value, 0);
}
}
public ushort Type
{
get
{
return ReadUInt16(2);
}
set
{
WriteUInt16(value, 2);
}
}
public void WriteSByte(sbyte value, int offset)
{
(*(sbyte*)(Ptr + offset)) = value;
}
public void WriteInt16(short value, int offset)
{
(*(short*)(Ptr + offset)) = value;
}
public void WriteInt32(int value, int offset)
{
(*(int*)(Ptr + offset)) = value;
}
public void WriteInt64(long value, int offset)
{
(*(long*)(Ptr + offset)) = value;
}
public void WriteByte(byte value, int offset)
{
(*(byte*)(Ptr + offset)) = value;
}
public void WriteUInt16(ushort value, int offset)
{
(*(ushort*)(Ptr + offset)) = value;
}
public void WriteUInt32(uint value, int offset)
{
(*(uint*)(Ptr + offset)) = value;
}
public void WriteUInt64(ulong value, int offset)
{
(*(ulong*)(Ptr + offset)) = value;
}
public void WriteStringWithLength(string value, int offset, out int nextoffset)
{
WriteByte((byte)(value.Length > 255 ? 255 : value.Length), offset);
offset++;
foreach (char c in value)
{
WriteByte((byte)c, offset);
offset++;
}
nextoffset = offset;
}
public void WriteString(string value, int offset)
{
foreach (char c in value)
{
WriteByte((byte)c, offset);
offset++;
}
}
public sbyte ReadSByte(int offset)
{
return (*(sbyte*)(Ptr + offset));
}
public short ReadInt16(int offset)
{
return (*(short*)(Ptr + offset));
}
public int ReadInt32(int offset)
{
return (*(int*)(Ptr + offset));
}
public long ReadInt64(int offset)
{
return (*(long*)(Ptr + offset));
}
public byte ReadByte(int offset)
{
return (*(byte*)(Ptr + offset));
}
public byte[] ReadBytes(int offset, int length)
{
byte[] bytes = new byte[length];
for (int i = offset; i < length; i++)
bytes[i] = (*(byte*)(Ptr + i));
return bytes;
}
public ushort ReadUInt16(int offset)
{
return (*(ushort*)(Ptr + offset));
}
public uint ReadUInt32(int offset)
{
return (*(uint*)(Ptr + offset));
}
public ulong ReadUInt64(int offset)
{
return (*(ulong*)(Ptr + offset));
}
public string ReadString(int offset, int length)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++)
sb.Append((char)ReadByte(offset + i));
return sb.ToString().Replace("\0", "").Replace("\r", "");
}
public string ReadString(int offset)
{
byte size = ReadByte(offset);
offset++;
return ReadString(offset, size);
}
public byte[] ToArray()
{
byte[] newbuffer = new byte[Buffer.Length];
System.Buffer.BlockCopy(Buffer, 0, newbuffer, 0, Buffer.Length);
return newbuffer;
}
public static implicit operator byte[](DataPacket dPacket)
{
return dPacket.ToArray();
}
public static implicit operator DataPacket(byte[] Packet)
{
return new DataPacket(Packet);
}
}
}
You may have tested this on a private server and had success, but I noticed one thing in your receive body (as well as your receive header) part which will fail in a proxy environment. You may the assumption when you say "I want to receive n-bytes" you receive n-bytes, and if you don't, you drop the connection. In the real world however, fragmentation occurs and you may only receive a fraction of a n-bytes and may need to continue receiving until n-bytes has been read in total.
You may have tested this on a private server and had success, but I noticed one thing in your receive body (as well as your receive header) part which will fail in a proxy environment. You may the assumption when you say "I want to receive n-bytes" you receive n-bytes, and if you don't, you drop the connection. In the real world however, fragmentation occurs and you may only receive a fraction of a n-bytes and may need to continue receiving until n-bytes has been read in total.
Ohh yeah I didn't think of that! I'll update this tomorrow also found a few other things to change
But in DataPacket.cs why don't you just turn the buffer to read only and rename it
Code:
private readonly byte[] _buffer;
To prevent using this. redundantly ?
Code:
public DataPacket(byte[] buffer)
{
this.buffer = new byte[buffer.Length];
System.Buffer.BlockCopy(buffer, 0, this.buffer, 0, buffer.Length);
}
It is really misleading to have 2 byte[] with the same name.
Felt lazy and the datapacket is just a class I'm using over and over and never really modifying it. Hence why it's not commented or documented at all.
Quote:
Originally Posted by Danial Eugen
Also i see you never used this name spaces
Code:
using System;
using System.Collections.Generic;
using System.Linq;
I'm not wasting my time removing namespaces that I don't use and as I can't remember the short key for it then as lazy as I am I'll just leave them and the System namespace is always in use lol, so it'd be Collections.Generic and Linq only.
Some more constructive feed back would be nice instead this...
Felt lazy and the datapacket is just a class I'm using over and over and never really modifying it. Hence why it's not commented or documented at all.
I'm not wasting my time removing namespaces that I don't use and as I can't remember the short key for it then as lazy as I am I'll just leave them and the System namespace is always in use lol, so it'd be Collections.Generic and Linq only.
Some more constructive feed back would be nice instead this...
Well you find this non constructive
i was just pointing you out because i wanted your code to be elegant and clean ;However, i see your code perfect and doing the job...
Also in DataPacket you don't have to add using System;, simply because you only needed it 2 time but you just added System before the code
Also can i use your Method of writing and reading (DataPacket.cs) the packets in my -non conquer related- project ? it will save me sometime writing one
Also can i use your Method of writing and reading (DataPacket.cs) the packets in my -non conquer related- project ? it will save me sometime writing one
I like to type the whole namespace out for System.Buffer. Most likely a personal preference and yes you can lol it's not like it's anything special.
i've had some hard time understanding IAsyncResult and call backs , so i did search
and here what i found out (i did fully understand it as it was explained in pretty easy way and WAY BETTER than msdn ) so im sharing them for everyone
Quote:
The IAsyncResult interface represents an operation (such as a web request or a database call) that is running in the background, while your code continues to execute. It can tell you whether the operation finished (the IsCompleted property). It also gives you a WaitHandle object (the AsyncWaitHandle property) which can be used to wait until the operation finishes. (By calling result.AsyncWaitHandle.WaitOne())
You get an IAsyncResult by calling a BeginWhatever method. (BeginExecuteReader, BeginGetResponse, and many others). The BeginWhatever method will take any parameters needed for the operation (For example, BeginExecuteReader can take a CommandBehavior parameter), and can take an AsyncCallback delegate (not interface) and a state parameter. In returns an IAsyncResult object.
The AsyncCallback delegate is a method that you supply, which will be called when the operation finishes. It will usually be called on a different thread, so be careful in it. Your AsyncCallback method will be given the same IAsyncResult that the BeginWhatever method gave you earlier. The state parameter is put into the IAsyncResult and ignored by the system; you can use it in your AsyncCallback method to keep track of what the operation was for. (The state can be whatever you want it to be, including null)
Inside your AsyncCallback (or anywhere else), you can call the EndWhatever method that corresponds to the BeginWhatever method you called in the first place. You have to give it the IAsyncResult from BeginWhatever or from the AsyncCallback. When you call it, it will wait for the operation to finish (if it isn't already finished), and then give you back the operation's result. (Assuming the operation returns something; for example, WebRequest.EndGetResponse will return a WebResponse). If any error occurred during the operation, EndWhatever will throw an exception.
Quote:
A common use of internal access is in component-based development because it enables a group of components to cooperate in a private manner without being exposed to the rest of the application code. For example, a framework for building graphical user interfaces could provide Control and Form classes that cooperate using members with internal access. Since these members are internal, they are not exposed to code that is using the framework.
Quote:
EndAccept completes a call to BeginAccept. Before calling BeginAccept, you need to create a callback method that implements the AsyncCallback delegate. This callback method executes in a separate thread, and is called by the system after the BeginAccept method returns. It must accept the asyncResult parameter returned from the BeginAccept method.
Within the callback method, call the AsyncState method of the asyncResult parameter to obtain the Socket on which the connection attempt is being made. After obtaining the Socket, you can call the EndAccept method to successfully complete the connection attempt.
The EndAccept method blocks until a connection is pending in the incoming connection queue. The EndAccept method accepts the incoming connection and returns a new Socket that can be used to send data to and receive data from the remote host.
Quote:
The EndReceive method completes the asynchronous read operation started in the BeginReceive method.
Before calling BeginReceive, you need to create a callback method that implements the AsyncCallback delegate. This callback method executes in a separate thread and is called by the system after BeginReceive returns. The callback method must accept the IAsyncResult returned by the BeginReceive method as a parameter.
Within the callback method, call the AsyncState method of the IAsyncResult to obtain the state object passed to the BeginReceive method. Extract the receiving Socket from this state object. After obtaining the Socket, you can call the EndReceive method to successfully complete the read operation and return the number of bytes read.
The EndReceive method will block until data is available. If you are using a connectionless protocol, EndReceive will read the first enqueued datagram available in the incoming network buffer. If you are using a connection-oriented protocol, the EndReceive method will read as much data as is available up to the number of bytes you specified in the size parameter of the BeginReceive method. If the remote host shuts down the Socket connection with the Shutdown method, and all available data has been received, the EndReceive method will complete immediately and return zero bytes.
To obtain the received data, call the AsyncState method of the IAsyncResult, and extract the buffer contained in the resulting state object.
To cancel a pending BeginReceive, call the Close method.
Quote:
The Monitor class controls access to objects by granting a lock for an object to a single thread. Object locks provide the ability to restrict access to a block of code, commonly called a critical section. While a thread owns the lock for an object, no other thread can acquire that lock. You can also use Monitor to ensure that no other thread is allowed to access a section of application code being executed by the lock owner, unless the other thread is executing the code using a different locked object.
Monitor.TryEnter(Object, int32) Attempts to acquire an exclusive lock on the specified object, and atomically sets a value that indicates whether the lock was taken.
Monitor.Exit Releases an exclusive lock on the specified object.
i took those form msdn as those what jacob used at this example , one does the look for 50 ms which is enough to try sending the packet and one release the lock so the next buffer could use baseSocket.BeginSend
check out for more
i duno why i find this better than locks >.<
to be edited if i found another method/interface that i can't understand and found good explanation for it around
so far i've mentioned iasyncresult , internal and socket endaccept , and yes im going in sequence as im reading it (also doing a flow chart with methods on sketch to fully understand the logic and how the system work)
btw most of information i post and explanation is from stackoverflow and msdn
---------------------------------------------------------------------------------------------
hybrid i got question about
Quote:
You may have tested this on a private server and had success, but I noticed one thing in your receive body (as well as your receive header) part which will fail in a proxy environment. You may the assumption when you say "I want to receive n-bytes" you receive n-bytes, and if you don't, you drop the connection. In the real world however, fragmentation occurs and you may only receive a fraction of a n-bytes and may need to continue receiving until n-bytes has been read in total.
thanks for this information , but i got a question , i should not disconnect if i didn't receive the size of packet i read on the header , i should continue receiving until i get that n-bytes , so they may get delayed but server must send it , right ?
----------------------------------------------------------------------------------------------
jacob i've been 19 hrs learning from this and i enjoyed it and the logic , also it improved my programming skills was damn confusing until i made something crazy which u may scream my face off for
here
---------------------------------------------------------------------------------------------
hybrid i got question about
thanks for this information , but i got a question , i should not disconnect if i didn't receive the size of packet i read on the header , i should continue receiving until i get that n-bytes , so they may get delayed but server must send it , right ?
Typically, you may not receive the entire packet at the same time this occurs to fragmentation. So, your code becomes circular until nBytes has been received like this (I haven't actually tested it, but it should give you a fairly good idea of what I mean by circular):
Code:
public class ReceiveAsyncBuffer
{
public bool OperationInProgress { get; private set; }
public byte[] Buffer { get; private set; }
public int Received { get { return offset; } }
private Socket target;
private int offset;
private int left;
private Action<bool> callback;
public ReceiveAsyncBuffer(int size)
{
Buffer = new byte[size];
}
public void Receive(Socket socket, int size, Action<bool> complete)
{
if (OperationInProgress)
throw new InvalidOperationException("another receive operation is already in progress");
if (complete == null)
throw new ArgumentNullException("complete delegate cannot be null");
this.target = socket;
this.offset = 0;
this.left = size;
this.callback = complete;
this.OperationInProgress = true;
this.BlockReceive();
}
private void BlockReceive()
{
try
{
this.target.BeginReceive(this.Buffer, this.offset, this.left, SocketFlags.None,
(result) =>
{
try
{
int nRecv = this.target.EndReceive(result);
if (nRecv <= 0)
{
this.OperationInProgress = false;
this.callback(false); // fail
}
else
{
this.left -= nRecv;
this.offset += nRecv;
if (this.left == 0)
{
this.OperationInProgress = false;
this.callback(true); // done
}
else
BlockReceive();
}
}
catch (Exception)
{
this.OperationInProgress = false;
this.callback(false);
}
}, null);
}
catch (Exception)
{
this.OperationInProgress = false;
this.callback(false); // failed
}
}
}
As I got quite busy yesterday with my presentation for exam which I had today and haven't got the time rewrite it then I'll eventually do it today I think
As I got quite busy yesterday with my presentation for exam which I had today and haven't got the time rewrite it then I'll eventually do it today I think
[Release] EXP/SP Rates splitter 02/18/2024 - SRO PServer Guides & Releases - 38 Replies so,this project was only in underground section,but i decided to release it here,
this is a patcher which sets sp rates,so now you can make smth like:
exp rates:200x
sp rates:300x
download in attachments (source code included)
this works only for vsro 188 serverfiles
put it in your serverfiles folder,run Rates Splitter.exe (make sure your gameserver is called SR_GameServer.exe) and set your rates
Async Socket Wrapper 11/11/2011 - CO2 Programming - 8 Replies So I was bored and thought I would code a socket wrapper. It's a class library, but full project is available for download + an example use for a socket server.
It contains both wrapper for server and client stuff, which means it can be used for either private servers as server-socket or for a proxy.
WinAsync - This class contains all the events.
public delegate void WinEvent(WinClient wClient);
public delegate void WinBufferEvent(WinClient wClient, WinBuffer Buffer);
...
[VK]Splitter entfernen! 06/08/2011 - Metin2 Trading - 0 Replies Verkaufe Stein-Handbuch!
Verkaufe auf S25 Leviathan einen Account(Level 1,hat ein Stein-Handbuch).
Damit kannst du deine Splitter aus einen beliebiegen Gegenstand entfernen!
Nehme nur E*Gold!
Macht Gebote!
[How To]Splitter Enfernen 11/03/2008 - Metin2 Guides & Templates - 20 Replies Hi,
Ich sage euch nun wie ihr Splitter enfernen koennt wenn ihr welche in euren waffen bzw ruetungen habt.Das geht auf jedem Server (ausser deutschen)!.Zuerst muesst ihr lvl 25 erreicht haben was nicht ausserordentlich schwer ist auf longju,Us,chinatown usw :D.Danach geht ihr zu Deokbae (dem holzfaeller) in map2 und klickt auf ihn.Das muesste dann ca so aussehen : 黄金斧.Danach geht ihr (egal welches lvl ihr seit also koennt auch lvl 70 sein^^) St.Wilde Generaele killen.Irgendwann nach langem...
Splitter-,- 08/31/2008 - Metin2 Private Server - 15 Replies huhu,
wollt mal fragn ob es am markt auch splitter entfernen gibt?
Und wenn ja wie sieht das aus?
oder kann mir das jemand ingame verkaufn der itemshopt...