mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-22 20:16:36 -04:00
Move network stuff to abstract socket
This commit is contained in:
parent
54a194c12f
commit
decc2116ca
85
MCGalaxy/Blocks/ExtBlock.cs
Normal file
85
MCGalaxy/Blocks/ExtBlock.cs
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright 2015 MCGalaxy
|
||||
|
||||
Dual-licensed under the Educational Community License, Version 2.0 and
|
||||
the GNU General Public License, Version 3 (the "Licenses"); you may
|
||||
not use this file except in compliance with the Licenses. You may
|
||||
obtain a copy of the Licenses at
|
||||
|
||||
http://www.opensource.org/licenses/ecl2.php
|
||||
http://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the Licenses are distributed on an "AS IS"
|
||||
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
or implied. See the Licenses for the specific language governing
|
||||
permissions and limitations under the Licenses.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace MCGalaxy {
|
||||
|
||||
/// <summary> Describes an extended block. (Meaning either a core, physics, or custom block) </summary>
|
||||
public struct ExtBlock : IEquatable<ExtBlock> {
|
||||
public byte BlockID, ExtID;
|
||||
|
||||
/// <summary> Constructs an extended block. </summary>
|
||||
public ExtBlock(byte block, byte extBlock) {
|
||||
BlockID = block; ExtID = extBlock;
|
||||
}
|
||||
|
||||
public static ExtBlock Air = new ExtBlock(Block.air, 0);
|
||||
public static ExtBlock Invalid = new ExtBlock(Block.Invalid, 0);
|
||||
|
||||
|
||||
/// <summary> Returns whether the type of this extended block is a physics block. </summary>
|
||||
public bool IsPhysicsType {
|
||||
get { return BlockID >= Block.CpeCount && BlockID != Block.custom_block; }
|
||||
}
|
||||
|
||||
/// <summary> Returns whether the type of this extended block is an invalid block. </summary>
|
||||
public bool IsInvalidType { get { return BlockID == Block.Invalid; } }
|
||||
|
||||
/// <summary> Returns the raw (for client side) block ID of this block. </summary>
|
||||
public byte RawID {
|
||||
get { return BlockID == Block.custom_block ? ExtID : BlockID; }
|
||||
}
|
||||
|
||||
public static ExtBlock FromRaw(byte raw) {
|
||||
ExtBlock block = default(ExtBlock);
|
||||
block.BlockID = raw;
|
||||
if (raw < Block.CpeCount) return block;
|
||||
|
||||
block.BlockID = Block.custom_block;
|
||||
block.ExtID = raw;
|
||||
return block;
|
||||
}
|
||||
|
||||
/// <summary> Constructs an extended block. </summary>
|
||||
public static explicit operator ExtBlock(byte block) { return new ExtBlock(block, 0); }
|
||||
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
return (obj is ExtBlock) && Equals((ExtBlock)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return BlockID | (ExtID << 8);
|
||||
}
|
||||
|
||||
public bool Equals(ExtBlock other) {
|
||||
return (BlockID == Block.custom_block && other.BlockID == Block.custom_block)
|
||||
? ExtID == other.ExtID : BlockID == other.BlockID;
|
||||
}
|
||||
|
||||
public static bool operator == (ExtBlock a, ExtBlock b) {
|
||||
return (a.BlockID == Block.custom_block && b.BlockID == Block.custom_block)
|
||||
? a.ExtID == b.ExtID : a.BlockID == b.BlockID;
|
||||
}
|
||||
|
||||
public static bool operator != (ExtBlock a, ExtBlock b) {
|
||||
return (a.BlockID == Block.custom_block && b.BlockID == Block.custom_block)
|
||||
? a.ExtID != b.ExtID : a.BlockID != b.BlockID;
|
||||
}
|
||||
}
|
||||
}
|
@ -567,6 +567,8 @@
|
||||
<Compile Include="Network\Packets\Packet.BlockDefs.cs" />
|
||||
<Compile Include="Network\Packets\Packet.CPE.cs" />
|
||||
<Compile Include="Network\Packets\Packet.cs" />
|
||||
<Compile Include="Network\Socket\INetworkSocket.cs" />
|
||||
<Compile Include="Network\Socket\TcpSocket.cs" />
|
||||
<Compile Include="Network\Utils\BufferedBlockSender.cs" />
|
||||
<Compile Include="Network\Utils\LevelChunkStream.cs" />
|
||||
<Compile Include="Network\Utils\NetUtils.cs" />
|
||||
@ -714,6 +716,7 @@
|
||||
<Folder Include="Database\Stats" />
|
||||
<Folder Include="Network\Heartbeat" />
|
||||
<Folder Include="Network\IRCPlugin" />
|
||||
<Folder Include="Network\Socket" />
|
||||
<Folder Include="Network\Utils" />
|
||||
<Folder Include="Network\Packets" />
|
||||
<Folder Include="Entity" />
|
||||
|
@ -23,43 +23,6 @@ using MCGalaxy.Network;
|
||||
namespace MCGalaxy {
|
||||
public sealed partial class Player : IDisposable {
|
||||
|
||||
static void Receive(IAsyncResult result) {
|
||||
//Server.s.Log(result.AsyncState.ToString());
|
||||
Player p = (Player)result.AsyncState;
|
||||
if (p.disconnected || p.socket == null) return;
|
||||
|
||||
try {
|
||||
int length = p.socket.EndReceive(result);
|
||||
if (length == 0) { p.Disconnect(); return; }
|
||||
|
||||
byte[] allData = new byte[p.leftBuffer.Length + length];
|
||||
Buffer.BlockCopy(p.leftBuffer, 0, allData, 0, p.leftBuffer.Length);
|
||||
Buffer.BlockCopy(p.tempbuffer, 0, allData, p.leftBuffer.Length, length);
|
||||
p.leftBuffer = p.ProcessReceived(allData);
|
||||
|
||||
if (p.dontmindme && p.leftBuffer.Length == 0) {
|
||||
Server.s.Log("Disconnected");
|
||||
p.socket.Close();
|
||||
p.disconnected = true;
|
||||
return;
|
||||
}
|
||||
if ( !p.disconnected )
|
||||
p.socket.BeginReceive(p.tempbuffer, 0, p.tempbuffer.Length, SocketFlags.None,
|
||||
new AsyncCallback(Receive), p);
|
||||
} catch ( SocketException ) {
|
||||
p.Disconnect();
|
||||
} catch ( ObjectDisposedException ) {
|
||||
// Player is no longer connected, socket was closed
|
||||
// Mark this as disconnected and remove them from active connection list
|
||||
connections.Remove(p);
|
||||
p.RemoveFromPending();
|
||||
p.disconnected = true;
|
||||
} catch ( Exception e ) {
|
||||
Server.ErrorLog(e);
|
||||
p.Leave("Error!");
|
||||
}
|
||||
}
|
||||
|
||||
public bool hasCpe, finishedCpeLogin = false;
|
||||
public string appName;
|
||||
public int extensionCount;
|
||||
@ -103,27 +66,7 @@ namespace MCGalaxy {
|
||||
}
|
||||
}
|
||||
|
||||
public void Send(byte[] buffer, bool sync = false) {
|
||||
// Abort if socket has been closed
|
||||
if (disconnected || socket == null || !socket.Connected) return;
|
||||
|
||||
try {
|
||||
if (sync)
|
||||
socket.Send(buffer, 0, buffer.Length, SocketFlags.None);
|
||||
else
|
||||
socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, delegate(IAsyncResult result) { }, null);
|
||||
buffer = null;
|
||||
} catch (SocketException e) {
|
||||
buffer = null;
|
||||
Disconnect();
|
||||
#if DEBUG
|
||||
Server.ErrorLog(e);
|
||||
#endif
|
||||
} catch (ObjectDisposedException) {
|
||||
// socket was already closed by another thread.
|
||||
buffer = null;
|
||||
}
|
||||
}
|
||||
public void Send(byte[] buffer, bool sync = false) { socket.Send(buffer, sync); }
|
||||
|
||||
public static void MessageLines(Player p, IEnumerable<string> lines) {
|
||||
foreach (string line in lines)
|
||||
@ -349,37 +292,9 @@ namespace MCGalaxy {
|
||||
Send(Packet.ExtAddPlayerName(id, listName, displayName, grp, grpRank, hasCP437));
|
||||
}
|
||||
|
||||
internal void CloseSocket() {
|
||||
// Try to close the socket.
|
||||
// Sometimes its already closed so these lines will cause an error
|
||||
// We just trap them and hide them from view :P
|
||||
try {
|
||||
// Close the damn socket connection!
|
||||
socket.Shutdown(SocketShutdown.Both);
|
||||
#if DEBUG
|
||||
Server.s.Log("Socket was shutdown for " + name ?? ip);
|
||||
#endif
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
#if DEBUG
|
||||
Exception ex = new Exception("Failed to shutdown socket for " + name ?? ip, e);
|
||||
Server.ErrorLog(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
try {
|
||||
socket.Close();
|
||||
#if DEBUG
|
||||
Server.s.Log("Socket was closed for " + name ?? ip);
|
||||
#endif
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
#if DEBUG
|
||||
Exception ex = new Exception("Failed to close socket for " + name ?? ip, e);
|
||||
Server.ErrorLog(ex);
|
||||
#endif
|
||||
}
|
||||
RemoveFromPending();
|
||||
internal void CloseSocket() {
|
||||
socket.Close();
|
||||
RemoveFromPending();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
37
MCGalaxy/Network/Socket/INetworkSocket.cs
Normal file
37
MCGalaxy/Network/Socket/INetworkSocket.cs
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright 2015 MCGalaxy
|
||||
|
||||
Dual-licensed under the Educational Community License, Version 2.0 and
|
||||
the GNU General Public License, Version 3 (the "Licenses"); you may
|
||||
not use this file except in compliance with the Licenses. You may
|
||||
obtain a copy of the Licenses at
|
||||
|
||||
http://www.opensource.org/licenses/ecl2.php
|
||||
http://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the Licenses are distributed on an "AS IS"
|
||||
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
or implied. See the Licenses for the specific language governing
|
||||
permissions and limitations under the Licenses.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace MCGalaxy.Network {
|
||||
|
||||
/// <summary> Abstracts sending to/receiving from a network socket. </summary>
|
||||
public interface INetworkSocket {
|
||||
|
||||
/// <summary> Gets the remote IP of this socket. </summary>
|
||||
string RemoteIP { get; }
|
||||
|
||||
/// <summary> Receives next block of received data, asynchronously. </summary>
|
||||
void ReceiveNextAsync();
|
||||
|
||||
/// <summary> Sends a block of data, either synchronously or asynchronously. </summary>
|
||||
void Send(byte[] buffer, bool sync = false);
|
||||
|
||||
/// <summary> Closes this network socket. </summary>
|
||||
void Close();
|
||||
}
|
||||
}
|
129
MCGalaxy/Network/Socket/TcpSocket.cs
Normal file
129
MCGalaxy/Network/Socket/TcpSocket.cs
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright 2010 MCSharp team (Modified for use with MCZall/MCLawl/MCGalaxy)
|
||||
Dual-licensed under the Educational Community License, Version 2.0 and
|
||||
the GNU General Public License, Version 3 (the "Licenses"); you may
|
||||
not use this file except in compliance with the Licenses. You may
|
||||
obtain a copy of the Licenses at
|
||||
http://www.opensource.org/licenses/ecl2.php
|
||||
http://www.gnu.org/licenses/gpl-3.0.html
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the Licenses are distributed on an "AS IS"
|
||||
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
or implied. See the Licenses for the specific language governing
|
||||
permissions and limitations under the Licenses.
|
||||
*/
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace MCGalaxy.Network {
|
||||
|
||||
/// <summary> Abstracts sending to/receiving from a TCP socket. </summary>
|
||||
public sealed class TcpSocket : INetworkSocket {
|
||||
readonly Player player;
|
||||
readonly Socket socket;
|
||||
byte[] leftBuffer = new byte[0];
|
||||
byte[] tempbuffer = new byte[0xFF];
|
||||
|
||||
public TcpSocket(Player p, Socket s) {
|
||||
player = p; socket = s;
|
||||
}
|
||||
|
||||
public string RemoteIP {
|
||||
// TODO: This is very icky
|
||||
get { return socket.RemoteEndPoint.ToString().Split(':')[0]; }
|
||||
}
|
||||
|
||||
|
||||
public void ReceiveNextAsync() {
|
||||
socket.BeginReceive(tempbuffer, 0, tempbuffer.Length, SocketFlags.None, new AsyncCallback(Receive), this);
|
||||
}
|
||||
|
||||
static void Receive(IAsyncResult result) {
|
||||
TcpSocket s = (TcpSocket)result.AsyncState;
|
||||
Player p = s.player;
|
||||
if (p.disconnected) return;
|
||||
|
||||
try {
|
||||
int length = s.socket.EndReceive(result);
|
||||
if (length == 0) { p.Disconnect(); return; }
|
||||
|
||||
byte[] allData = new byte[s.leftBuffer.Length + length];
|
||||
Buffer.BlockCopy(s.leftBuffer, 0, allData, 0, s.leftBuffer.Length);
|
||||
Buffer.BlockCopy(s.tempbuffer, 0, allData, s.leftBuffer.Length, length);
|
||||
s.leftBuffer = p.ProcessReceived(allData);
|
||||
|
||||
if (p.dontmindme && s.leftBuffer.Length == 0) {
|
||||
Server.s.Log("Disconnected");
|
||||
s.Close();
|
||||
p.disconnected = true;
|
||||
return;
|
||||
}
|
||||
if (!p.disconnected) s.ReceiveNextAsync();
|
||||
} catch (SocketException) {
|
||||
p.Disconnect();
|
||||
} catch (ObjectDisposedException) {
|
||||
// Player is no longer connected, socket was closed
|
||||
// Mark this as disconnected and remove them from active connection list
|
||||
Player.connections.Remove(p);
|
||||
p.RemoveFromPending();
|
||||
p.disconnected = true;
|
||||
} catch (Exception e) {
|
||||
Server.ErrorLog(e);
|
||||
p.Leave("Error!");
|
||||
}
|
||||
}
|
||||
|
||||
public void Send(byte[] buffer, bool sync = false) {
|
||||
// Abort if socket has been closed
|
||||
if (player.disconnected || !socket.Connected) return;
|
||||
|
||||
try {
|
||||
if (sync)
|
||||
socket.Send(buffer, 0, buffer.Length, SocketFlags.None);
|
||||
else
|
||||
socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, delegate(IAsyncResult result) { }, null);
|
||||
buffer = null;
|
||||
} catch (SocketException e) {
|
||||
buffer = null;
|
||||
player.Disconnect();
|
||||
#if DEBUG
|
||||
Server.ErrorLog(e);
|
||||
#endif
|
||||
} catch (ObjectDisposedException) {
|
||||
// socket was already closed by another thread.
|
||||
buffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Close() {
|
||||
// Try to close the socket.
|
||||
// Sometimes its already closed so these lines will cause an error
|
||||
// We just trap them and hide them from view :P
|
||||
try {
|
||||
// Close the damn socket connection!
|
||||
socket.Shutdown(SocketShutdown.Both);
|
||||
#if DEBUG
|
||||
Server.s.Log("Socket was shutdown for " + name ?? ip);
|
||||
#endif
|
||||
} catch (Exception e) {
|
||||
#if DEBUG
|
||||
Exception ex = new Exception("Failed to shutdown socket for " + name ?? ip, e);
|
||||
Server.ErrorLog(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
try {
|
||||
socket.Close();
|
||||
#if DEBUG
|
||||
Server.s.Log("Socket was closed for " + name ?? ip);
|
||||
#endif
|
||||
} catch (Exception e) {
|
||||
#if DEBUG
|
||||
Exception ex = new Exception("Failed to close socket for " + name ?? ip, e);
|
||||
Server.ErrorLog(ex);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ using MCGalaxy.Games;
|
||||
using MCGalaxy.Undo;
|
||||
using MCGalaxy.Maths;
|
||||
using MCGalaxy.Events;
|
||||
using MCGalaxy.Network;
|
||||
|
||||
namespace MCGalaxy {
|
||||
|
||||
@ -58,7 +59,8 @@ namespace MCGalaxy {
|
||||
public static string storedHelp = "";
|
||||
public string truename;
|
||||
internal bool dontmindme = false;
|
||||
public Socket socket;
|
||||
INetworkSocket socket;
|
||||
|
||||
public DateTime LastAction, AFKCooldown;
|
||||
public bool IsAfk = false, AutoAfk;
|
||||
public bool cmdTimer = false;
|
||||
@ -66,9 +68,6 @@ namespace MCGalaxy {
|
||||
public string BrushName = "normal", DefaultBrushArgs = "";
|
||||
public Transform Transform = NoTransform.Instance;
|
||||
public string afkMessage;
|
||||
|
||||
byte[] leftBuffer = new byte[0];
|
||||
byte[] tempbuffer = new byte[0xFF];
|
||||
public bool disconnected = false;
|
||||
|
||||
DateTime startTime;
|
||||
|
@ -33,7 +33,7 @@ namespace MCGalaxy {
|
||||
public sealed partial class Player : IDisposable {
|
||||
|
||||
bool removedFromPending = false;
|
||||
void RemoveFromPending() {
|
||||
internal void RemoveFromPending() {
|
||||
if (removedFromPending) return;
|
||||
removedFromPending = true;
|
||||
|
||||
@ -195,7 +195,7 @@ namespace MCGalaxy {
|
||||
return block == Block.air || (block >= Block.water && block <= Block.lavastill);
|
||||
}
|
||||
|
||||
byte[] ProcessReceived(byte[] buffer) {
|
||||
internal byte[] ProcessReceived(byte[] buffer) {
|
||||
try {
|
||||
int size = PacketSize(buffer);
|
||||
if (size == -2) return new byte[1]; // WoM get request
|
||||
|
@ -50,14 +50,14 @@ namespace MCGalaxy {
|
||||
public Player(Socket s) {
|
||||
spamChecker = new SpamChecker(this);
|
||||
try {
|
||||
socket = s;
|
||||
ip = socket.RemoteEndPoint.ToString().Split(':')[0];
|
||||
socket = new TcpSocket(this, s);
|
||||
ip = socket.RemoteIP;
|
||||
SessionID = Interlocked.Increment(ref sessionCounter) & SessionIDMask;
|
||||
Server.s.Log(ip + " connected to the server.");
|
||||
|
||||
for (byte i = 0; i < Block.CpeCount; i++) bindings[i] = i;
|
||||
|
||||
socket.BeginReceive(tempbuffer, 0, tempbuffer.Length, SocketFlags.None, new AsyncCallback(Receive), this);
|
||||
socket.ReceiveNextAsync();
|
||||
connections.Add(this);
|
||||
}
|
||||
catch ( Exception e ) { Leave("Login failed!"); Server.ErrorLog(e); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user