Add proper singleplayer support. Can generate new flatgrass worlds with /client gen, also the client starts singleplayer when no arguments are provided.

This commit is contained in:
UnknownShadow200 2015-09-01 17:24:01 +10:00
parent db800f3b32
commit 7baf64051f
12 changed files with 167 additions and 64 deletions

View File

@ -1,6 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# SharpDevelop 4.4
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassicalSharp", "ClassicalSharp\ClassicalSharp.csproj", "{BEB1C785-5CAD-48FF-A886-876BF0A318D4}"
EndProject

View File

@ -33,8 +33,8 @@
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<StartAction>Project</StartAction>
<StartArguments>wwwf null 127.0.0.1 25566</StartArguments>
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
<StartArguments>wwwf null 127.0.0.1 25566</StartArguments>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>..\output\release\</OutputPath>
@ -129,7 +129,6 @@
<Compile Include="Model\ZombieModel.cs" />
<Compile Include="Network\Enums.cs" />
<Compile Include="Network\INetworkProcessor.cs" />
<Compile Include="Network\SinglePlayerServer.cs" />
<Compile Include="Network\NetworkProcessor.cs" />
<Compile Include="Network\Utils\AsyncDownloader.cs" />
<Compile Include="Network\Utils\FastNetReader.cs" />
@ -156,6 +155,8 @@
<Compile Include="Selections\SelectionBox.cs" />
<Compile Include="Selections\SelectionBoxComparer.cs" />
<Compile Include="Selections\SelectionManager.cs" />
<Compile Include="Singleplayer\Commands.cs" />
<Compile Include="Singleplayer\Server.cs" />
<Compile Include="Utils\Camera.cs" />
<Compile Include="Utils\FastBitmap.cs" />
<Compile Include="Utils\FastColour.cs" />
@ -187,6 +188,7 @@
<Folder Include="Game" />
<Folder Include="Model" />
<Folder Include="Network\Utils" />
<Folder Include="Singleplayer" />
<Folder Include="Utils" />
<Folder Include="Physics" />
</ItemGroup>

View File

