public static Packet MakeAddEntity( byte id, [NotNull] string name, Position pos ) { if( name == null ) throw new ArgumentNullException( "name" ); Packet packet = new Packet( OpCode.AddEntity ); packet.Bytes[1] = id; Encoding.ASCII.GetBytes( name.PadRight( 64 ), 0, 64, packet.Bytes, 2 ); ToNetOrder( pos.X, packet.Bytes, 66 ); ToNetOrder( pos.Z, packet.Bytes, 68 ); ToNetOrder( pos.Y, packet.Bytes, 70 ); packet.Bytes[72] = pos.R; packet.Bytes[73] = pos.L; return packet; }
public Map( int width, int length, int height ) { if( width < 16 || width > 2048 || length < 16 || length > 2048 || height < 16 || height > 2048 ) { throw new ArgumentException( "Invalid map dimension(s)." ); } Width = width; Length = length; Height = height; Volume = width*length*height; WaterLevel = Height/2; Blocks = new byte[Volume]; Spawn = new Position( Width*16, Length*16, Math.Min( Height*32, Int16.MaxValue ) ); }
public static Map Load( [NotNull] string fileName ) { if( fileName == null ) throw new ArgumentNullException( "fileName" ); using( FileStream mapStream = File.OpenRead( fileName ) ) { byte[] temp = new byte[8]; Map map = null; mapStream.Seek( -4, SeekOrigin.End ); mapStream.Read( temp, 0, 4 ); mapStream.Seek( 0, SeekOrigin.Begin ); int uncompressedLength = BitConverter.ToInt32( temp, 0 ); byte[] data = new byte[uncompressedLength]; using( GZipStream reader = new GZipStream( mapStream, CompressionMode.Decompress, true ) ) { reader.Read( data, 0, uncompressedLength ); } for( int i = 0; i < uncompressedLength - 1; i++ ) { if( data[i] != 0xAC || data[i + 1] != 0xED ) continue; // bypassing the header crap int pointer = i + 6; Array.Copy( data, pointer, temp, 0, 2 ); pointer += IPAddress.HostToNetworkOrder( BitConverter.ToInt16( temp, 0 ) ); pointer += 13; int headerEnd; // find the end of serialization listing for( headerEnd = pointer; headerEnd < data.Length - 1; headerEnd++ ) { if( data[headerEnd] == 0x78 && data[headerEnd + 1] == 0x70 ) { headerEnd += 2; break; } } // start parsing serialization listing int offset = 0; int width = 0, length = 0, height = 0; Position spawn = new Position(); while( pointer < headerEnd ) { switch( (char)data[pointer] ) { case 'Z': offset++; break; case 'F': case 'I': offset += 4; break; case 'J': offset += 8; break; } pointer += 1; Array.Copy( data, pointer, temp, 0, 2 ); short skip = IPAddress.HostToNetworkOrder( BitConverter.ToInt16( temp, 0 ) ); pointer += 2; // look for relevant variables Array.Copy( data, headerEnd + offset - 4, temp, 0, 4 ); if( MemCmp( data, pointer, "width" ) ) { width = (ushort)IPAddress.HostToNetworkOrder( BitConverter.ToInt32( temp, 0 ) ); } else if( MemCmp( data, pointer, "depth" ) ) { height = (ushort)IPAddress.HostToNetworkOrder( BitConverter.ToInt32( temp, 0 ) ); } else if( MemCmp( data, pointer, "height" ) ) { length = (ushort)IPAddress.HostToNetworkOrder( BitConverter.ToInt32( temp, 0 ) ); } else if( MemCmp( data, pointer, "xSpawn" ) ) { spawn.X = (short)(IPAddress.HostToNetworkOrder( BitConverter.ToInt32( temp, 0 ) )*32 + 16); } else if( MemCmp( data, pointer, "ySpawn" ) ) { spawn.Z = (short)(IPAddress.HostToNetworkOrder( BitConverter.ToInt32( temp, 0 ) )*32 + 16); } else if( MemCmp( data, pointer, "zSpawn" ) ) { spawn.Y = (short)(IPAddress.HostToNetworkOrder( BitConverter.ToInt32( temp, 0 ) )*32 + 16); } pointer += skip; } map = new Map( width, length, height ) { Spawn = spawn }; // find the start of the block array bool foundBlockArray = false; offset = Array.IndexOf<byte>( data, 0x00, headerEnd ); while( offset != -1 && offset < data.Length - 2 ) { if( data[offset] == 0x00 && data[offset + 1] == 0x78 && data[offset + 2] == 0x70 ) { foundBlockArray = true; pointer = offset + 7; } offset = Array.IndexOf<byte>( data, 0x00, offset + 1 ); } // copy the block array... or fail if( !foundBlockArray ) { throw new Exception( "DatMapConverter: Could not locate block array." ); } Array.Copy( data, pointer, map.Blocks, 0, map.Blocks.Length ); // Map survivaltest/indev blocktypes to standard/presentation blocktypes map.ConvertBlockTypes( Mapping ); if( Config.Physics ) map.EnablePhysics(); break; } if( map == null ) { throw new Exception( "DatMapConverter: Error loading map." ); } return map; } }
void SendMap() { // write MapBegin //Logger.Log( "Send: MapBegin()" ); writer.Write( OpCode.MapBegin ); // grab a compressed copy of the map byte[] blockData; Map map = Server.Map; using( MemoryStream mapStream = new MemoryStream() ) { using( GZipStream compressor = new GZipStream( mapStream, CompressionMode.Compress ) ) { int convertedBlockCount = IPAddress.HostToNetworkOrder( map.Volume ); compressor.Write( BitConverter.GetBytes( convertedBlockCount ), 0, 4 ); byte[] rawData = ( UsesCustomBlocks ? map.Blocks : map.GetFallbackMap() ); compressor.Write( rawData, 0, rawData.Length ); } blockData = mapStream.ToArray(); } // Transfer the map copy byte[] buffer = new byte[1024]; int mapBytesSent = 0; while( mapBytesSent < blockData.Length ) { int chunkSize = blockData.Length - mapBytesSent; if( chunkSize > 1024 ) { chunkSize = 1024; } else { // CRC fix for ManicDigger for( int i = 0; i < buffer.Length; i++ ) { buffer[i] = 0; } } Buffer.BlockCopy( blockData, mapBytesSent, buffer, 0, chunkSize ); byte progress = (byte)( 100 * mapBytesSent / blockData.Length ); // write in chunks of 1024 bytes or less //Logger.Log( "Send: MapChunk({0},{1})", chunkSize, progress ); writer.Write( OpCode.MapChunk ); writer.Write( (short)chunkSize ); writer.Write( buffer, 0, 1024 ); writer.Write( progress ); mapBytesSent += chunkSize; } // write MapEnd writer.Write( OpCode.MapEnd ); writer.Write( (short)map.Width ); writer.Write( (short)map.Height ); writer.Write( (short)map.Length ); // write spawn point writer.Write( Packet.MakeAddEntity( 255, Name, map.Spawn ).Bytes ); writer.Write( Packet.MakeTeleport( 255, map.Spawn ).Bytes ); lastValidPosition = map.Spawn; }
void ProcessMovementPacket() { reader.ReadByte(); Position newPos = new Position { X = reader.ReadInt16(), Z = reader.ReadInt16(), Y = reader.ReadInt16(), R = reader.ReadByte(), L = reader.ReadByte() }; Position oldPos = Position; // calculate difference between old and new positions Position delta = new Position { X = (short)( newPos.X - oldPos.X ), Y = (short)( newPos.Y - oldPos.Y ), Z = (short)( newPos.Z - oldPos.Z ), R = (byte)Math.Abs( newPos.R - oldPos.R ), L = (byte)Math.Abs( newPos.L - oldPos.L ) }; bool posChanged = ( delta.X != 0 ) || ( delta.Y != 0 ) || ( delta.Z != 0 ); bool rotChanged = ( delta.R != 0 ) || ( delta.L != 0 ); // skip everything if player hasn't moved if( !posChanged && !rotChanged ) return; // only reset the timer if player rotated // if player is just pushed around, rotation does not change (and timer should not reset) if( rotChanged ) ResetIdleTimer(); if( !IsOp && !Config.AllowSpeedHack || IsOp && !Config.OpAllowSpeedHack ) { int distSquared = delta.X * delta.X + delta.Y * delta.Y + delta.Z * delta.Z; // speedhack detection if( DetectMovementPacketSpam() ) return; if( ( distSquared - delta.Z * delta.Z > AntiSpeedMaxDistanceSquared || delta.Z > AntiSpeedMaxJumpDelta ) && speedHackDetectionCounter >= 0 ) { if( speedHackDetectionCounter == 0 ) { lastValidPosition = Position; } else if( speedHackDetectionCounter > 1 ) { DenyMovement(); speedHackDetectionCounter = 0; return; } speedHackDetectionCounter++; } else { speedHackDetectionCounter = 0; } } BroadcastMovementChange( newPos, delta ); }
void BroadcastMovementChange( Position newPos, Position delta ) { Position = newPos; bool posChanged = ( delta.X != 0 ) || ( delta.Y != 0 ) || ( delta.Z != 0 ); bool rotChanged = ( delta.R != 0 ) || ( delta.L != 0 ); Packet packet; // create the movement packet if( delta.FitsIntoMoveRotatePacket && positionSyncCounter < PositionSyncInterval ) { if( posChanged && rotChanged ) { // incremental position + rotation update packet = Packet.MakeMoveRotate( Id, new Position { X = delta.X, Y = delta.Y, Z = delta.Z, R = newPos.R, L = newPos.L } ); } else if( posChanged ) { // incremental position update packet = Packet.MakeMove( Id, delta ); } else if( rotChanged ) { // absolute rotation update packet = Packet.MakeRotate( Id, newPos ); } else { return; } } else { // full (absolute position + rotation) update packet = Packet.MakeTeleport( Id, newPos ); } positionSyncCounter++; if( positionSyncCounter >= PositionSyncInterval ) { positionSyncCounter = 0; } Server.Players.Send( this, packet ); }
public static Packet MakeTeleport( byte id, Position pos ) { Packet packet = new Packet( OpCode.Teleport ); packet.Bytes[1] = id; ToNetOrder( pos.X, packet.Bytes, 2 ); ToNetOrder( pos.Z, packet.Bytes, 4 ); ToNetOrder( pos.Y, packet.Bytes, 6 ); packet.Bytes[8] = pos.R; packet.Bytes[9] = pos.L; return packet; }
public static Packet MakeSelfTeleport( Position pos ) { return MakeTeleport( 255, pos.GetFixed() ); }
public static Packet MakeRotate( int id, Position pos ) { Packet packet = new Packet( OpCode.Rotate ); packet.Bytes[1] = (byte)id; packet.Bytes[2] = pos.R; packet.Bytes[3] = pos.L; return packet; }
public static Packet MakeMoveRotate( int id, Position pos ) { Packet packet = new Packet( OpCode.MoveRotate ); packet.Bytes[1] = (byte)id; packet.Bytes[2] = (byte)( pos.X & 0xFF ); packet.Bytes[3] = (byte)( pos.Z & 0xFF ); packet.Bytes[4] = (byte)( pos.Y & 0xFF ); packet.Bytes[5] = pos.R; packet.Bytes[6] = pos.L; return packet; }
public static Packet MakeMove( int id, Position pos ) { Packet packet = new Packet( OpCode.Move ); packet.Bytes[1] = (byte)id; packet.Bytes[2] = (byte)pos.X; packet.Bytes[3] = (byte)pos.Z; packet.Bytes[4] = (byte)pos.Y; return packet; }