-
[C# - Development] Jolt Environment
Hey
Over the last 2 weeks or so, I've been working on a project called "Jolt Environment", basically a framework for RuneScape, but "Jolt" is an environment, which is powered by MySQL and ION storage, and TCP asynchronous connections. Everything runescape is within the namespace "RuneScape", and everything in Jolt, is not requiring anything from that, so logically, you can basically delete the runescape namespace, and create a emulator of your own usage Jolt
Requirements to Edit / Run:
VS10 with .NET 4.0
MySQL database
Source is well commented for people willing to learn
Connection/NET for MySQL connection is in /Resources/ and also in /Bin/Drivers/ - You don't need to do anything, the emulator automatically loads the drivers for you
You can check out the source & the project @ http://ajravindiran.com/projects/jolt/
Feedback so i can improve :)
-
Re: [C# - Development] Jolt Environment
Now will this be using the same items and information as the original Runescape or will it be very custimized using the same playingfield?
-
Re: [C# - Development] Jolt Environment
I will be making it as original as runescape, the server will be really customizable, so it'll be up to the server owner for customization of NPCs, items, objects, and so forth
-
Re: [C# - Development] Jolt Environment
If you ever think about making it closed source I might be interested in helping out. :)
-
Re: [C# - Development] Jolt Environment
I've been monitoring this since before he made it public. This is gonna be the most lean framework ever created for RuneScape. Load speeds are incredulously fast, and the asynchronous socket protocol creates more efficiency with less need for looping code. Unlike anything ever released, I highly recommend people start learning this base for future development. If I ever manage, I'll even program for this as well
-
Re: [C# - Development] Jolt Environment
-
Re: [C# - Development] Jolt Environment
Quote:
Originally Posted by
jMerliN
Iocp?
Asynchronous .NET sockets inherently use IOCP. This is the .NET framework we're talking about.
-
Re: [C# - Development] Jolt Environment
Havn't been doing much this week(end), But I've redone the byte vectors (streams).
Isn't really an "improvement", it is basically just more readable, and easier to work with.
CodecFactory.cs:
Code:
/* ######################################## *\
* ### Copyright (C) 2009 AJ Ravindiran ### *
* ### HTTP://THEAJ.NET/ <AJ@THEAJ.NET> ### *
\* ######################################## */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AJRavindiran.Jolt.RuneScape.Network.Codecs
{
/// <summary>
/// Represents a codec factory which controls incoming and outgoing bytevectors.
/// </summary>
public class CodecFactory
{
#region Fields
private int mInputOffset = 0;
private int mInputLength = 0;
private byte[] mInputBuffer;
private int mOutputOffset = 0;
private int mOutputLength = 0;
private byte[] mOutputBuffer;
private int mFrameStackPtr = -1;
private static int mFrameStackSize = 10;
private int[] mFrameStack = new int[mFrameStackSize];
private int[] mBitMaskOut = new int[32];
private int mBitPosition = 0;
#endregion
#region Properties
public int InputOffset
{
get { return mInputOffset; }
set { mInputOffset = value; }
}
public int InputLength
{
get { return mInputLength; }
set { mInputLength = value; }
}
public byte[] InputBuffer
{
get { return mInputBuffer; }
set { mInputBuffer = value; }
}
public int OutputOffset
{
get { return mOutputOffset; }
set { mOutputOffset = value; }
}
public int OutputLength
{
get { return mOutputLength; }
set { mOutputLength = value; }
}
public byte[] OutputBuffer
{
get { return mOutputBuffer; }
set { mOutputBuffer = value; }
}
#endregion
#region Constructors
public CodecFactory(int inputLength, int outputLength)
{
mInputLength = inputLength;
mOutputLength = outputLength;
mInputBuffer = new byte[inputLength];
mOutputBuffer = new byte[outputLength];
for (int i = 0; i < 32; i++)
mBitMaskOut[i] = (1 << i) - 1;
}
#endregion
#region Methods
public byte ReadByte()
{
return (byte)(mInputBuffer[mInputOffset++]);
}
public int ReadSByte()
{
return (ReadByte() & 0xff);
}
public byte ReadByteA()
{
return (byte)(ReadByte() - 128);
}
public byte ReadByteC()
{
return (byte)(-ReadByte());
}
public byte ReadByteS()
{
return (byte)(128 - ReadByte());
}
public int ReadSByteA()
{
return (ReadSByte() - 128 & 0xff);
}
public int ReadSByteC()
{
return -(ReadSByte() & 0xff);
}
public int ReadSByteS()
{
return (128 - ReadSByte() & 0xff);
}
public int Read3Bytes()
{
return (ReadSByte() << 16) | (ReadSByte() << 8) | ReadSByte();
}
public int Read2Bytes()
{
return (ReadSByte() << 8) + ReadSByte();
}
public CodecFactory ReadBytes(byte[] array, int endOffset, int startOffSet)
{
for (int i = startOffSet; i < startOffSet + endOffset; i++)
array[i] = ReadByte();
return this;
}
public CodecFactory ReadBytesReserved(byte[] array, int endOffset, int startOffSet)
{
for (int i = (startOffSet + endOffset) - 1; i >= startOffSet; i--)
array[i] = ReadByte();
return this;
}
public CodecFactory ReadBytesReserved128(byte[] array, int endOffset, int startOffset)
{
for (int i = (startOffset + endOffset) - 1; i >= startOffset; i--)
array[i] = ReadByteA();
return this;
}
public int ReadInt16()
{
mInputOffset += 2;
int i = ((mInputBuffer[mInputOffset - 2] & 0xff) << 8) + (mInputBuffer[mInputOffset - 1] & 0xff);
if (i > 32767)
i -= 0x10000;
return i;
}
public int ReadInt16A()
{
mInputOffset += 2;
int i = ((mInputBuffer[mInputOffset - 1] & 0xff) << 8)
+ (mInputBuffer[mInputOffset - 2] - 128 & 0xff);
if (i > 32767)
i -= 0x10000;
return i;
}
public int ReadInt16Endian()
{
mInputOffset += 2;
int i = ((mInputBuffer[mInputOffset - 1] & 0xff) << 8)
+ (mInputBuffer[mInputOffset - 2] & 0xff);
if (i > 32767)
i -= 0x10000;
return i;
}
public int ReadInt16EndianA()
{
mInputOffset += 2;
int i = ((mInputBuffer[mInputOffset - 1] & 0xff) << 8)
+ (mInputBuffer[mInputOffset - 2] - 128 & 0xff);
if (i > 32767)
i -= 0x10000;
return i;
}
public int ReadUInt16()
{
mInputOffset += 2;
return ((mInputBuffer[mInputOffset - 2] & 0xff) << 8)
+ (mInputBuffer[mInputOffset - 1] - 128 & 0xff);
}
public int ReadUInt16A()
{
mInputOffset += 2;
return ((mInputBuffer[mInputOffset - 2] & 0xff) << 8)
+ (mInputBuffer[mInputOffset - 1] - 128 & 0xff);
}
public int ReadUInt16Endian()
{
mInputOffset += 2;
return ((mInputBuffer[mInputOffset - 1] & 0xff) << 8)
+ (mInputBuffer[mInputOffset - 2] & 0xff);
}
public int ReadUInt16EndianA()
{
mInputOffset += 2;
return ((mInputBuffer[mInputOffset - 1] & 0xff) << 8)
+ (mInputBuffer[mInputOffset - 2] - 128 & 0xff);
}
public int ReadInt32()
{
mInputOffset += 4;
return ((mInputBuffer[mInputOffset - 4] & 0xff) << 24)
+ ((mInputBuffer[mInputOffset - 3] & 0xff) << 16)
+ ((mInputBuffer[mInputOffset - 2] & 0xff) << 8)
+ (mInputBuffer[mInputOffset - 1] & 0xff);
}
public int ReadInt32V1()
{
mInputOffset += 4;
return ((mInputBuffer[mInputOffset - 2] & 0xff) << 24)
+ ((mInputBuffer[mInputOffset - 1] & 0xff) << 16)
+ ((mInputBuffer[mInputOffset - 4] & 0xff) << 8)
+ (mInputBuffer[mInputOffset - 3] & 0xff);
}
public int ReadInt32V2()
{
mInputOffset += 4;
return ((mInputBuffer[mInputOffset - 3] & 0xff) << 24)
+ ((mInputBuffer[mInputOffset - 4] & 0xff) << 16)
+ ((mInputBuffer[mInputOffset - 1] & 0xff) << 8)
+ (mInputBuffer[mInputOffset - 2] & 0xff);
}
public long ReadInt64()
{
long l = (long)ReadInt32() & 0xffffffffL;
long l1 = (long)ReadInt32() & 0xffffffffL;
return (l << 32) + l1;
}
public long ReadInt64V2()
{
mInputOffset += 8;
return (((mInputBuffer[mInputOffset - 8] & 0xff) << 56)
+ ((mInputBuffer[mInputOffset - 7] & 0xff) << 48)
+ ((mInputBuffer[mInputOffset - 6] & 0xff) << 40)
+ ((mInputBuffer[mInputOffset - 5] & 0xff) << 32)
+ ((mInputBuffer[mInputOffset - 4] & 0xff) << 24)
+ ((mInputBuffer[mInputOffset - 3] & 0xff) << 16)
+ ((mInputBuffer[mInputOffset - 2] & 0xff) << 8)
+ (mInputBuffer[mInputOffset - 1] & 0xff));
}
public string ReadString()
{
StringBuilder sb = new StringBuilder();
byte b;
while ((b = ReadByte()) != 0)
sb.Append((char)b);
return sb.ToString();
}
public void ExpandOutBuffer()
{
byte[] oldBuffer = mOutputBuffer;
mOutputBuffer = new byte[oldBuffer.Length + 1000];
System.Array.Copy(oldBuffer, 0, mOutputBuffer, 0, oldBuffer.Length);
}
public CodecFactory AppendByte(int i)
{
if (mOutputOffset >= mOutputBuffer.Length)
ExpandOutBuffer();
mOutputBuffer[mOutputOffset++] = (byte)i;
return this;
}
public CodecFactory AppendByte(int i, int position)
{
if (position >= mOutputBuffer.Length)
ExpandOutBuffer();
mOutputBuffer[position] = (byte)i;
return this;
}
public CodecFactory AppendByteA(int i)
{
AppendByte(i + 128);
return this;
}
public CodecFactory AppendByteS(int i)
{
AppendByte(128 - i);
return this;
}
public CodecFactory AppendByteC(int i)
{
AppendByte(-i);
return this;
}
public CodecFactory AppendBytes(byte[] array, int endOffset, int startOffset)
{
for (int i = startOffset; i < startOffset + endOffset; i++)
AppendByte(array[i]);
return this;
}
public CodecFactory AppendBytesS(byte[] array, int endOffset, int startOffset)
{
for (int i = startOffset; i < startOffset + endOffset; i++)
AppendByte(-128 + array[i]);
return this;
}
public CodecFactory AppendBytesA(byte[] array, int endOffset, int startOffset)
{
for (int i = startOffset; i < startOffset + endOffset; i++)
AppendByte(array[i] - 128);
return this;
}
public CodecFactory AppendBytesC(byte[] array, int endOffset, int startOffset)
{
for (int i = startOffset; i < startOffset + endOffset; i++)
AppendByte(array[i] + 128);
return this;
}
public CodecFactory AppendBytesReverse(byte[] array, int endOffset, int startOffset)
{
for (int i = (startOffset + endOffset) - 1; i >= startOffset; i--)
AppendByte(array[i]);
return this;
}
public CodecFactory AppendBytesReverseA(byte[] array, int endOffset, int startOffset)
{
for (int i = (startOffset + endOffset) - 1; i >= startOffset; i--)
AppendByteA(array[i]);
return this;
}
public CodecFactory Append3Byte(int i)
{
AppendByte(i >> 16);
AppendByte(i >> 8);
AppendByte(i);
return this;
}
public CodecFactory AppendInt16(int i)
{
AppendByte(i >> 8);
AppendByte(i);
return this;
}
public CodecFactory AppendInt16A(int i)
{
AppendByte(i >> 8);
AppendByte(i + 128);
return this;
}
public CodecFactory AppendInt16Endian(int i)
{
AppendByte(i);
AppendByte(i >> 8);
return this;
}
public CodecFactory AppendInt16EndianA(int i)
{
AppendByte(i + 128);
AppendByte(i >> 8);
return this;
}
public CodecFactory AppendInt32(int i)
{
AppendByte(i >> 24);
AppendByte(i >> 16);
AppendByte(i >> 8);
AppendByte(i);
return this;
}
public CodecFactory AppendInt32Endian(int i)
{
AppendByte(i);
AppendByte(i >> 8);
AppendByte(i >> 16);
AppendByte(i >> 24);
return this;
}
public CodecFactory AppendInt32V1(int i)
{
AppendByte(i >> 8);
AppendByte(i);
AppendByte(i >> 24);
AppendByte(i >> 16);
return this;
}
public CodecFactory AppendInt32V2(int i)
{
AppendByte(i >> 16);
AppendByte(i >> 24);
AppendByte(i);
AppendByte(i >> 8);
return this;
}
public CodecFactory AppendInt64(long l)
{
AppendByte((int)(l >> 56));
AppendByte((int)(l >> 48));
AppendByte((int)(l >> 40));
AppendByte((int)(l >> 32));
AppendByte((int)(l >> 24));
AppendByte((int)(l >> 16));
AppendByte((int)(l >> 8));
AppendByte((int)l);
return this;
}
public byte[] StrToByteArray(string str)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
return encoding.GetBytes(str);
}
public CodecFactory AppendString(string s)
{
byte[] stringBytes = StrToByteArray(s);
for (int i = 0; i < s.Length; i++)
AppendByte(stringBytes[i]);
AppendByte(0);
return this;
}
public CodecFactory AppendVarByte(int i)
{
if ((i & 255) >= 128)
AppendInt16(i - 32768);
else
AppendByte(i);
return this;
}
public CodecFactory CreateFrame(int id)
{
AppendByteA(id);
return this;
}
public CodecFactory CreateFrameByte(int id)
{
AppendByte(id);
AppendByte(0);
if (mFrameStackPtr >= mFrameStackSize - 1)
JoltEnvironment.GetLogger().WriteWarn("Stack overflow.");
else
mFrameStack[++mFrameStackPtr] = mInputOffset;
return this;
}
public CodecFactory CreateFrameInt16(int id)
{
AppendByte(id);
AppendByte(0);
if (mFrameStackPtr >= mFrameStackSize - 1)
JoltEnvironment.GetLogger().WriteWarn("Stack overflow.");
else
mFrameStack[++mFrameStackPtr] = mInputOffset;
return this;
}
public CodecFactory EndFrameByte()
{
if (mFrameStackPtr < 0)
JoltEnvironment.GetLogger().WriteWarn("Stack empty");
else
AppendFrameSize(mOutputOffset - mFrameStack[mFrameStackPtr--]);
return this;
}
public CodecFactory EndFrameInt16()
{
if (mFrameStackPtr < 0)
JoltEnvironment.GetLogger().WriteWarn("Stack empty");
else
AppendFrameSizeInt16(mOutputOffset - mFrameStack[mFrameStackPtr--]);
return this;
}
public CodecFactory AppendFrameSize(int i)
{
AppendByte(i, (mOutputOffset - i - 1));
return this;
}
public CodecFactory AppendFrameSizeInt16(int i)
{
AppendByte((i >> 8), (mOutputOffset - i - 2));
AppendByte(i, (mOutputOffset - i - 1));
return this;
}
public CodecFactory InitBitAccess()
{
mBitPosition = mOutputOffset * 8;
return this;
}
public CodecFactory FinishBitAccess()
{
mOutputOffset = (mBitPosition + 7) / 8;
return this;
}
public CodecFactory AppendBit(int bit, int pos)
{
if (pos >= mOutputBuffer.Length)
ExpandOutBuffer();
mOutputBuffer[pos] &= (byte)~bit;
return this;
}
public CodecFactory PlaceBit(int bit, int pos)
{
if (pos >= mOutputBuffer.Length)
ExpandOutBuffer();
mOutputBuffer[pos] |= (byte)bit;
return this;
}
public CodecFactory AppendBits(int numBits, int value)
{
int bytePos = mBitPosition >> 3;
int bitOffset = 8 - (mBitPosition & 7);
mBitPosition += numBits;
for (; numBits > bitOffset; bitOffset = 8)
{
AppendBit(mBitMaskOut[bitOffset], bytePos);
PlaceBit(((value >> (numBits - bitOffset)) & mBitMaskOut[bitOffset]), bytePos++);
numBits -= bitOffset;
}
if (numBits == bitOffset)
{
AppendBit(mBitMaskOut[bitOffset], bytePos);
PlaceBit((value & mBitMaskOut[bitOffset]), bytePos);
}
else
{
AppendBit((mBitMaskOut[numBits] << (bitOffset - numBits)), bytePos);
PlaceBit((value & mBitMaskOut[numBits]) << (bitOffset - numBits), bytePos);
}
return this;
}
#endregion
}
}
From the older codec factory you would use the follow code to read / write streams to the runescape client:
Code:
character.GetCodecFactory().GetDecoder().ReadSignedByte();
character.GetCodecFactory().GetDecoder().ReadUnsignedDWord();
character.GetCodecFactory().GetEncoder().WriteByte(0);
character.GetCodecFactory().GetEncoder().WriteDWord(1);
character.GetCodecFactory().GetEncoder().WriteQWord(2);
character.GetCodecFactory().GetEncoder().WriteWord128(3);
character.GetCodecFactory().GetEncoder().WriteUnsignedByte(4);
character.GetCodecFactory().GetEncoder().WriteString("something");
Now:
Code:
character.GetCodecFactory().ReadByte();
character.GetCodecFactory().ReadInt32();
character.GetCodecFactory()
.AppendByte(0)
.AppendInt32(1)
.AppendInt64(2)
.AppendInt16A(3)
.AppendSByte(4)
.AppendString("something");
-
Re: [C# - Development] Jolt Environment
I suggest you to use SocketAsyncEventArgs in your network code, It's just a more scalable solution created especially for network server applications that require high performance such as a mmorpg server.
http://msdn.microsoft.com/en-us/libr...eventargs.aspx
-
Re: [C# - Development] Jolt Environment
This looks really nice if you have a beta testing for it i would love to try it.
-
Re: [C# - Development] Jolt Environment
So its like how mta uses lua, and samp uses pawno?
-
Re: [C# - Development] Jolt Environment
Added XML parsing yesterday... well, it was already there, but was a temporary placement so i can load some configurations, so basically an improvement. Also updated some old shit, and worked a bit more on character details
Details of the updates:
http://jolte.codeplex.com/SourceCont...leCommits.aspx
http://jolte.codeplex.com/SourceCont...set/view/38372
Example of how i would use the XML before:
Code:
XML config = new XML();
string name = config.ReadValue("config.xml", "server-name");
now:
Code:
string name = "";
JoltEnvironment.GetXML("config").AssignValue("server-name", ref name);
Also can do multiple assignments at once
Code:
string name = "";
string location = "";
string expRate = "";
JoltEnvironment.GetXML("config")
.AssignValue("server-name", ref name)
.AssignValue("default-location", ref location)
.AssignValue("exp-rate", ref expRate);
string[] coords = new string[3];
coords = name.Split(';');
RuneScape.GetConfig().ServerName = name;
RuneScape.GetConfig().ExperienceRate = double.Parse(expRate);
RuneScape.GetConfig().DefaultLocation = new Location(int.Parse(coords[0]), int.Parse(coords[1]), int.Parse(coords[2]));
---------- Post added at 08:43 PM ---------- Previous post was at 08:11 PM ----------
PS. sorry for the slow progress, i really dislike having to work on such over the summer.
-
Re: [C# - Development] Jolt Environment
Haha, I understand :).
But AJ, I really have to admit, your really going at this. So far, the interface is amazing, the feel of the program feels, original and not overbearing. The source is so nice, I don't think I have seen a new C# Programmer make something this great. Nicely organized. Maybe someday people will respect me the same way they respect you, but I got awhile to go. If you ever need a little advice or help, you can always ask me.
Good luck AJ!
-
Re: [C# - Development] Jolt Environment
Thanks mate, always appriated these types of comments, makes me feel better what i'm working on, enforcing me to work more efficient etc :P
PS. here's a better explanation of the XML example i gave in my last post:
Code:
/* ######################################## *\
* ### Copyright (C) 2009 AJ Ravindiran ### *
* ### HTTP://THEAJ.NET/ <AJ@THEAJ.NET> ### *
\* ######################################## */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AJRavindiran.Jolt.RuneScape.Configuration;
using AJRavindiran.Jolt.RuneScape.Models.Characters.Information;
namespace AJRavindiran.Jolt.RuneScape.Utilities.Loaders
{
/// <summary>
/// Represents a game configuration loader which is used to load the "game" configurations.
/// </summary>
public class GameConfiguratinLoader
{
#region Properties
private string mLocationX, mLocationY, mLocationZ, mServerName, mExerpienceRate;
#endregion
#region Constructor
/// <summary>
/// Constructs a new GameConfigurationLoader class.
/// Gives values to the temporary fields.
/// </summary>
public GameConfiguratinLoader()
{
// Assign temporary fields.
JoltEnvironment.GetXML("config")
.AssignValue("location-x", ref mLocationX)
.AssignValue("location-y", ref mLocationY)
.AssignValue("location-z", ref mLocationZ)
.AssignValue("server-name", ref mServerName)
.AssignValue("experience-rate", ref mExerpienceRate);
// Assign official fields.
this.parseConfigs();
}
#endregion
#region Methods
/// <summary>
/// Parses the configurations, and assigns values.
/// </summary>
private void parseConfigs()
{
RuneScape.GetGameConfig().DefaultLocation = new Location(
int.Parse(mLocationX),
int.Parse(mLocationY),
int.Parse(mLocationZ));
RuneScape.GetGameConfig().ServerName = mServerName;
RuneScape.GetGameConfig().ExperienceRate = double.Parse(mExerpienceRate);
}
#endregion
}
}
-
Re: [C# - Development] Jolt Environment
Awesome stuff AJ.
Its good to see your working on the internal stuff and tidying that up before working on the games features.
Good Luck with this! id love to follow it.
-
Re: [C# - Development] Jolt Environment
Nice project, i'm building an 317 server of c#, started a month ego i don't spend much time on it, since i cannot get cryption and stream 100% converted :P
-
Re: [C# - Development] Jolt Environment
Quote:
Originally Posted by
laurens
Nice project, i'm building an 317 server of c#, started a month ego i don't spend much time on it, since i cannot get cryption and stream 100% converted :P
You should try making it by yourself mate, converting may be easy, but what's the point? you're not learning :(:
-
Re: [C# - Development] Jolt Environment
The problem is since c# does not support >>>
to convert i'm using
k1 ^= l1 >>> 16; to k1 ^= Math.Abs(l1) >> 16;
only not sure if it works 100% :P is that the correct way to convert it? or i'm screwing it up :P
-
Re: [C# - Development] Jolt Environment
The "> or <"'s are called shift operators (also called bitwise shifts), and JAVA has one with three(3) shifts which is used for unsigned sifting, which C#'s 2 shifts does automatically (any unsigned field)
So really,
Code:
k1 ^= l1 >> 16; to k1 ^= Math.Abs(l1) >> 16;
will do the same as it would in JAVA
please back to topic :P
-
Re: [C# - Development] Jolt Environment
I plan on adding a lot to this project, when will you have that "directory" set up for me?
-
Re: [C# - Development] Jolt Environment
Quote:
Originally Posted by
King Izu
Asynchronous .NET sockets inherently use IOCP. This is the .NET framework we're talking about.
This is not true.
-
Re: [C# - Development] Jolt Environment
-
Re: [C# - Development] Jolt Environment
What's the deal with this codec stuff? This is just the stuff of binary streams... (BinaryReader/BinaryWriter etc).
And templates would make that over 9000 times nicer :).
-
Re: [C# - Development] Jolt Environment
I knew about the binary reader and writer, just wasn't sure if they're going to do what i wanted them to do
Also, what do you mean by templates?
-
Re: [C# - Development] Jolt Environment
Quote:
Originally Posted by
TheAJ
I knew about the binary reader and writer, just wasn't sure if they're going to do what i wanted them to do
Also, what do you mean by templates?
Code:
template <typename T>
T read_basic() {
if(!curbuf) return T(0);
if(sizeof(T)>(size-ptr)) return T(0); // Teh fail, buffer overflow prevention
T retval = *((T*)(curbuf+ptr));
ptr += sizeof(T);
return retval;
}
template <typename T>
READ_RESULT read_copy(T* t) {
if(!curbuf)return READ_NOBUFFER;
if(sizeof(T)>(size-ptr)) return READ_EOF; // Teh fail, buffer overflow prevention
memcpy(t,(curbuf+ptr),sizeof(T)); // Replace with interface copy?
ptr+=sizeof(T);
return READ_SUCCESS;
}
// object reading deserializes an object from the stream, KEWL!
READ_RESULT read_object(Deserializable* obj) {
return obj->deserialize(this);
}
template <typename T>
BinaryReader& operator >>(T& obj){
read_copy<T>((T*)&obj);
return *this;
}
Etc etc etc.
-
Re: [C# - Development] Jolt Environment
Alright guys... this might piss you off, but I've started the project from scratch.. again :P
Reason being is i keep learning more and more, and when i look back at my work, it just loops like a massive dump of shit. So i promise this will be my last restart :)
You can however download the older version here: http://rapidshare.com/files/267476411/Jolt.zip - Enjoy.
-
Re: [C# - Development] Jolt Environment
No, you have a disease many programmers have. It has to do with learning faster then you can complete projects.
It's all part of being a beginner programmer. I have the same problem with things..
>.<
-
Re: [C# - Development] Jolt Environment
Quote:
Originally Posted by
s-p-n
No, you have a disease many programmers have. It has to do with learning faster then you can complete projects.
It's all part of being a beginner programmer. I have the same problem with things..
>.<
Yeah i regret starting this project so early in my C# learning :laugh:
-
Re: [C# - Development] Jolt Environment
lol.
Well good luck Aj,
Hopefully it'll be 10x better this time round. :)
-
Quote:
Originally Posted by
iTyler
lol.
Well good luck Aj,
Hopefully it'll be 10x better this time round. :)
I know it pisses everyone off, but i guess it's better than a crapy version which everyone will complain about :(:
anyways, I've done some compatibility improvements, the server comes in 2 version, x86 and x64 bit
Also there is multi threading (+ thread pooling), and optimize for multiple cores (divides threads and handles on each core using Environment.ProcessorCount)
I'll do a svn commit later today so you guys can check it out - regardless, the redo is going great, just trying to improve everything that i've already done last version
Updates:
Added database handling / storage
Added multi threading (as said above) with thread pooling
Improved logging system
Improved support for x32 and x64 systems (as said above)
Picture of new console:
http://img12.imageshack.us/img12/7595/67338126.png
folders are also more organized:
http://img40.imageshack.us/img40/7202/50479774.png
console now logs all errors to a log file (option to turn it on and off also included in /config/system_console.xml)
http://img12.imageshack.us/img12/7559/62933992.png
-
Re: [C# - Development] Jolt Environment
Nicely Done! Looks like it was thought through very well, head-to-toe ;)
-
Re: [C# - Development] Jolt Environment
Try to avoid equitable division etc. Just pool all the resources together and design your system so that ACTIVE threads go through as few context switches as possible, meaning if 1 thread is active from a thread pool, before it goes back to sleep, it grabs another job if anything is available (assuming the thread pool is powered by a semaphore or something to pick up tasks etc).
Similarly, if you can assign thread affinity in C# (not sure), it's more efficient if your management scheme is setup this way. Windows may decide that your thread runs on a different core when it wakes up from a blocking state to do something, which causes a context switch. Additionally, your thread pool efficiency only goes down when # of available worker threads exceeds the # of CPUs in the system, so the above mention design choice was accurate.
And I still say re-design any networking component to use IOCP, with your own thread pool. It can be setup to flow in a wait-free manner which gives a great deal of speed with no resource contention which is perfect for emulator design (though it doesn't scale as well on lots of cores, a more direct thread pool of workers and job queue idea where your IOCP thread simply pulls jobs out of the IOCP's queue and enters them into your internal queue, then waits for more allows for much more async I/O, though it can make the framework much, much more complex to accompany things like async db queries, as it violates the idea of program flow).
-
Re: [C# - Development] Jolt Environment
Yeah i plan on changing the pooling a bit, I've only tested a single thread on each core, so i don't know how powerful it is yet.
I plan to change it up a bit, here's an example of how i want it to work:
there are 50 players
one thread worker has a minimum player value of 15, a max of 25, and a overload of 50, so right now, when the servers starts up the first thread will doesn't have a minimum value (else wise there'd be errors up my ass), so right now the thread has 50 players, and is overloaded, and now 1 more players logs in, a new worker thread is added, 26 players are now moved to the thread2, and the first thread is now locked until it reaches the minimum player value again, i'm probably not going to transfer the 26 players all at once, but probably one by one via a slave thread or so
---------- Post added at 03:41 PM ---------- Previous post was at 01:47 PM ----------
oh btw
i also added commands, doesn't interupt the server in any way, unless you use the shutdown command or something
http://img232.imageshack.us/img232/9013/44553981.jpg
-
Re: [C# - Development] Jolt Environment
Nice job man!
I'm really waiting to see this project finished.
-
Re: [C# - Development] Jolt Environment
Quote:
Originally Posted by
TheAJ
Yeah i plan on changing the pooling a bit, I've only tested a single thread on each core, so i don't know how powerful it is yet.
I plan to change it up a bit, here's an example of how i want it to work:
there are 50 players
one thread worker has a minimum player value of 15, a max of 25, and a overload of 50, so right now, when the servers starts up the first thread will doesn't have a minimum value (else wise there'd be errors up my ass), so right now the thread has 50 players, and is overloaded, and now 1 more players logs in, a new worker thread is added, 26 players are now moved to the thread2, and the first thread is now locked until it reaches the minimum player value again, i'm probably not going to transfer the 26 players all at once, but probably one by one via a slave thread or so
---------- Post added at 03:41 PM ---------- Previous post was at 01:47 PM ----------
oh btw
i also added commands, doesn't interupt the server in any way, unless you use the shutdown command or something
http://img232.imageshack.us/img232/9013/44553981.jpg
If you're doing C# why not use the Asynchronous built in framework? BeginAccept, BeginSend, BeginRecieve, etc. I have ran a nice server with close to 400 players with no issues using those callbacks. Also, for your log (I didn't look through it much) why are you passing a reference for a string. Is it intended to be edited?
-
Re: [C# - Development] Jolt Environment
Quote:
Originally Posted by
Theoretical
If you're doing C# why not use the Asynchronous built in framework? BeginAccept, BeginSend, BeginRecieve, etc. I have ran a nice server with close to 400 players with no issues using those callbacks.
I'm already using Asynchronous I/O
Quote:
Originally Posted by
Theoretical
Also, for your log (I didn't look through it much) why are you passing a reference for a string. Is it intended to be edited?
No clue what you mean :ehh:
-
Re: [C# - Development] Jolt Environment
/// <summary>
/// Prints out a log to the console depending on loglevel.
/// </summary>
private void PrintLog(StackFrame sf, LogLevel logLevel, ref string message)
you're passing a reference.
-
Yeah i thought i needed it since i was editing the next (adding date stamp, etc), i guess not
Updates:
- Sends update keys the client if needed
- Partial login server (only up to check for player in database)
http://img197.imageshack.us/img197/5609/77701690.jpg
The logs in gray are debug logs, they will be removed after i'm done with login
LoginWorker.cs (Thread running the process):
Code:
/* ######################################## *\
* ### Copyright (C) 2009 AJ Ravindiran ### *
\* ######################################## */
using System;
using System.Threading;
using AJRavindiran.Jolt.RuneScape.Models.Characters;
namespace AJRavindiran.Jolt.RuneScape.Workers
{
/// <summary>
/// Represents a worker.
/// </summary>
public class LoginWorker
{
#region Fields
private Thread loginWorkerThread;
#endregion Fields
#region Constructors
public LoginWorker()
{
Jolt.GetLog().WriteInfo("Constructing login worker...");
// Initialize the worker thread, set the normal priority, and start it.
this.loginWorkerThread = new Thread(new ThreadStart(Run));
this.loginWorkerThread.Priority = ThreadPriority.Normal;
this.loginWorkerThread.Start();
}
#endregion Constructors
#region Destructors
#endregion Destructors
#region Methods
/// <summary>
/// A thread which runs the login server processor every second.
/// </summary>
private void Run()
{
while (true)
{
Character[] queuedCharactersArray = new Character[
RuneScape.GetLoginServer().GetQueuedCharacters().Count];
RuneScape.GetLoginServer().GetQueuedCharacters().CopyTo(queuedCharactersArray);
foreach (Character c in queuedCharactersArray)
{
if (c.Online)
continue;
RuneScape.GetLoginServer().Process(c);
if (c.LoginStage == -1 || (Utilities.TimeUtilities.GetCurrentMilliseconds() - c.LoginTimeout) >= 15000)
{
RuneScape.GetLoginServer().GetQueuedCharacters().Remove(c);
if (!c.Online)
{
RuneScape.GetCharacterManager().UnRegister(c);
}
}
}
try
{
Thread.Sleep(100);
}
catch (Exception ex)
{
Jolt.GetLog().WriteException(ex);
}
}
}
#endregion Methods
}
}
LoginServer.cs:
Code:
/* ######################################## *\
* ### Copyright (C) 2009 AJ Ravindiran ### *
\* ######################################## */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AJRavindiran.Jolt.RuneScape.Models.Characters;
namespace AJRavindiran.Jolt.RuneScape.Network.Login
{
/// <summary>
/// Represents a login server.
/// </summary>
public class LoginServer
{
#region Fields
/// <summary>
/// Container for all queued characters.
/// </summary>
private HashSet<Character> queuedCharacters;
private LoginUpdateServer loginUpdateServer;
private LoginStreamBuffer loginStreamBuffer;
#endregion Fields
#region Constructors
/// <summary>
/// Constructs a new login server class.
/// </summary>
public LoginServer()
{
Jolt.GetLog().WriteInfo("Constructing login server...");
// Initialize the container.
this.queuedCharacters = new HashSet<Character>();
// Initialize sister clases.
this.loginUpdateServer = new LoginUpdateServer();
this.loginStreamBuffer = new LoginStreamBuffer();
}
#endregion Constructors
#region Methods
/// <summary>
/// Attempts to login all the users queued in the container.
/// </summary>
/// <param name="character"></param>
public void Process(Character character)
{
try
{
character.ServerSessionKey = ((long)(new Random().NextDouble() * 99999999D) << 32) + (long)(new Random().NextDouble() * 99999999D);
character.ClientSessionKey = 0;
LoginCodesEnumeration returnCode = LoginCodesEnumeration.LoginOK;
if (character.LoginStage < -1)
{
this.loginUpdateServer.SendUpdateKeys(character);
Jolt.GetLog().WriteDebug("Sending update keys (login stage -1)");
}
else if (character.LoginStage == 0)
{
Jolt.GetLog().WriteDebug("Login stage == 0");
try
{
if (!this.loginStreamBuffer.FillStream(character, 2))
{
Jolt.GetLog().WriteDebug("FillStream(2) failed.");
return;
}
}
catch (Exception) { return; }
byte connectionType = character.GetStreamReader().ReadByte();
Jolt.GetLog().WriteDebug("conection type: " + connectionType.ToString());
if (connectionType == 15)
{
this.loginUpdateServer.SendUpdateKeys(character);
character.LoginStage = -5;
return;
}
if (connectionType != 14)
{
character.LoginStage = -1;
return;
}
byte longPlayerName = character.GetStreamReader().ReadByte();
Jolt.GetLog().WriteDebug("Long player name: " + longPlayerName.ToString());
character.GetStreamWriter().WriteByte(0);
character.GetStreamWriter().WriteLong(character.ServerSessionKey);
this.loginStreamBuffer.DirectFlushStream(character);
character.LoginStage++;
}
else if (character.LoginStage == 1)
{
Jolt.GetLog().WriteDebug("login stage == 1");
try
{
if (!this.loginStreamBuffer.FillStream(character, 3))
{
Jolt.GetLog().WriteDebug("Fillstream(3) failed.");
return;
}
}
catch (Exception) { return; }
int loginType = character.GetStreamReader().ReadByte();
Jolt.GetLog().WriteDebug("login type: " + loginType.ToString());
if (loginType != 16 && loginType != 18 && loginType != 14)
{
character.LoginStage = -1;
return;
}
character.LoginStage++;
}
else if (character.LoginStage == 2)
{
Jolt.GetLog().WriteDebug("login stage == 2");
int loginPacketSize = character.GetStreamReader().ReadUShort();
Jolt.GetLog().WriteDebug("login packet size: " + loginPacketSize.ToString());
int loginEncryptPacketSize = loginPacketSize - (36 + 1 + 1 + 2);
Jolt.GetLog().WriteDebug("login encrypted size: " + loginEncryptPacketSize.ToString());
if (loginEncryptPacketSize <= 0)
{
character.LoginStage = -1;
return;
}
try
{
if (!this.loginStreamBuffer.FillStream(character, loginPacketSize))
{
Jolt.GetLog().WriteDebug("fillstream(packetsize) failed.");
return;
}
}
catch (Exception ex)
{
Jolt.GetLog().WriteException(ex);
return;
}
int clientVersion = character.GetStreamReader().ReadInt();
Jolt.GetLog().WriteDebug("client version: " + clientVersion.ToString());
if (clientVersion != 508)
{
character.LoginStage = -1;
return;
}
character.GetStreamReader().ReadByte();
character.GetStreamReader().ReadUShort();
character.GetStreamReader().ReadUShort();
for (int i = 0; i < 24; i++)
{
int cacheIndex = character.GetStreamReader().ReadByte();
}
string junk = character.GetStreamReader().ReadString();
for (int i = 0; i < 29; i++)
{
int junk2 = character.GetStreamReader().ReadInt();
}
loginEncryptPacketSize--;
byte junk29 = character.GetStreamReader().ReadByte();
byte encryption = character.GetStreamReader().ReadByte();
if (encryption != 10 & encryption != 64)
{
character.LoginStage = -1;
return;
}
character.ClientSessionKey = character.GetStreamReader().ReadLong();
character.ServerSessionKey = character.GetStreamReader().ReadLong();
character.Username = Utilities.MathUtilities.LongToString(character.GetStreamReader().ReadLong()).ToLower().Trim();
if (character.Username == null)
{
character.LoginStage = -1;
character.Username = "null";
return;
}
Jolt.GetLog().WriteDebug("username: " + character.Username);
for (int i = 0; i < character.Username.Length; i++)
{
char c = character.Username[i];
if (!char.IsLetterOrDigit(c) && !char.IsWhiteSpace(c))
{
character.LoginStage = -1;
character.Username = "null";
return;
}
}
if (RuneScape.GetCharacterManager().IsOnline(character))
returnCode = LoginCodesEnumeration.AlreadyOnline;
if (RuneScape.GetOffenceManager().GetBans().IsBanned(character))
returnCode = LoginCodesEnumeration.AccountDisabled;
if (RuneScape.GetOffenceManager().GetIPBans().IsBanned(character))
returnCode = LoginCodesEnumeration.AccountDisabled;
if (RuneScape.GetOffenceManager().GetMutes().IsMuted(character))
character.Muted = true;
string password = character.GetStreamReader().ReadString();
if (password == null)
{
character.LoginStage = -1;
return;
}
bool isValid = RuneScape.GetCharacterManager().GetLoader().Execute(character);
try
{
password = Utilities.Security.Cryptography.MD5[password];
}
catch (Exception ex)
{
Jolt.GetLog().WriteException(ex);
password = "null";
}
if (password != null && character.Password != null && character.Password != "null" && !character.Password.Equals(password) || !isValid)
returnCode = LoginCodesEnumeration.InvalidPassword;
// Set player online database.
character.GetStreamWriter().WriteByte((int)returnCode);
character.GetStreamWriter().WriteByte(character.Rights);
character.GetStreamWriter().WriteByte(0);
character.GetStreamWriter().WriteByte(0);
character.GetStreamWriter().WriteByte(0);
character.GetStreamWriter().WriteByte(1);
character.GetStreamWriter().WriteByte(0);
character.GetStreamWriter().WriteByte(character.ConnectionID);
character.GetStreamWriter().WriteByte(0);
this.loginStreamBuffer.DirectFlushStream(character);
}
}
catch (Login.Exceptions.InvalidLoginException ile)
{
throw ile;
}
}
/// <summary>
/// Add a character to the login queue.
/// </summary>
/// <param name="character">The player to queue in for login.</param>
public void AddToLoginQueue(Character character)
{
queuedCharacters.Add(character);
}
/// <summary>
/// Remove a player from the login queue.
/// </summary>
/// <param name="character">The player to queue out from the login.</param>
public void RemoveFromLoginQueue(Character character)
{
queuedCharacters.Remove(character);
}
/// <summary>
/// Accessor for the queued players hashset.
/// </summary>
/// <returns></returns>
public HashSet<Character> GetQueuedCharacters()
{
return this.queuedCharacters;
}
/// <summary>
/// Accessor for the update server class.
/// </summary>
/// <returns></returns>
public LoginUpdateServer GetUpdateServer()
{
return this.loginUpdateServer;
}
/// <summary>
/// Accessor for the stream buffer class.
/// </summary>
/// <returns></returns>
public LoginStreamBuffer GetStreamBuffer()
{
return this.loginStreamBuffer;
}
#endregion
}
}
LoginCodeEnumeration.cs:
Code:
/* ######################################## *\
* ### Copyright (C) 2009 AJ Ravindiran ### *
\* ######################################## */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AJRavindiran.Jolt.RuneScape.Network.Login
{
/// <summary>
/// Represents the login return codes.
/// </summary>
public enum LoginCodesEnumeration : byte
{
LoginOK = 2,
InvalidPassword = 3,
AccountDisabled = 4,
AlreadyOnline = 5,
WorldFull = 6,
TryAgain = 11
}
}
LoginStreamBuffer.cs:
Code:
/* ######################################## *\
* ### Copyright (C) 2009 AJ Ravindiran ### *
\* ######################################## */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AJRavindiran.Jolt.RuneScape.Network.Login
{
/// <summary>
/// Represents a login stream buffer.
/// </summary>
public class LoginStreamBuffer
{
#region Methods
/// <summary>
/// Check and read any incoming bytes.
/// </summary>
public bool FillStream(Models.Characters.Character character, int forceRead)
{
try
{
if (forceRead >= 500)
return false;
if (character.GetPlayerSocket().Availible < forceRead)
return false;
character.GetStreamReader().ReadOffset = 0;
character.GetPlayerSocket().Read(forceRead);
return true;
}
catch (StreamException se)
{
Jolt.GetLog().WriteException(se);
throw se;
}
}
/// <summary>
/// Send the bytes in the stream's outBuffer directly to the client.
/// </summary>
public void DirectFlushStream(Models.Characters.Character character)
{
try
{
character.GetPlayerSocket().Write(
character.GetStreamWriter().OutBuffer, 0,
character.GetStreamWriter().WriteOffset);
character.GetStreamWriter().WriteOffset = 0;
}
catch (StreamException se)
{
Jolt.GetLog().WriteException(se);
throw se;
}
}
#endregion Methods
}
}
LoginUpdateServer.cs:
Code:
/* ######################################## *\
* ### Copyright (C) 2009 AJ Ravindiran ### *
\* ######################################## */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AJRavindiran.Jolt.RuneScape.Network.Login
{
/// <summary>
/// Represents a login update server.
/// </summary>
public class LoginUpdateServer
{
#region Fields
/// <summary>
/// The update keys needed to update the r508 client.
/// </summary>
private int[] updateKeys =
{
0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xd8,
0x84, 0xa1, 0xa1, 0x2b, 0x00, 0x00, 0x00, 0xba,
0x58, 0x64, 0xe8, 0x14, 0x00, 0x00, 0x00, 0x7b,
0xcc, 0xa0, 0x7e, 0x23, 0x00, 0x00, 0x00, 0x48,
0x20, 0x0e, 0xe3, 0x6e, 0x00, 0x00, 0x01, 0x88,
0xec, 0x0d, 0x58, 0xed, 0x00, 0x00, 0x00, 0x71,
0xb9, 0x4c, 0xc0, 0x50, 0x00, 0x00, 0x01, 0x8b,
0x5b, 0x61, 0x79, 0x20, 0x00, 0x00, 0x00, 0x0c,
0x0c, 0x69, 0xb1, 0xc8, 0x00, 0x00, 0x02, 0x31,
0xc8, 0x56, 0x67, 0x52, 0x00, 0x00, 0x00, 0x69,
0x78, 0x17, 0x7b, 0xe2, 0x00, 0x00, 0x00, 0xc3,
0x29, 0x76, 0x27, 0x6a, 0x00, 0x00, 0x00, 0x05,
0x44, 0xe7, 0x75, 0xcb, 0x00, 0x00, 0x00, 0x08,
0x7d, 0x21, 0x80, 0xd5, 0x00, 0x00, 0x01, 0x58,
0xeb, 0x7d, 0x49, 0x8e, 0x00, 0x00, 0x00, 0x0c,
0xf4, 0xdf, 0xd6, 0x4d, 0x00, 0x00, 0x00, 0x18,
0xec, 0x33, 0x31, 0x7e, 0x00, 0x00, 0x00, 0x01,
0xf7, 0x7a, 0x09, 0xe3, 0x00, 0x00, 0x00, 0xd7,
0xe6, 0xa7, 0xa5, 0x18, 0x00, 0x00, 0x00, 0x45,
0xb5, 0x0a, 0xe0, 0x64, 0x00, 0x00, 0x00, 0x75,
0xba, 0xf2, 0xa2, 0xb9, 0x00, 0x00, 0x00, 0x5f,
0x31, 0xff, 0xfd, 0x16, 0x00, 0x00, 0x01, 0x48,
0x03, 0xf5, 0x55, 0xab, 0x00, 0x00, 0x00, 0x1e,
0x85, 0x03, 0x5e, 0xa7, 0x00, 0x00, 0x00, 0x23,
0x4e, 0x81, 0xae, 0x7d, 0x00, 0x00, 0x00, 0x18,
0x67, 0x07, 0x33, 0xe3, 0x00, 0x00, 0x00, 0x14,
0xab, 0x81, 0x05, 0xac, 0x00, 0x00, 0x00, 0x03,
0x24, 0x75, 0x85, 0x14, 0x00, 0x00, 0x00, 0x36
};
#endregion Fields
#region Methods
/// <summary>
/// If the connection is the client's update server than send the keys.
/// </summary>
public void SendUpdateKeys(Models.Characters.Character character)
{
try
{
if (character.LoginStage == 0)
{
if (!RuneScape.GetLoginServer().GetStreamBuffer().FillStream(character, 3))
return;
character.GetStreamWriter().WriteByte(0);
RuneScape.GetLoginServer().GetStreamBuffer().DirectFlushStream(character);
}
else if (character.LoginStage == -5)
{
if (!RuneScape.GetLoginServer().GetStreamBuffer().FillStream(character, 8))
return;
for (int i = 0; i < updateKeys.Length; i++)
character.GetStreamWriter().WriteByte(updateKeys[i]);
RuneScape.GetLoginServer().GetStreamBuffer().DirectFlushStream(character);
character.LoginStage = -1;
}
}
catch (Login.Exceptions.UpdateServerException use)
{
Jolt.GetLog().WriteException(use);
throw use;
}
}
#endregion Methods
}
}
Jolt Environment 1.0.2000: http://jolte.codeplex.com/Release/Pr...eleaseId=32148
Did a bench mark on the server, it's pretty good at handling multiple cores, spreads out evenly:
http://img42.imageshack.us/img42/4962/31812770.png
Dev blog: http://ajravindiran.com/projects/jolt/
more login:
http://img196.imageshack.us/img196/7...rtiallogin.png
-
Re: [C# - Development] Jolt Environment
Uhh.. shouldn't this be in the RS section?
-
Re: [C# - Development] Jolt Environment
Nice Aj, I've seen you progress a lot, you're doing such a great job! :P
Quote:
Originally Posted by
Monsta.
Uhh.. shouldn't this be in the RS section?
No, because it's in it's development process, and it's being programmed.
-
Re: [C# - Development] Jolt Environment
Quote:
Originally Posted by
Monsta.
Uhh.. shouldn't this be in the RS section?
No. As he's focusing on C# and not the game.
He chose to code the game in C#, but not only RuneScape can be run using this if you read more thoroughly.
-
Re: [C# - Development] Jolt Environment
-
Re: [C# - Development] Jolt Environment
Why are you doing asynchronous accept and synchronous data sending/reading? You should use asynchronous sending/receiving. Just look into BeginSend and BeginRecieve. Also for backup proof of my statement:
"The TcpClient class provides simple methods for connecting, sending, and receiving stream data over a network in synchronous blocking mode." So you should fix that ;3.
-
Re: [C# - Development] Jolt Environment
Quote:
Originally Posted by
Theoretical
Why are you doing asynchronous accept and synchronous data sending/reading? You should use asynchronous sending/receiving. Just look into BeginSend and BeginRecieve. Also for backup proof of my statement:
"The TcpClient class provides simple methods for connecting, sending, and receiving stream data over a network in synchronous blocking mode." So you should fix that ;3.
Been working on this since yesterday - I only did synchronous socketing so i can get an accurate result as my older emulator.
-
Re: [C# - Development] Jolt Environment
Quote:
Originally Posted by
Theoretical
Why are you doing asynchronous accept and synchronous data sending/reading? You should use asynchronous sending/receiving. Just look into BeginSend and BeginRecieve. Also for backup proof of my statement:
"The TcpClient class provides simple methods for connecting, sending, and receiving stream data over a network in synchronous blocking mode." So you should fix that ;3.
Sending doesn't really have to be asynchronous, but receiving should be. Async sending doesn't have a performance advantage until you're dealing with a huge number of connections, and even then it's a sore for memory consumption.
With 10000 connected users (yes, this is EASILY possible in a good emulator), assuming lots of activity, let's say 2-3 packets are queued for each user outgoing.
If your system isn't really smart with resource usage, you've got ~25,000 buffers dedicated to async operations until they all complete. Depending on how this is setup, that could be quite a lot of memory, and further, if your memory management system isn't top notch, those memory buffers might stick around for a bit before a garbage collector cleans them up (assuming a managed system), or they could be leaked.