forked from daveyliam/mapwriter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMw.java
671 lines (562 loc) · 21.8 KB
/
Mw.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
package mapwriter;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import mapwriter.forge.MwConfig;
import mapwriter.forge.MwForge;
import mapwriter.forge.MwKeyHandler;
import mapwriter.gui.MwGui;
import mapwriter.gui.MwGuiMarkerDialog;
import mapwriter.map.MapTexture;
import mapwriter.map.MapView;
import mapwriter.map.Marker;
import mapwriter.map.MarkerManager;
import mapwriter.map.OverlayManager;
import mapwriter.map.Trail;
import mapwriter.region.BlockColours;
import mapwriter.region.RegionManager;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGameOver;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.network.packet.Packet1Login;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
/*
data transfers
---------------
chunk image (16x16 int[]) -> texture (512x512 GL texture) | every chunk update
region file png -> texture (512x512 GL texture) | on region load (slow, disk access)
texture (512x512 GL texture) -> region file png | on region unload (slow, disk access)
chunk (Chunk object) -> anvil save file | on chunk unload, separate thread handled by minecraft
background thread
------------------
performs all data transfers except Chunk->Anvil, which is handled by ThreadedFileIOBase in minecraft.
regions created in main thread when necessary, but filled from the background thread.
initialization
--------------
init()
Called once only.
- registers event and key handlers
- loads configuration
- inits marker manager
- inits commands
- inits chunkQueue
onClientLoggedIn()
Called upon entry to each world.
- inits executor
- inits overlay
- inits anvil save handler
- inits regionMap
onConnectionClosed()
Called on every exit from world.
- closes chunkLoader
- closes regionMap
- closes overlay
- saves markermanager
- saves config
- closes executor
- flush chunkQueue
Every hook and event handler should be enclosed in an 'if (this.ready)' statement to ensure that all
components are initialised.
One exception is the fillChunk handler which adds chunks to the chunkQueue so that they can be processed
after initialization. This is so that no chunks are skipped if the chunks are loaded before the player is
logged in.
*/
/* TODO list
*
* - Button to cycle through group selection
* - Save map as 8192x8192 tiles
* - Rei's format marker reading and writing
* - Cave map
*/
public class Mw {
public Minecraft mc = null;
// server information
public String worldName = "default";
private String serverName = "default";
private int serverPort = 0;
// configuration files (global and world specific)
public MwConfig config;
public MwConfig worldConfig = null;
// directories
private final File configDir;
private final File saveDir;
public File worldDir = null;
public File imageDir = null;
// configuration options
public boolean linearTextureScalingEnabled = true;
public boolean coordsEnabled = false;
public boolean teleportEnabled = true;
public String teleportCommand = "tp";
public int defaultTeleportHeight = 80;
public static int maxZoom = 5;
public static int minZoom = -5;
public boolean useSavedBlockColours = false;
public int maxChunkSaveDistSq = 128 * 128;
public boolean mapPixelSnapEnabled = true;
private int textureSize = 2048;
public int configTextureSize = 2048;
public int maxDeathMarkers = 3;
public int chunksPerTick = 5;
// flags and counters
private boolean onPlayerDeathAlreadyFired = false;
public boolean ready = false;
public boolean multiplayer = false;
public int tickCounter = 0;
// list of available dimensions
public List<Integer> dimensionList = new ArrayList<Integer>();
// player position and heading
public double playerX = 0.0;
public double playerZ = 0.0;
public double playerY = 0.0;
public int playerXInt = 0;
public int playerYInt = 0;
public int playerZInt = 0;
public double playerHeading = 0.0;
public int playerDimension = 0;
public double mapRotationDegrees = 0.0;
// constants
public final static String catWorld = "world";
public final static String catMarkers = "markers";
public final static String catOptions = "options";
public final static String worldDirConfigName = "mapwriter.cfg";
public final static String blockColourSaveFileName = "MapWriterBlockColours.txt";
public final static String blockColourOverridesFileName = "MapWriterBlockColourOverrides.txt";
// instances of components
public MapTexture mapTexture = null;
public BackgroundExecutor executor = null;
public OverlayManager overlayManager = null;
public MarkerManager markerManager = null;
public BlockColours blockColours = null;
public RegionManager regionManager = null;
public ChunkManager chunkManager = null;
public Trail playerTrail = null;
public static Mw instance;
public Mw(MwConfig config) {
// client only initialization
// oops, no idea why I was using a ModLoader method to get the Minecraft instance before
this.mc = Minecraft.getMinecraft();
// load config
this.config = config;
// create base save directory
this.saveDir = new File(this.mc.mcDataDir, "saves");
this.configDir = new File(this.mc.mcDataDir, "config");
this.ready = false;
RegionManager.logger = MwForge.logger;
instance = this;
}
public String getWorldName() {
String worldName;
if (!this.multiplayer) {
// cannot use this.mc.theWorld.getWorldInfo().getWorldName() as it
// is set statically to "MpServer".
IntegratedServer server = this.mc.getIntegratedServer();
worldName = (server != null) ? server.getFolderName() : "sp_world";
} else {
worldName = String.format("%s_%d", this.serverName, this.serverPort);
}
// strip invalid characters from the server name so that it
// can't be something malicious like '..\..\..\windows\'
worldName = MwUtil.mungeString(worldName);
// if something went wrong make sure the name is not blank
// (causes crash on start up due to empty configuration section)
if (worldName == "") {
worldName = "default";
}
return worldName;
}
public void loadConfig() {
this.config.load();
this.linearTextureScalingEnabled = this.config.getOrSetBoolean(catOptions, "linearTextureScaling", true);
this.useSavedBlockColours = this.config.getOrSetBoolean(catOptions, "useSavedBlockColours", false);
this.teleportEnabled = this.config.getOrSetBoolean(catOptions, "teleportEnabled", this.teleportEnabled);
this.teleportCommand = this.config.get(catOptions, "teleportCommand", this.teleportCommand).getString();
this.coordsEnabled = this.config.getOrSetBoolean(catOptions, "coordsEnabled", this.coordsEnabled);
this.maxChunkSaveDistSq = this.config.getOrSetInt(catOptions, "maxChunkSaveDistSq", this.maxChunkSaveDistSq, 1, 256 * 256);
this.mapPixelSnapEnabled = this.config.getOrSetBoolean(catOptions, "mapPixelSnapEnabled", this.mapPixelSnapEnabled);
this.maxDeathMarkers = this.config.getOrSetInt(catOptions, "maxDeathMarkers", this.maxDeathMarkers, 0, 1000);
this.chunksPerTick = this.config.getOrSetInt(catOptions, "chunksPerTick", this.chunksPerTick, 1, 500);
maxZoom = this.config.getOrSetInt(catOptions, "zoomOutLevels", maxZoom, 1, 256);
minZoom = -this.config.getOrSetInt(catOptions, "zoomInLevels", -minZoom, 1, 256);
this.configTextureSize = this.config.getOrSetInt(catOptions, "textureSize", this.configTextureSize, 1024, 8192);
this.setTextureSize();
// load markers from config
File worldConfigFile = new File(this.worldDir, worldDirConfigName);
this.worldConfig = new MwConfig(worldConfigFile);
this.worldConfig.load();
this.dimensionList.clear();
this.worldConfig.getIntList(catWorld, "dimensionList", this.dimensionList);
this.addDimension(0);
this.cleanDimensionList();
}
public void saveConfig() {
this.worldConfig.setIntList(catWorld, "dimensionList", this.dimensionList);
this.config.setBoolean(catOptions, "linearTextureScaling", this.linearTextureScalingEnabled);
this.config.setBoolean(catOptions, "useSavedBlockColours", this.useSavedBlockColours);
this.config.setInt(catOptions, "textureSize", this.configTextureSize);
this.config.setBoolean(catOptions, "coordsEnabled", this.coordsEnabled);
this.config.setInt(catOptions, "maxChunkSaveDistSq", this.maxChunkSaveDistSq);
this.config.setBoolean(catOptions, "mapPixelSnapEnabled", this.mapPixelSnapEnabled);
this.config.setInt(catOptions, "maxDeathMarkers", this.maxDeathMarkers);
this.config.setInt(catOptions, "chunksPerTick", this.chunksPerTick);
// save config
this.config.save();
this.worldConfig.save();
}
public void setTextureSize() {
if (this.configTextureSize != this.textureSize) {
int maxTextureSize = Render.getMaxTextureSize();
int textureSize = 1024;
while ((textureSize <= maxTextureSize) && (textureSize <= this.configTextureSize)) {
textureSize *= 2;
}
textureSize /= 2;
MwUtil.log("GL reported max texture size = %d", maxTextureSize);
MwUtil.log("texture size from config = %d", this.configTextureSize);
MwUtil.log("setting map texture size to = %d", textureSize);
this.textureSize = textureSize;
if (this.ready) {
// if we are already up and running need to close and reinitialize the map texture and
// region manager.
this.reloadMapTexture();
}
}
}
// update the saved player position and orientation
// called every tick
public void updatePlayer() {
// get player pos
this.playerX = (double) this.mc.thePlayer.posX;
this.playerY = (double) this.mc.thePlayer.posY;
this.playerZ = (double) this.mc.thePlayer.posZ;
this.playerXInt = (int) Math.floor(this.playerX);
this.playerYInt = (int) Math.floor(this.playerY);
this.playerZInt = (int) Math.floor(this.playerZ);
// rotationYaw of 0 points due north, we want it to point due east instead
// so add pi/2 radians (90 degrees)
this.playerHeading = Math.toRadians(this.mc.thePlayer.rotationYaw) + (Math.PI / 2.0D);
this.mapRotationDegrees = -this.mc.thePlayer.rotationYaw + 180;
// set by onWorldLoad
//this.playerDimension = this.mc.theWorld.provider.dimensionId;
}
public void addDimension(int dimension) {
int i = this.dimensionList.indexOf(dimension);
if (i < 0) {
this.dimensionList.add(dimension);
}
}
public void cleanDimensionList() {
List<Integer> dimensionListCopy = new ArrayList<Integer>(this.dimensionList);
this.dimensionList.clear();
for (int dimension : dimensionListCopy) {
this.addDimension(dimension);
}
}
public void toggleMarkerMode() {
this.markerManager.nextGroup();
this.markerManager.update();
this.mc.thePlayer.addChatMessage("group " + this.markerManager.getVisibleGroupName() + " selected");
}
// cheap and lazy way to teleport...
public void teleportTo(int x, int y, int z) {
if (this.teleportEnabled) {
this.mc.thePlayer.sendChatMessage(String.format("/%s %d %d %d", this.teleportCommand, x, y, z));
} else {
MwUtil.printBoth("teleportation is disabled in mapwriter.cfg");
}
}
public void teleportToMapPos(MapView mapView, int x, int y, int z) {
double scale = mapView.getDimensionScaling(this.playerDimension);
this.teleportTo((int) (x / scale), y, (int) (z / scale));
}
public void teleportToMarker(Marker marker) {
if (marker.dimension == this.playerDimension) {
this.teleportTo(marker.x, marker.y, marker.z);
} else {
MwUtil.printBoth("cannot teleport to marker in different dimension");
}
}
public void loadBlockColourOverrides(BlockColours bc) {
File f = new File(this.configDir, blockColourOverridesFileName);
if (f.isFile()) {
MwUtil.logError("loading block colour overrides file %s", f);
bc.loadFromFile(f);
} else {
MwUtil.logError("recreating block colour overrides file %s", f);
BlockColours.writeOverridesFile(f);
if (f.isFile()) {
bc.loadFromFile(f);
} else {
MwUtil.logError("could not load block colour overrides from file %s", f);
}
}
}
public void saveBlockColours(BlockColours bc) {
File f = new File(this.configDir, blockColourSaveFileName);
MwUtil.logInfo("saving block colours to '%s'", f);
bc.saveToFile(f);
}
public void reloadBlockColours() {
BlockColours bc = new BlockColours();
File f = new File(this.configDir, blockColourSaveFileName);
if (this.useSavedBlockColours && f.isFile()) {
// load block colours from file
MwUtil.logInfo("loading block colours from %s", f);
bc.loadFromFile(f);
this.loadBlockColourOverrides(bc);
} else {
// generate block colours from current texture pack
MwUtil.logInfo("generating block colours");
// block type overrides need to be loaded before the block colours are generated
this.loadBlockColourOverrides(bc);
BlockColourGen.genBlockColours(bc);
// load overrides again to override block and biome colours
this.loadBlockColourOverrides(bc);
this.saveBlockColours(bc);
}
this.blockColours = bc;
}
public void reloadMapTexture() {
this.executor.addTask(new CloseRegionManagerTask(this.regionManager));
this.executor.close();
MapTexture oldMapTexture = this.mapTexture;
this.mapTexture = new MapTexture(this.textureSize, this.linearTextureScalingEnabled);
if (oldMapTexture != null) {
oldMapTexture.close();
}
this.executor = new BackgroundExecutor();
this.regionManager = new RegionManager(this.worldDir, this.imageDir, this.blockColours);
}
public void setCoords(boolean enabled) {
this.coordsEnabled = enabled;
}
public boolean toggleCoords() {
this.setCoords(!this.coordsEnabled);
return this.coordsEnabled;
}
////////////////////////////////
// Event handling methods
////////////////////////////////
// single player connection opened event
public void onConnectionOpened() {
MwUtil.log("connection opened to integrated server");
this.multiplayer = false;
}
// multi player connection opened event
public void onConnectionOpened(String server, int port) {
MwUtil.log("connection opened to remote server: %s %d", server, port);
// set worldname to server_hostname.server_port
this.serverName = server;
this.serverPort = port;
this.multiplayer = true;
}
public void onClientLoggedIn(Packet1Login login) {
MwUtil.log("onClientLoggedIn: dimension = %d", login.dimension);
this.worldName = this.getWorldName();
// create directories
if (this.multiplayer) {
this.worldDir = new File(new File(this.saveDir, "mapwriter_mp_worlds"), this.worldName);
} else {
this.worldDir = new File(new File(this.saveDir, "mapwriter_sp_worlds"), this.worldName);
}
this.imageDir = new File(this.worldDir, "images");
if (!this.imageDir.exists()) {
this.imageDir.mkdirs();
}
if (!this.imageDir.isDirectory()) {
MwUtil.log("Mapwriter: ERROR: could not create images directory '%s'", this.imageDir.getPath());
}
// create directories for zoom levels 1..n
//boolean zoomLevelsExist = true;
for (int i = 1; i <= maxZoom; i++) {
File zDir = new File(imageDir, "z" + i);
//zoomLevelsExist &= zDir.exists();
zDir.mkdirs();
}
this.tickCounter = 0;
this.onPlayerDeathAlreadyFired = false;
this.loadConfig();
//this.multiplayer = !this.mc.isIntegratedServerRunning();
// marker manager only depends on the config being loaded
this.markerManager = new MarkerManager();
this.markerManager.load(this.worldConfig, catMarkers);
this.playerTrail = new Trail(this, "player");
// executor does not depend on anything
this.executor = new BackgroundExecutor();
// mapTexture depends on config being loaded
this.mapTexture = new MapTexture(this.textureSize, this.linearTextureScalingEnabled);
this.reloadBlockColours();
// region manager depends on config, mapTexture, and block colours
this.regionManager = new RegionManager(this.worldDir, this.imageDir, this.blockColours);
// overlay manager depends on mapTexture
this.overlayManager = new OverlayManager(this);
this.overlayManager.overlayView.setDimension(login.dimension);
this.chunkManager = new ChunkManager(this);
this.ready = true;
//if (!zoomLevelsExist) {
//printBoth("recreating zoom levels");
//this.regionManager.recreateAllZoomLevels();
//}
}
public void onWorldLoad(World world) {
//MwUtil.log("onWorldLoad: %s, name %s, dimension %d",
// world,
// world.getWorldInfo().getWorldName(),
// world.provider.dimensionId);
this.playerDimension = world.provider.dimensionId;
if (this.ready) {
this.addDimension(this.playerDimension);
this.overlayManager.overlayView.setDimension(this.playerDimension);
}
}
public void onWorldUnload(World world) {
//MwUtil.log("onWorldUnload: %s, name %s, dimension %d",
// world,
// world.getWorldInfo().getWorldName(),
// world.provider.dimensionId);
}
public void onConnectionClosed() {
MwUtil.log("connection closed");
if (this.ready) {
this.ready = false;
this.chunkManager.close();
this.chunkManager = null;
// close all loaded regions, saving modified images.
// this will create extra tasks that need to be completed.
this.executor.addTask(new CloseRegionManagerTask(this.regionManager));
this.regionManager = null;
MwUtil.log("waiting for %d tasks to finish...", this.executor.tasksRemaining());
if (this.executor.close()) {
MwUtil.log("error: timeout waiting for tasks to finish");
}
MwUtil.log("done");
this.playerTrail.close();
this.markerManager.save(this.worldConfig, catMarkers);
this.markerManager.clear();
// close overlay
this.overlayManager.close();
this.overlayManager = null;
this.mapTexture.close();
this.saveConfig();
this.tickCounter = 0;
}
}
public void onTick() {
if (this.ready && (this.mc.thePlayer != null)) {
this.updatePlayer();
// check if the game over screen is being displayed and if so
// (thanks to Christian Ehrhardt for this method of checking when the player is dead)
if (this.mc.currentScreen instanceof GuiGameOver) {
if (!this.onPlayerDeathAlreadyFired) {
this.onPlayerDeath();
this.onPlayerDeathAlreadyFired = true;
}
} else {
// if the player is not dead
this.onPlayerDeathAlreadyFired = false;
// if in game (no gui screen) center the minimap on the player and render it.
if (this.mc.currentScreen == null) {
this.overlayManager.overlayView.setViewCentreScaled(this.playerX, this.playerZ, this.playerDimension);
this.overlayManager.drawCurrentMap();
}
}
// process background tasks
int maxTasks = 50;
while (!this.executor.processTaskQueue() && (maxTasks > 0)) {
maxTasks--;
}
this.chunkManager.onTick();
// update GL texture of mapTexture if updated
this.mapTexture.processTextureUpdates();
// let the renderEngine know we have changed the bound texture.
//this.mc.renderEngine.resetBoundTexture();
//if (this.tickCounter % 100 == 0) {
// MwUtil.log("tick %d", this.tickCounter);
//}
this.playerTrail.onTick();
this.tickCounter++;
}
}
// add chunk to the set of loaded chunks
public void onChunkLoad(Chunk chunk) {
if (this.ready && (chunk != null) && (chunk.worldObj instanceof net.minecraft.client.multiplayer.WorldClient)) {
this.chunkManager.addChunk(chunk);
}
}
// remove chunk from the set of loaded chunks.
// convert to mwchunk and write chunk to region file if in multiplayer.
public void onChunkUnload(Chunk chunk) {
if (this.ready && (chunk != null) && (chunk.worldObj instanceof net.minecraft.client.multiplayer.WorldClient)) {
this.chunkManager.removeChunk(chunk);
}
}
// from onTick when mc.currentScreen is an instance of GuiGameOver
// it's the only option to detect death client side
public void onPlayerDeath() {
if (this.ready && (this.maxDeathMarkers > 0)) {
this.updatePlayer();
int deleteCount = this.markerManager.countMarkersInGroup("playerDeaths") - this.maxDeathMarkers + 1;
for (int i = 0; i < deleteCount; i++) {
// delete the first marker found in the group "playerDeaths".
// as new markers are only ever appended to the marker list this will delete the
// earliest death marker added.
this.markerManager.delMarker(null, "playerDeaths");
}
this.markerManager.addMarker(MwUtil.getCurrentDateString(), "playerDeaths", this.playerXInt, this.playerYInt, this.playerZInt, this.playerDimension, 0xffff0000);
this.markerManager.setVisibleGroupName("playerDeaths");
this.markerManager.update();
}
}
public void onKeyDown(KeyBinding kb) {
// make sure not in GUI element (e.g. chat box)
if ((this.mc.currentScreen == null) && (this.ready)) {
//Mw.log("client tick: %s key pressed", kb.keyDescription);
if (kb == MwKeyHandler.keyMapMode) {
// map mode toggle
this.overlayManager.nextOverlayMode(1);
} else if (kb == MwKeyHandler.keyMapGui) {
// open map gui
this.mc.displayGuiScreen(new MwGui(this));
} else if (kb == MwKeyHandler.keyNewMarker) {
// open new marker dialog
String group = this.markerManager.getVisibleGroupName();
if (group.equals("none")) {
group = "group";
}
this.mc.displayGuiScreen(
new MwGuiMarkerDialog(
null,
this.markerManager,
"",
group,
this.playerXInt,
this.playerYInt,
this.playerZInt,
this.playerDimension
)
);
} else if (kb == MwKeyHandler.keyNextGroup) {
// toggle marker mode
this.markerManager.nextGroup();
this.markerManager.update();
this.mc.thePlayer.addChatMessage("group " + this.markerManager.getVisibleGroupName() + " selected");
} else if (kb == MwKeyHandler.keyTeleport) {
// set or remove marker
Marker marker = this.markerManager.getNearestMarkerInDirection(
this.playerXInt,
this.playerZInt,
this.playerHeading);
if (marker != null) {
this.teleportToMarker(marker);
}
} else if (kb == MwKeyHandler.keyZoomIn) {
// zoom in
this.overlayManager.overlayView.adjustZoomLevel(-1);
} else if (kb == MwKeyHandler.keyZoomOut) {
// zoom out
this.overlayManager.overlayView.adjustZoomLevel(1);
}
}
}
}