@ -23,7 +23,7 @@ namespace ClassicalSharp.Commands {
RegisterCommand( new ViewDistanceCommand() );
}
void RegisterCommand( Command command ) {
public void RegisterCommand( Command command ) {
command.Window = Window;
foreach( Command cmd in RegisteredCommands ) {
if( Utils.CaselessEquals( cmd.Name, command.Name ) ) {

View File

@ -139,7 +139,11 @@ namespace ClassicalSharp {
MapRenderer = new MapRenderer( this );
MapEnvRenderer = new MapEnvRenderer( this );
EnvRenderer = new StandardEnvRenderer( this );
if( IPAddress == null ) {
Network = new Singleplayer.SinglePlayerServer( this );
} else {
Network = new NetworkProcessor( this );
}
firstPersonCam = new FirstPersonCamera( this );
thirdPersonCam = new ThirdPersonCamera( this );
Camera = firstPersonCam;

View File

@ -18,12 +18,22 @@ namespace ClassicalSharp {
if( !AllResourcesExist( "terrain.png", "char.png", "clouds.png" ) ) {
return;
}
if( args.Length < 4 ) {
if( args.Length == 0 ) {
Utils.Log( "Starting singleplayer mode." );
using( Game game = new Game() ) {
game.Username = "LocalPlayer";
game.skinServer = "http://s3.amazonaws.com/MinecraftSkins/";
game.Run();
}
} else if( args.Length < 4 ) {
Fail( "ClassicalSharp.exe is only the raw client. You must either use the launcher or"
+ " provide command line arguments to start the client." );
return;
} else {
RunMultiplayer( args );
}
}
static void RunMultiplayer( string[] args ) {
IPAddress ip = null;
if( !IPAddress.TryParse( args[2], out ip ) ) {
Fail( "Invalid IP \"" + args[2] + '"' );

View File

@ -0,0 +1,43 @@
using System;
using ClassicalSharp.Commands;
namespace ClassicalSharp.Singleplayer {
/// <summary> Command that modifies the font size of chat in the normal gui screen. </summary>
public sealed class GenerateCommand : Command {
public GenerateCommand() {
Name = "Generate";
Help = new [] {
"&a/client generate [width height length]",
"&bwidth: &eSpecifies X-axis/width of the new map.",
"&bheight: &eSpecifies Y-axis/height of the new map.",
"&blength: &eSpecifies Z-axis/length of the new map.",
};
}
public override void Execute( CommandReader reader ) {
int width, height, length;
if( !reader.NextInt( out width ) || !reader.NextInt( out height ) || !reader.NextInt( out length ) ) {
Window.AddChat( "&e/client generate: &cInvalid dimensions." );
} else {
if( width < 16 || height < 16 || length < 16 ) {
Window.AddChat( "&e/client generate: &cDimensions too small." );
return;
}
if( width > 1024 || height > 1024 || length > 1024 ) {
Window.AddChat( "&e/client generate: &cDimensions too large." );
return;
}
if( !( Window.Network is SinglePlayerServer ) ) {
Window.AddChat( "&e/client generate: &cThis command only works in singleplayer mode." );
return;
}
SinglePlayerServer server = (SinglePlayerServer)Window.Network;
server.NewMap();
Window.chatInInputBuffer = "";
server.MakeMap( width, height, length );
}
}
}
}

View File

@ -3,7 +3,7 @@ using System.Net;
using OpenTK;
using OpenTK.Input;
namespace ClassicalSharp {
namespace ClassicalSharp.Singleplayer {
public sealed class SinglePlayerServer : INetworkProcessor {
@ -23,7 +23,8 @@ namespace ClassicalSharp {
}
game.RaiseBlockPermissionsChanged();
NewMap();
MapLoaded();
MakeMap( 128, 128, 128 );
game.CommandManager.RegisterCommand( new GenerateCommand() );
}
public override void SendChat( string text ) {
@ -48,7 +49,7 @@ namespace ClassicalSharp {
if( Disconnected ) return;
}
void NewMap() {
internal void NewMap() {
ServerName = "Single player";
ServerMotd = "Generating a map..";
game.LocalPlayer.UserType = 0x64;
@ -58,25 +59,25 @@ namespace ClassicalSharp {
game.SetNewScreen( new LoadingMapScreen( game, ServerName, ServerMotd ) );
}
void MapLoaded() {
game.SetNewScreen( new NormalScreen( game ) );
int width = 16, height = 16, length = 16;
internal unsafe void MakeMap( int width, int height, int length ) {
byte[] map = new byte[width * height * length];
MapSet( width, length, map, 0, height / 2 - 2, (byte)Block.Dirt );
MapSet( width, length, map, height / 2 - 1, height / 2 - 1, (byte)Block.Grass );
var sw = System.Diagnostics.Stopwatch.StartNew();
fixed( byte* ptr = map ) {
MapSet( width, length, ptr, 0, height / 2 - 2, (byte)Block.Dirt );
MapSet( width, length, ptr, height / 2 - 1, height / 2 - 1, (byte)Block.Grass );
}
game.Map.UseRawMap( map, width, height, length );
game.RaiseOnNewMapLoaded();
game.SetNewScreen( new NormalScreen( game ) );
ResetPlayerPosition();
game.AddChat( "&ePlaying single player", CpeMessage.Status1 );
GC.Collect();
}
void MapSet( int width, int length, byte[] map, int yStart, int yEnd, byte block ) {
unsafe void MapSet( int width, int length, byte* ptr, int yStart, int yEnd, byte block ) {
int startIndex = yStart * length * width;
int endIndex = ( yEnd * length + (length - 1) ) * width + (width - 1);
for( int i = startIndex; i <= endIndex; i++ ) {
map[i] = block;
}
MemUtils.memset( (IntPtr)ptr, block, startIndex, endIndex - startIndex + 1 );
}
void ResetPlayerPosition() {

67
OpenTK/MemUtils.cs Normal file
View File

@ -0,0 +1,67 @@
using System;
namespace OpenTK {
public static class MemUtils {
static MemUtils() {
use64Bit = IntPtr.Size == 8;
}
static bool use64Bit;
public static unsafe void memcpy( IntPtr srcPtr, IntPtr dstPtr, int bytes ) {
byte* srcByte, dstByte;
if( use64Bit ) {
ulong* srcLong = (ulong*)srcPtr, dstLong = (ulong*)dstPtr;
while( bytes >= 8 ) {
*dstLong++ = *srcLong++;
bytes -= 8;
}
srcByte = (byte*)srcLong; dstByte = (byte*)dstLong;
} else {
uint* srcInt = (uint*)srcPtr, dstInt = (uint*)dstPtr;
while( bytes >= 4 ) {
*dstInt++ = *srcInt++;
bytes -= 4;
}
srcByte = (byte*)srcInt; dstByte = (byte*)dstInt;
}
for( int i = 0; i < bytes; i++ ) {
*dstByte++ = *srcByte++;
}
}
public static unsafe void memset( IntPtr srcPtr, byte value, int startIndex, int bytes ) {
byte* srcByte = (byte*)srcPtr + startIndex;
// Make sure we do an aligned write/read for the bulk copy
while( bytes > 0 && ( startIndex & 0x7 ) != 0 ) {
*srcByte++ = value;
startIndex++;
bytes--;
}
uint valueInt = (uint)( ( value << 24 ) | ( value << 16 ) | ( value << 8 ) | value );
if( use64Bit ) {
ulong valueLong = ( (ulong)valueInt << 32 ) | valueInt;
ulong* srcLong = (ulong*)srcByte;
while( bytes >= 8 ) {
*srcLong++ = valueLong;
bytes -= 8;
}
srcByte = (byte*)srcLong;
} else {
uint* srcInt = (uint*)srcByte;
while( bytes >= 4 ) {
*srcInt++ = valueInt;
bytes -= 4;
}
srcByte = (byte*)srcInt;
}
for( int i = 0; i < bytes; i++ ) {
*srcByte++ = value;
}
}
}
}

View File

@ -51,7 +51,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="BindingsBase.cs" />
<Compile Include="Configuration.cs" />
<Compile Include="DisplayDevice.cs" />
<Compile Include="DisplayResolution.cs" />
<Compile Include="FrameEventArgs.cs" />
@ -62,6 +61,7 @@
<Compile Include="INativeWindow.cs" />
<Compile Include="Interop.cs" />
<Compile Include="KeyPressEventArgs.cs" />
<Compile Include="MemUtils.cs" />
<Compile Include="NativeWindow.cs" />
<Compile Include="Graphics\ColorFormat.cs" />
<Compile Include="Graphics\GraphicsContextBase.cs" />
@ -80,6 +80,7 @@
<Compile Include="Math\Vector2.cs" />
<Compile Include="Math\Vector3.cs" />
<Compile Include="Math\Vector4.cs" />
<Compile Include="Platform\Configuration.cs" />
<Compile Include="Platform\IDisplayDeviceDriver.cs" />
<Compile Include="Platform\IPlatformFactory.cs" />
<Compile Include="Platform\IWindowInfo.cs" />

View File

@ -34,7 +34,6 @@ namespace SharpDX.Direct3D9 {
Adapters = new List<AdapterInformation>( count );
for( int i = 0; i < count; i++ )
Adapters.Add( new AdapterInformation( this, i ) );
memcpy64Bit = IntPtr.Size == 8;
}
public List<AdapterInformation> Adapters;
@ -104,29 +103,5 @@ namespace SharpDX.Direct3D9 {
if( res < 0 ) { throw new SharpDXException( res ); }
return new Device( devicePtr );
}
// TODO: Place this in a utilities class.
static bool memcpy64Bit;
internal static unsafe void memcpy( IntPtr srcPtr, IntPtr dstPtr, int bytes ) {
byte* srcByte, dstByte;
if( memcpy64Bit ) {
long* srcLong = (long*)srcPtr, dstLong = (long*)dstPtr;
while( bytes >= 8 ) {
*dstLong++ = *srcLong++;
bytes -= 8;
}
srcByte = (byte*)srcLong; dstByte = (byte*)dstLong;
} else {
int* srcInt = (int*)srcPtr, dstInt = (int*)dstPtr;
while( bytes >= 4 ) {
*dstInt++ = *srcInt++;
bytes -= 4;
}
srcByte = (byte*)srcInt; dstByte = (byte*)dstInt;
}
for( int i = 0; i < bytes; i++ ) {
*dstByte++ = *srcByte++;
}
}
}
}

View File

@ -57,14 +57,14 @@ namespace SharpDX.Direct3D9 {
public void SetData( IntPtr data, int bytes, LockFlags flags ) {
IntPtr dst = Lock( 0, bytes, flags );
Direct3D.memcpy( data, dst, bytes );
MemUtils.memcpy( data, dst, bytes );
Unlock();
}
public void SetData<T>( T[] data, int bytes, LockFlags flags ) where T : struct {
IntPtr src = Interop.Fixed( ref data[0] );
IntPtr dst = Lock( 0, bytes, flags );
Direct3D.memcpy( src, dst, bytes );
MemUtils.memcpy( src, dst, bytes );
Unlock();
}
@ -108,7 +108,7 @@ namespace SharpDX.Direct3D9 {
public void SetData( IntPtr data, int bytes, int level, LockFlags flags ) {
LockedRectangle rect = LockRectangle( level, flags );
Direct3D.memcpy( data, rect.DataPointer, bytes );
MemUtils.memcpy( data, rect.DataPointer, bytes );
UnlockRectangle( level );
}