Add a generation gui.

This commit is contained in:
UnknownShadow200 2015-12-10 21:36:55 +11:00
parent ffafd8023b
commit f652953582
12 changed files with 202 additions and 96 deletions

View File

@ -13,7 +13,7 @@ namespace ClassicalSharp {
hotkeys = game.InputHandler.Hotkeys; hotkeys = game.InputHandler.Hotkeys;
} }
Font hintFont, arrowFont, textFont; Font arrowFont, textFont;
public override void Render( double delta ) { public override void Render( double delta ) {
RenderMenuBounds(); RenderMenuBounds();
graphicsApi.Texturing = true; graphicsApi.Texturing = true;
@ -75,7 +75,6 @@ namespace ClassicalSharp {
game.Keyboard.KeyRepeat = true; game.Keyboard.KeyRepeat = true;
base.Init(); base.Init();
regularFont = new Font( "Arial", 16, FontStyle.Regular ); regularFont = new Font( "Arial", 16, FontStyle.Regular );
hintFont = new Font( "Arial", 14, FontStyle.Italic );
arrowFont = new Font( "Arial", 18, FontStyle.Bold ); arrowFont = new Font( "Arial", 18, FontStyle.Bold );
textFont = new Font( "Arial", 14, FontStyle.Bold ); textFont = new Font( "Arial", 14, FontStyle.Bold );
@ -111,7 +110,6 @@ namespace ClassicalSharp {
game.Keyboard.KeyRepeat = false; game.Keyboard.KeyRepeat = false;
DisposeEditingWidgets(); DisposeEditingWidgets();
hintFont.Dispose();
arrowFont.Dispose(); arrowFont.Dispose();
textFont.Dispose(); textFont.Dispose();
base.Dispose(); base.Dispose();
@ -202,7 +200,7 @@ namespace ClassicalSharp {
currentAction = MenuInputWidget.Create( currentAction = MenuInputWidget.Create(
game, 0, 90, 600, 25, "", Anchor.Centre, Anchor.Centre, game, 0, 90, 600, 25, "", Anchor.Centre, Anchor.Centre,
regularFont, titleFont, hintFont, new StringValidator( 64 ) ); regularFont, titleFont, new StringValidator( 64 ) );
currentMoreInputLabel = TextWidget.Create( currentMoreInputLabel = TextWidget.Create(
game, -170, 120, "Keep input bar open:", game, -170, 120, "Keep input bar open:",
Anchor.Centre, Anchor.Centre, textFont ); Anchor.Centre, Anchor.Centre, textFont );

View File

@ -0,0 +1,165 @@
using System;
using System.Drawing;
using System.IO;
using ClassicalSharp.Generator;
using ClassicalSharp.Singleplayer;
using OpenTK.Input;
namespace ClassicalSharp {
public sealed class GenLevelScreen : MenuScreen {
public GenLevelScreen( Game game ) : base( game ) {
}
TextWidget[] labels;
MenuInputWidget[] inputs;
MenuInputWidget selectedWidget;
public override void Render( double delta ) {
RenderMenuBounds();
graphicsApi.Texturing = true;
RenderMenuButtons( delta );
for( int i = 0; i < inputs.Length; i++ )
inputs[i].Render( delta );
for( int i = 0; i < labels.Length; i++ )
labels[i].Render( delta );
graphicsApi.Texturing = false;
if( textPath != null ) {
SaveMap( textPath );
textPath = null;
}
}
public override bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) {
return HandleMouseClick( buttons, mouseX, mouseY, button ) ||
HandleMouseClick( inputs, mouseX, mouseY, button );
}
public override bool HandlesKeyPress( char key ) {
return selectedWidget == null ? true :
selectedWidget.HandlesKeyPress( key );
}
public override bool HandlesKeyDown( Key key ) {
if( key == Key.Escape ) {
game.SetNewScreen( null );
return true;
}
return selectedWidget == null ? true :
selectedWidget.HandlesKeyDown( key );
}
public override bool HandlesKeyUp( Key key ) {
return selectedWidget == null ? true :
selectedWidget.HandlesKeyUp( key );
}
public override void Init() {
game.Keyboard.KeyRepeat = true;
base.Init();
int size = game.Drawer2D.UseBitmappedChat ? 14 : 18;
titleFont = new Font( "Arial", size, FontStyle.Bold );
regularFont = new Font( "Arial", 16, FontStyle.Regular );
inputs = new [] { MakeInput( -80 ), MakeInput( -40 ),
MakeInput( 0 ), MakeInput( 40 )
};
labels = new [] { MakeLabel( -80, "Width:" ), MakeLabel( -40, "Height:" ),
MakeLabel( 0, "Length:" ), MakeLabel( 40, "Seed:" ),
};
buttons = new [] {
ButtonWidget.Create( game, 0, 90, 250, 30, "Generate flatgrass", Anchor.Centre,
Anchor.Centre, titleFont, GenFlatgrassClick ),
ButtonWidget.Create( game, 0, 140, 250, 30, "Generate notchy", Anchor.Centre,
Anchor.Centre, titleFont, GenNotchyClick ),
MakeBack( false, titleFont,
(g, w) => g.SetNewScreen( new PauseScreen( g ) ) ),
};
}
MenuInputWidget MakeInput( int y ) {
MenuInputWidget widget = MenuInputWidget.Create(
game, 0, y, 200, 25, "", Anchor.Centre, Anchor.Centre,
regularFont, titleFont, new IntegerValidator( 1, 8192 ) );
widget.Active = false;
widget.OnClick = InputClick;
return widget;
}
TextWidget MakeLabel( int y, string text ) {
return TextWidget.Create( game, -140, y, text,
Anchor.Centre, Anchor.Centre, titleFont );
}
public override void OnResize( int oldWidth, int oldHeight, int width, int height ) {
for( int i = 0; i < inputs.Length; i++ )
inputs[i].OnResize( oldWidth, oldHeight, width, height );
for( int i = 0; i < labels.Length; i++ )
labels[i].OnResize( oldWidth, oldHeight, width, height );
base.OnResize( oldWidth, oldHeight, width, height );
}
public override void Dispose() {
game.Keyboard.KeyRepeat = false;
for( int i = 0; i < inputs.Length; i++ )
inputs[i].Dispose();
for( int i = 0; i < labels.Length; i++ )
labels[i].Dispose();
base.Dispose();
}
void InputClick( Game game, Widget widget ) {
if( selectedWidget != null )
selectedWidget.Active = false;
selectedWidget = (MenuInputWidget)widget;
selectedWidget.Active = true;
}
void GenFlatgrassClick( Game game, Widget widget ) {
GenerateMap( new FlatGrassGenerator() );
}
void GenNotchyClick( Game game, Widget widget ) {
GenerateMap( new NotchyGenerator() );
}
void GenerateMap( IMapGenerator gen ) {
SinglePlayerServer server = (SinglePlayerServer)game.Network;
int width = GetInt( 0 ), height = GetInt( 1 );
int length = GetInt( 2 ), seed = GetInt( 3 );
long volume = (long)width * height * length;
if( volume > 800 * 800 * 800 ) {
game.Chat.Add( "&cThe generated map's volume is too big." );
} else if( width == 0 || height == 0 || length == 0 ) {
game.Chat.Add( "&cOne of the map dimensions is invalid.");
} else {
server.GenMap( width, height, length, seed, gen );
}
}
int GetInt( int index ) {
string text = inputs[index].GetText();
if( !inputs[index].Validator.IsValidValue( text ) )
return 0;
return text == "" ? 0 : Int32.Parse( text );
}
string textPath;
void SaveMap( string path ) {
try {
using( FileStream fs = new FileStream( path, FileMode.CreateNew, FileAccess.Write ) ) {
IMapFileFormat map = new MapCw();
map.Save( fs, game );
}
} catch( Exception ex ) {
ErrorHandler.LogError( "saving map", ex );
return;
}
game.SetNewScreen( new PauseScreen( game ) );
}
}
}

View File

@ -12,7 +12,6 @@ namespace ClassicalSharp {
protected MenuInputWidget inputWidget; protected MenuInputWidget inputWidget;
protected MenuInputValidator[] validators; protected MenuInputValidator[] validators;
protected TextWidget descWidget; protected TextWidget descWidget;
protected Font hintFont;
protected int okayIndex; protected int okayIndex;
public override void Render( double delta ) { public override void Render( double delta ) {
@ -29,7 +28,6 @@ namespace ClassicalSharp {
public override void Init() { public override void Init() {
base.Init(); base.Init();
regularFont = new Font( "Arial", 16, FontStyle.Regular ); regularFont = new Font( "Arial", 16, FontStyle.Regular );
hintFont = new Font( "Arial", 14, FontStyle.Italic );
game.Keyboard.KeyRepeat = true; game.Keyboard.KeyRepeat = true;
} }
@ -69,7 +67,6 @@ namespace ClassicalSharp {
descWidget.Dispose(); descWidget.Dispose();
if( inputWidget != null ) if( inputWidget != null )
inputWidget.Dispose(); inputWidget.Dispose();
hintFont.Dispose();
game.Keyboard.KeyRepeat = false; game.Keyboard.KeyRepeat = false;
base.Dispose(); base.Dispose();
} }
@ -126,9 +123,8 @@ namespace ClassicalSharp {
inputWidget.Dispose(); inputWidget.Dispose();
targetWidget = selectedWidget; targetWidget = selectedWidget;
inputWidget = MenuInputWidget.Create( game, 0, 150, 400, 25, button.GetValue( game ), inputWidget = MenuInputWidget.Create( game, 0, 150, 400, 25, button.GetValue( game ), Anchor.Centre,
Anchor.Centre, Anchor.Centre, regularFont, titleFont, Anchor.Centre, regularFont, titleFont, validator );
hintFont, validator );
buttons[okayIndex] = ButtonWidget.Create( game, 240, 150, 30, 30, "OK", buttons[okayIndex] = ButtonWidget.Create( game, 240, 150, 30, 30, "OK",
Anchor.Centre, Anchor.Centre, titleFont, OnWidgetClick ); Anchor.Centre, Anchor.Centre, titleFont, OnWidgetClick );
UpdateDescription( targetWidget ); UpdateDescription( targetWidget );

View File

@ -30,15 +30,19 @@ namespace ClassicalSharp {
(g, w) => g.SetNewScreen( new NormalKeyBindingsScreen( g ) ) ), (g, w) => g.SetNewScreen( new NormalKeyBindingsScreen( g ) ) ),
Make( -140, 50, "Hotkeys", Anchor.Centre, Make( -140, 50, "Hotkeys", Anchor.Centre,
(g, w) => g.SetNewScreen( new HotkeyScreen( g ) ) ), (g, w) => g.SetNewScreen( new HotkeyScreen( g ) ) ),
// Column 2 // Column 2
Make( 140, -150, "Save level", Anchor.Centre, Make( 140, -150, "Save level", Anchor.Centre,
(g, w) => g.SetNewScreen( new SaveLevelScreen( g ) ) ), (g, w) => g.SetNewScreen( new SaveLevelScreen( g ) ) ),
!game.Network.IsSinglePlayer ? null : !game.Network.IsSinglePlayer ? null :
Make( 140, -100, "Load level", Anchor.Centre, Make( 140, -100, "Load level", Anchor.Centre,
(g, w) => g.SetNewScreen( new LoadLevelScreen( g ) ) ), (g, w) => g.SetNewScreen( new LoadLevelScreen( g ) ) ),
// TODO: singleplayer Generate level screen !game.Network.IsSinglePlayer ? null :
Make( 140, -50, "Generate level", Anchor.Centre,
(g, w) => g.SetNewScreen( new GenLevelScreen( g ) ) ),
Make( 140, 50, "Select texture pack", Anchor.Centre, Make( 140, 50, "Select texture pack", Anchor.Centre,
(g, w) => g.SetNewScreen( new TexturePackScreen( g ) ) ), (g, w) => g.SetNewScreen( new TexturePackScreen( g ) ) ),
// Other // Other
MakeOther( 10, 5, 120, "Quit game", Anchor.BottomOrRight, MakeOther( 10, 5, 120, "Quit game", Anchor.BottomOrRight,
(g, w) => g.Exit() ), (g, w) => g.Exit() ),

View File

@ -11,7 +11,6 @@ namespace ClassicalSharp {
} }
MenuInputWidget inputWidget; MenuInputWidget inputWidget;
Font hintFont;
TextWidget descWidget; TextWidget descWidget;
public override void Render( double delta ) { public override void Render( double delta ) {
@ -49,11 +48,10 @@ namespace ClassicalSharp {
game.Keyboard.KeyRepeat = true; game.Keyboard.KeyRepeat = true;
base.Init(); base.Init();
regularFont = new Font( "Arial", 16, FontStyle.Regular ); regularFont = new Font( "Arial", 16, FontStyle.Regular );
hintFont = new Font( "Arial", 14, FontStyle.Italic );
inputWidget = MenuInputWidget.Create( inputWidget = MenuInputWidget.Create(
game, -30, 50, 500, 25, "", Anchor.Centre, Anchor.Centre, game, -30, 50, 500, 25, "", Anchor.Centre, Anchor.Centre,
regularFont, titleFont, hintFont, new PathValidator() ); regularFont, titleFont, new PathValidator() );
buttons = new [] { buttons = new [] {
ButtonWidget.Create( game, 260, 50, 60, 30, "Save", Anchor.Centre, ButtonWidget.Create( game, 260, 50, 60, 30, "Save", Anchor.Centre,
@ -72,7 +70,6 @@ namespace ClassicalSharp {
public override void Dispose() { public override void Dispose() {
game.Keyboard.KeyRepeat = false; game.Keyboard.KeyRepeat = false;
inputWidget.Dispose(); inputWidget.Dispose();
hintFont.Dispose();
DisposeDescWidget(); DisposeDescWidget();
base.Dispose(); base.Dispose();
} }

View File

@ -6,18 +6,17 @@ namespace ClassicalSharp {
public sealed class MenuInputWidget : Widget { public sealed class MenuInputWidget : Widget {
public MenuInputWidget( Game game, Font font, Font boldFont, Font hintFont ) : base( game ) { public MenuInputWidget( Game game, Font font, Font boldFont ) : base( game ) {
HorizontalAnchor = Anchor.LeftOrTop; HorizontalAnchor = Anchor.LeftOrTop;
VerticalAnchor = Anchor.BottomOrRight; VerticalAnchor = Anchor.BottomOrRight;
this.font = font; this.font = font;
this.boldFont = boldFont; this.boldFont = boldFont;
this.hintFont = hintFont;
chatInputText = new StringBuffer( 64 ); chatInputText = new StringBuffer( 64 );
} }
public static MenuInputWidget Create( Game game, int x, int y, int width, int height, string text, Anchor horizontal, public static MenuInputWidget Create( Game game, int x, int y, int width, int height, string text, Anchor horizontal,
Anchor vertical, Font font, Font tildeFont, Font hintFont, MenuInputValidator validator ) { Anchor vertical, Font font, Font tildeFont, MenuInputValidator validator ) {
MenuInputWidget widget = new MenuInputWidget( game, font, tildeFont, hintFont ); MenuInputWidget widget = new MenuInputWidget( game, font, tildeFont );
widget.HorizontalAnchor = horizontal; widget.HorizontalAnchor = horizontal;
widget.VerticalAnchor = vertical; widget.VerticalAnchor = vertical;
@ -33,16 +32,17 @@ namespace ClassicalSharp {
Texture chatInputTexture, chatCaretTexture; Texture chatInputTexture, chatCaretTexture;
Color backColour = Color.FromArgb( 200, 30, 30, 30 ); Color backColour = Color.FromArgb( 200, 30, 30, 30 );
readonly Font font, boldFont, hintFont; readonly Font font, boldFont;
StringBuffer chatInputText; StringBuffer chatInputText;
public int XOffset = 0, YOffset = 0; public int XOffset = 0, YOffset = 0;
public int DesiredMaxWidth, DesiredMaxHeight; public int DesiredMaxWidth, DesiredMaxHeight;
public MenuInputValidator Validator; public MenuInputValidator Validator;
public bool Active = true;
double accumulator; double accumulator;
public override void Render( double delta ) { public override void Render( double delta ) {
chatInputTexture.Render( graphicsApi ); chatInputTexture.Render( graphicsApi );
if( (accumulator % 1) >= 0.5 ) if( (accumulator % 1) >= 0.5 && Active )
chatCaretTexture.Render( graphicsApi ); chatCaretTexture.Render( graphicsApi );
accumulator += delta; accumulator += delta;
} }

View File

@ -98,6 +98,7 @@
<Compile Include="2D\Screens\HotkeyScreen.cs" /> <Compile Include="2D\Screens\HotkeyScreen.cs" />
<Compile Include="2D\Screens\LoadingMapScreen.cs" /> <Compile Include="2D\Screens\LoadingMapScreen.cs" />
<Compile Include="2D\Screens\Menu\EnvSettingsScreen.cs" /> <Compile Include="2D\Screens\Menu\EnvSettingsScreen.cs" />
<Compile Include="2D\Screens\Menu\GenLevelScreen.cs" />
<Compile Include="2D\Screens\Menu\GuiOptionsScreen.cs" /> <Compile Include="2D\Screens\Menu\GuiOptionsScreen.cs" />
<Compile Include="2D\Screens\Menu\LoadLevelScreen.cs" /> <Compile Include="2D\Screens\Menu\LoadLevelScreen.cs" />
<Compile Include="2D\Screens\Menu\MenuInputScreen.cs" /> <Compile Include="2D\Screens\Menu\MenuInputScreen.cs" />
@ -228,7 +229,6 @@
<Compile Include="Selections\SelectionBox.cs" /> <Compile Include="Selections\SelectionBox.cs" />
<Compile Include="Selections\SelectionBoxComparer.cs" /> <Compile Include="Selections\SelectionBoxComparer.cs" />
<Compile Include="Selections\SelectionManager.cs" /> <Compile Include="Selections\SelectionManager.cs" />
<Compile Include="Singleplayer\Commands.cs" />
<Compile Include="Singleplayer\Physics.cs" /> <Compile Include="Singleplayer\Physics.cs" />
<Compile Include="Singleplayer\Server.cs" /> <Compile Include="Singleplayer\Server.cs" />
<Compile Include="TexturePack\AcceptedUrls.cs" /> <Compile Include="TexturePack\AcceptedUrls.cs" />

View File

@ -226,6 +226,7 @@ namespace ClassicalSharp.Generator {
bool sand = n1.Compute( x, z ) > 8; bool sand = n1.Compute( x, z ) > 8;
bool gravel = n2.Compute( x, z ) > 12; bool gravel = n2.Compute( x, z ) > 12;
int y = heightmap[hMapIndex++]; int y = heightmap[hMapIndex++];
if( y >= height ) continue;
int index = (y * length + z) * width + x; int index = (y * length + z) * width + x;
byte blockAbove = y >= (height - 1) ? (byte)0 : blocks[index + oneY]; byte blockAbove = y >= (height - 1) ? (byte)0 : blocks[index + oneY];

View File

@ -145,6 +145,7 @@ namespace ClassicalSharp {
} }
internal void UpdateHeight( int x, int y, int z, byte oldBlock, byte newBlock ) { internal void UpdateHeight( int x, int y, int z, byte oldBlock, byte newBlock ) {
if( game.Map.IsNotLoaded ) return;
bool didBlock = BlocksRain( oldBlock ); bool didBlock = BlocksRain( oldBlock );
bool nowBlocks = BlocksRain( newBlock ); bool nowBlocks = BlocksRain( newBlock );
if( didBlock == nowBlocks ) return; if( didBlock == nowBlocks ) return;

View File

@ -1,44 +0,0 @@
using System;
using System.IO;
using ClassicalSharp.Commands;
namespace ClassicalSharp.Singleplayer {
/// <summary> Command that generates a new flatgrass map in singleplayer mode. </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 ) ) {
game.Chat.Add( "&e/client generate: &cInvalid dimensions." );
} else {
if( width < 16 || height < 16 || length < 16 ) {
game.Chat.Add( "&e/client generate: &cDimensions too small." );
return;
}
if( width > 1024 || height > 1024 || length > 1024 ) {
game.Chat.Add( "&e/client generate: &cDimensions too large." );
return;
}
if( !( game.Network is SinglePlayerServer ) ) {
game.Chat.Add( "&e/client generate: &cThis command only works in singleplayer mode." );
return;
}
SinglePlayerServer server = (SinglePlayerServer)game.Network;
server.NewMap();
game.chatInInputBuffer = null;
server.MakeMap( width, height, length );
}
}
}
}

View File

@ -61,7 +61,7 @@ namespace ClassicalSharp.Singleplayer {
int tickCount = 0; int tickCount = 0;
public void Tick() { public void Tick() {
if( !Enabled ) return; if( !Enabled || game.Map.IsNotLoaded ) return;
//if( (tickCount % 5) == 0 ) { //if( (tickCount % 5) == 0 ) {
TickLava(); TickLava();

View File

@ -11,6 +11,10 @@ namespace ClassicalSharp.Singleplayer {
Game game; Game game;
internal Physics physics; internal Physics physics;
internal byte[] generatedMap;
IMapGenerator generator;
string lastState;
public SinglePlayerServer( Game window ) { public SinglePlayerServer( Game window ) {
game = window; game = window;
physics = new Physics( game ); physics = new Physics( game );
@ -28,13 +32,8 @@ namespace ClassicalSharp.Singleplayer {
} }
game.Events.RaiseBlockPermissionsChanged(); game.Events.RaiseBlockPermissionsChanged();
NewMap(); int seed = new Random().Next();
#if TEST_VANILLA GenMap( 128, 64, 128, seed, new NotchyGenerator() );
MakeMap( 384, 64, 384 );
#else
MakeMap( 128, 128, 128 );
#endif
game.CommandManager.RegisterCommand( new GenerateCommand() );
} }
public override void SendChat( string text, bool partial ) { public override void SendChat( string text, bool partial ) {
@ -59,7 +58,6 @@ namespace ClassicalSharp.Singleplayer {
physics.Dispose(); physics.Dispose();
} }
string lastState;
public override void Tick( double delta ) { public override void Tick( double delta ) {
if( Disconnected ) return; if( Disconnected ) return;
physics.Tick(); physics.Tick();
@ -81,16 +79,6 @@ namespace ClassicalSharp.Singleplayer {
} }
} }
IMapGenerator generator;
internal void NewMap() {
ServerName = "Single player";
ServerMotd = "Generating a map..";
game.LocalPlayer.UserType = 0x64;
game.Map.Reset();
game.SetNewScreen( new LoadingMapScreen( game, ServerName, ServerMotd ) );
}
void EndGeneration() { void EndGeneration() {
game.SetNewScreen( null ); game.SetNewScreen( null );
if( generatedMap == null ) { if( generatedMap == null ) {
@ -110,15 +98,13 @@ namespace ClassicalSharp.Singleplayer {
GC.Collect(); GC.Collect();
} }
public byte[] generatedMap; internal void GenMap( int width, int height, int length, int seed, IMapGenerator generator ) {
internal void MakeMap( int width, int height, int length ) { game.Map.Reset();
#if TEST_VANILLA GC.Collect();
generator = new NotchyGenerator(); this.generator = generator;
generator.GenerateAsync( game, width, height, length, 0x5553200 );
#else game.SetNewScreen( new LoadingMapScreen( game, "Single player", "Generating.." ) );
generator = new FlatGrassGenerator();
generator.GenerateAsync( game, width, height, length, 0 ); generator.GenerateAsync( game, width, height, length, 0 );
#endif
} }
unsafe void MapSet( int width, int length, byte* ptr, int yStart, int yEnd, byte block ) { unsafe void MapSet( int width, int length, byte* ptr, int yStart, int yEnd, byte block ) {
@ -128,7 +114,9 @@ namespace ClassicalSharp.Singleplayer {
} }
void ResetPlayerPosition() { void ResetPlayerPosition() {
float x = game.Map.Width / 2, y = game.Map.Height / 2, z = game.Map.Length / 2; int x = game.Map.Width / 2, z = game.Map.Length / 2;
int y = game.Map.GetLightHeight( x, z ) + 2;
LocationUpdate update = LocationUpdate.MakePosAndOri( x, y, z, 0, 0, false ); LocationUpdate update = LocationUpdate.MakePosAndOri( x, y, z, 0, 0, false );
game.LocalPlayer.SetLocation( update, false ); game.LocalPlayer.SetLocation( update, false );
} }