Gridarta Editor
AbstractMapManager.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2023 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.model.mapmanager;
21 
22 import java.io.File;
23 import java.io.IOException;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.concurrent.CopyOnWriteArrayList;
41 import org.jetbrains.annotations.NotNull;
42 import org.jetbrains.annotations.Nullable;
43 
48 public abstract class AbstractMapManager<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> implements MapManager<G, A, R> {
49 
53  private static final int DELETED_OBJECTS_TO_REPORT = 10;
54 
58  @NotNull
60 
64  @NotNull
66 
70  @NotNull
72 
76  @NotNull
77  private final PathManager pathManager;
78 
82  private final List<MapControl<G, A, R>> mapControls = new CopyOnWriteArrayList<>();
83 
87  private final Collection<MapManagerListener<G, A, R>> listenerList = new CopyOnWriteArrayList<>();
88 
92  @Nullable
94 
102  protected AbstractMapManager(@NotNull final MapReaderFactory<G, A> mapReaderFactory, @NotNull final ProjectSettings projectSettings, @NotNull final FaceObjectProviders faceObjectProviders, @NotNull final PathManager pathManager) {
103  this.projectSettings = projectSettings;
104  this.mapReaderFactory = mapReaderFactory;
105  this.pathManager = pathManager;
106 
107  final FaceObjectProvidersListener faceObjectProvidersListener = () -> {
108  for (final MapControl<G, A, R> mapControl : mapControls) {
109  mapControl.getMapModel().facesReloaded();
110  }
111  };
112  faceObjectProviders.addFaceObjectProvidersListener(faceObjectProvidersListener);
113  }
114 
115  @Deprecated
116  public void setFileControl(@NotNull final FileControl<G, A, R> fileControl) {
117  this.fileControl = fileControl;
118  }
119 
120  @NotNull
121  @Override
122  public MapControl<G, A, R> newMap(@Nullable final List<G> objects, @NotNull final A mapArchObject, @Nullable final MapFile mapFile, final boolean interactive) {
123  final MapControl<G, A, R> mapControl = createMapControl(objects, mapArchObject, mapFile);
124  mapControls.add(mapControl);
125  for (final MapManagerListener<G, A, R> listener : listenerList) {
126  listener.mapCreated(mapControl, interactive);
127  }
128  if (interactive) {
129  setCurrentMap(mapControl);
130  }
131  return mapControl;
132  }
133 
141  @NotNull
142  protected abstract MapControl<G, A, R> createMapControl(@Nullable List<G> objects, @NotNull A mapArchObject, @Nullable MapFile mapFile);
143 
144  @Nullable
145  @Override
147  if (currentMapControl != null) {
148  return currentMapControl;
149  }
150 
151  return mapControls.isEmpty() ? null : mapControls.get(mapControls.size() - 1);
152  }
153 
154  @Override
155  public void closeMap(@NotNull final MapControl<G, A, R> mapControl) {
156  for (final MapManagerListener<G, A, R> listener : listenerList) {
157  listener.mapClosing(mapControl);
158  }
159  assert mapControl.getUseCounter() <= 0;
160  mapControls.remove(mapControl);
161  if (currentMapControl == mapControl) {
162  setCurrentMap(mapControls.isEmpty() ? null : mapControls.get(0));
163  }
164  for (final MapManagerListener<G, A, R> listener : listenerList) {
165  listener.mapClosed(mapControl);
166  }
167  mapControl.getMapModel().mapClosed();
168  }
169 
170  @NotNull
171  @Override
172  public MapControl<G, A, R> openMapFile(@NotNull final MapFile mapFile, final boolean interactive) throws IOException {
173  // First look whether the file isn't already open.
174  // If so, return the previously loaded map.
175  for (final MapControl<G, A, R> mapControl : mapControls) {
176  final MapFile tmpMapFile = mapControl.getMapModel().getMapFile();
177  if (tmpMapFile != null && tmpMapFile.equals(mapFile)) {
178  mapControl.acquire();
179  return mapControl;
180  }
181  }
182 
183  final MapReader<G, A> decoder = decodeMapFile(mapFile.getFile(), interactive);
184  return newMap(decoder.getGameObjects(), decoder.getMapArchObject(), mapFile, interactive);
185  }
186 
187  @NotNull
188  @Override
189  public MapControl<G, A, R> openMapFile(@NotNull final File file, final boolean interactive) throws IOException {
190  return openMapFile(pathManager.getMapFile(file), interactive);
191  }
192 
202  @NotNull
203  private MapReader<G, A> decodeMapFile(@NotNull final File file, final boolean interactive) throws IOException {
204  final MapReader<G, A> decoder;
205  //noinspection ErrorNotRethrown
206  try {
207  decoder = mapReaderFactory.newMapReader(file);
208  } catch (final OutOfMemoryError ex) {
209  throw new IOException("out of memory", ex);
210  }
211 
212  int outOfMapBoundsDeleted = 0;
213  final StringBuilder outOfMapBoundsObjects = new StringBuilder();
214  final int mapWidth = decoder.getMapArchObject().getMapSize().getWidth();
215  final int mapHeight = decoder.getMapArchObject().getMapSize().getHeight();
216  final Iterator<G> it = decoder.getGameObjects().iterator();
217  while (it.hasNext()) {
218  final GameObject<G, A, R> gameObject = it.next();
219  if (!gameObject.isInContainer()) {
220  final int minX = gameObject.getHead().getMapX() + gameObject.getMinX();
221  final int minY = gameObject.getHead().getMapY() + gameObject.getMinY();
222  final int maxX = gameObject.getHead().getMapX() + gameObject.getMaxX();
223  final int maxY = gameObject.getHead().getMapY() + gameObject.getMaxY();
224  if (minX < 0 || minY < 0 || maxX >= mapWidth || maxY >= mapHeight) {
225  it.remove();
226  if (gameObject.isHead()) {
227  outOfMapBoundsDeleted++;
228  if (outOfMapBoundsDeleted <= DELETED_OBJECTS_TO_REPORT) {
229  outOfMapBoundsObjects.append('\n');
230  outOfMapBoundsObjects.append(gameObject.getBestName());
231  outOfMapBoundsObjects.append(" at ");
232  outOfMapBoundsObjects.append(minX).append('/').append(minY);
233  if (minX != maxX || minY != maxY) {
234  outOfMapBoundsObjects.append("..");
235  outOfMapBoundsObjects.append(maxX).append('/').append(maxY);
236  }
237  } else if (outOfMapBoundsDeleted == DELETED_OBJECTS_TO_REPORT + 1) {
238  outOfMapBoundsObjects.append("\n...");
239  }
240  }
241  }
242  }
243  }
244  if (interactive && outOfMapBoundsDeleted > 0) {
245  fileControl.reportOutOfMapBoundsDeleted(file, outOfMapBoundsDeleted, outOfMapBoundsObjects);
246  }
247 
248  return decoder;
249  }
250 
251  @Override
252  public void setCurrentMap(@Nullable final MapControl<G, A, R> mapControl) {
253  if (currentMapControl == mapControl) {
254  return;
255  }
256 
257  currentMapControl = mapControl;
258 
259  for (final MapManagerListener<G, A, R> listener : listenerList) {
260  listener.currentMapChanged(currentMapControl);
261  }
262  }
263 
264  @NotNull
265  @Override
266  public List<MapControl<G, A, R>> getOpenedMaps() {
267  return Collections.unmodifiableList(mapControls);
268  }
269 
275  @Nullable
276  @Override
278  return currentMapControl;
279  }
280 
281  @Override
282  public void addMapManagerListener(@NotNull final MapManagerListener<G, A, R> listener) {
283  listenerList.add(listener);
284  }
285 
286  @Override
287  public void removeMapManagerListener(@NotNull final MapManagerListener<G, A, R> listener) {
288  listenerList.remove(listener);
289  }
290 
291  @Override
292  public void revert(@NotNull final MapControl<G, A, R> mapControl) throws IOException {
293  final MapFile mapFile = mapControl.getMapModel().getMapFile();
294  if (mapFile == null) {
295  return;
296  }
297 
298  final MapReader<G, A> decoder = decodeMapFile(mapFile.getFile(), false);
299  final MapModel<G, A, R> mapModel = mapControl.getMapModel();
300  final A mapArchObject = mapModel.getMapArchObject();
301  mapModel.beginTransaction("revert");
302  try {
303  mapArchObject.setMapSize(decoder.getMapArchObject().getMapSize());
304  mapArchObject.beginTransaction();
305  try {
306  mapArchObject.setState(decoder.getMapArchObject());
307  } finally {
308  mapArchObject.endTransaction();
309  }
310  mapModel.clearMap();
311  mapModel.addObjectListToMap(decoder.getGameObjects());
312  } finally {
313  mapModel.endTransaction();
314  }
315  mapModel.resetModified();
316  }
317 
318  @Override
319  public File getLocalMapDir() {
320  final MapControl<G, A, R> mapControl = currentMapControl;
321  if (mapControl == null) {
323  }
324 
325  final MapFile mapFile = mapControl.getMapModel().getMapFile();
326  if (mapFile == null) {
328  }
329 
330  return mapFile.getFile().getParentFile();
331  }
332 
333  @Override
334  public void release(@NotNull final MapControl<G, A, R> mapControl) {
335  mapControl.release();
336  if (mapControl.getUseCounter() <= 0) {
337  closeMap(mapControl);
338  }
339  }
340 
341 }
net.sf.gridarta.model.mapmodel.MapModel
A MapModel reflects the data of a map.
Definition: MapModel.java:75
net.sf.gridarta.model.io.MapReader
Interface for classes that read map files.
Definition: MapReader.java:31
net.sf.gridarta.model.mapmodel.MapModel.getMapArchObject
A getMapArchObject()
Returns the Map Arch Object with the meta information about the map.
net.sf.gridarta.model.mapmanager.MapManager
A MapManager manages all opened maps.
Definition: MapManager.java:37
net.sf.gridarta.model.mapmanager.AbstractMapManager.currentMapControl
MapControl< G, A, R > currentMapControl
The current top map we are working with.
Definition: AbstractMapManager.java:93
net.sf.gridarta.model.mapmodel.MapModel.resetModified
void resetModified()
Resets the modified flag to false.
net.sf.gridarta.model.mapmanager.FileControl.reportOutOfMapBoundsDeleted
void reportOutOfMapBoundsDeleted(@NotNull File file, int outOfMapBoundsDeleted, @NotNull StringBuilder outOfMapBoundsObjects)
net.sf.gridarta
Base package of all Gridarta classes.
net.sf.gridarta.model.mapmodel.MapModel.endTransaction
void endTransaction()
End a transaction.
net.sf.gridarta.model.mapmanager.AbstractMapManager
Abstract base class for MapManager implementations.
Definition: AbstractMapManager.java:48
net.sf.gridarta.model.mapmanager.AbstractMapManager.setFileControl
void setFileControl(@NotNull final FileControl< G, A, R > fileControl)
Definition: AbstractMapManager.java:116
net.sf.gridarta.model.io.MapReaderFactory
A factory for creating MapReader instances.
Definition: MapReaderFactory.java:32
net.sf.gridarta.model.gameobject.GameObject.isInContainer
boolean isInContainer()
Check whether this GameObject is in a Container (in Gridarta sense, which means being in a MapSquare ...
net.sf.gridarta.model.baseobject.BaseObject.getMinY
int getMinY()
Determines the minimum y-coordinate of any part relative to the head part.
net.sf
net.sf.gridarta.model.mapmodel.MapModel.beginTransaction
void beginTransaction(@NotNull String name)
Starts a new transaction.
net.sf.gridarta.model.baseobject.BaseObject.getMinX
int getMinX()
Determines the minimum x-coordinate of any part relative to the head part.
net.sf.gridarta.model.mapmanager.FileControl< G, A, R >
net.sf.gridarta.model.mapmanager.MapManagerListener< G, A, R >
net.sf.gridarta.model.io.PathManager
This class contains methods for converting relative map paths to absolute map paths and vice versa.
Definition: PathManager.java:39
net.sf.gridarta.model.mapmodel
Definition: AboveFloorInsertionMode.java:20
net.sf.gridarta.model.mapmodel.MapFile.equals
boolean equals(@Nullable final Object obj)
Definition: MapFile.java:122
net.sf.gridarta.model.io.MapReader.getGameObjects
List< G > getGameObjects()
Return the decoded game objects.
net.sf.gridarta.model.archetype
Definition: AbstractArchetype.java:20
net.sf.gridarta.model.face.FaceObjectProviders
Provider for faces of GameObjects and Archetypes.
Definition: FaceObjectProviders.java:46
net.sf.gridarta.model.gameobject.GameObject
Reflects a game object (object on a map).
Definition: GameObject.java:36
net.sf.gridarta.model.baseobject.BaseObject.getBestName
String getBestName()
Returns the name which is best appropriate to describe this GameObject.
net.sf.gridarta.model.mapcontrol
Definition: DefaultMapControl.java:20
net.sf.gridarta.model.io.MapReaderFactory.newMapReader
MapReader< G, A > newMapReader(@NotNull File file)
Creates a new MapReader instance.
net.sf.gridarta.model.mapmanager.AbstractMapManager.listenerList
final Collection< MapManagerListener< G, A, R > > listenerList
The MapManagerListeners to inform of changes.
Definition: AbstractMapManager.java:87
net.sf.gridarta.model.baseobject.BaseObject.isHead
boolean isHead()
Returns whether this object is a single-part object or the head of the multi-part object.
net.sf.gridarta.model.mapmanager.AbstractMapManager.fileControl
FileControl< G, A, R > fileControl
The main control.
Definition: AbstractMapManager.java:59
net.sf.gridarta.model.mapmanager.AbstractMapManager.addMapManagerListener
void addMapManagerListener(@NotNull final MapManagerListener< G, A, R > listener)
Definition: AbstractMapManager.java:282
net.sf.gridarta.model.mapmanager.AbstractMapManager.getCurrentMap
MapControl< G, A, R > getCurrentMap()
Returns the current top map we are working with.
Definition: AbstractMapManager.java:277
net.sf.gridarta.model.gameobject
GameObjects are the objects based on Archetypes found on maps.
Definition: AbstractGameObject.java:20
net
net.sf.gridarta.model.mapmanager.AbstractMapManager.openMapFile
MapControl< G, A, R > openMapFile(@NotNull final File file, final boolean interactive)
Definition: AbstractMapManager.java:189
net.sf.gridarta.model.baseobject.BaseObject.getMaxX
int getMaxX()
Determines the maximum x-coordinate of any part relative to the head part.
net.sf.gridarta.model.mapmanager.AbstractMapManager.AbstractMapManager
AbstractMapManager(@NotNull final MapReaderFactory< G, A > mapReaderFactory, @NotNull final ProjectSettings projectSettings, @NotNull final FaceObjectProviders faceObjectProviders, @NotNull final PathManager pathManager)
Creates a instance.
Definition: AbstractMapManager.java:102
net.sf.gridarta.model.maparchobject.MapArchObject
Interface for MapArchObjects.
Definition: MapArchObject.java:40
net.sf.gridarta.model.mapmanager.AbstractMapManager.createMapControl
abstract MapControl< G, A, R > createMapControl(@Nullable List< G > objects, @NotNull A mapArchObject, @Nullable MapFile mapFile)
Creates a new MapControl instance.
net.sf.gridarta.model.io.PathManager.getMapFile
MapFile getMapFile(@NotNull final AbsoluteMapPath mapPath)
Returns a MapFile instance from an AbsoluteMapPath.
Definition: PathManager.java:72
net.sf.gridarta.model.mapmanager.AbstractMapManager.openMapFile
MapControl< G, A, R > openMapFile(@NotNull final MapFile mapFile, final boolean interactive)
Definition: AbstractMapManager.java:172
net.sf.gridarta.model.mapmodel.MapFile.getFile
File getFile()
Returns a File for this map file.
Definition: MapFile.java:102
net.sf.gridarta.model.mapmanager.AbstractMapManager.getOpenMap
MapControl< G, A, R > getOpenMap()
Definition: AbstractMapManager.java:146
net.sf.gridarta.model.mapmodel.MapFile
The location of a map file with a map directory.
Definition: MapFile.java:31
net.sf.gridarta.model.io
Reading and writing of maps, handling of paths.
Definition: AbstractAnimationObjectsReader.java:20
net.sf.gridarta.model.settings.ProjectSettings
Settings that apply to a project.
Definition: ProjectSettings.java:29
net.sf.gridarta.model.mapmanager.AbstractMapManager.newMap
MapControl< G, A, R > newMap(@Nullable final List< G > objects, @NotNull final A mapArchObject, @Nullable final MapFile mapFile, final boolean interactive)
Definition: AbstractMapManager.java:122
net.sf.gridarta.model.mapmanager.AbstractMapManager.mapReaderFactory
final MapReaderFactory< G, A > mapReaderFactory
The gridarta objects factory instance.
Definition: AbstractMapManager.java:71
net.sf.gridarta.model.mapmanager.AbstractMapManager.mapControls
final List< MapControl< G, A, R > > mapControls
All open maps.
Definition: AbstractMapManager.java:82
net.sf.gridarta.model.baseobject.BaseObject.getHead
T getHead()
Return the head part of a multi-part object.
net.sf.gridarta.model.mapmanager.AbstractMapManager.closeMap
void closeMap(@NotNull final MapControl< G, A, R > mapControl)
Definition: AbstractMapManager.java:155
net.sf.gridarta.model.mapmanager.AbstractMapManager.release
void release(@NotNull final MapControl< G, A, R > mapControl)
Definition: AbstractMapManager.java:334
net.sf.gridarta.model
net.sf.gridarta.model.archetype.Archetype
Reflects an Archetype.
Definition: Archetype.java:41
net.sf.gridarta.model.face.FaceObjectProvidersListener
Interface for listeners interested in FaceObjectProviders related events.
Definition: FaceObjectProvidersListener.java:29
net.sf.gridarta.model.face
The face is the appearance of an object.
Definition: AbstractFaceObjects.java:20
net.sf.gridarta.model.baseobject.BaseObject.getMaxY
int getMaxY()
Determines the maximum y-coordinate of any part relative to the head part.
net.sf.gridarta.model.mapmanager.AbstractMapManager.getLocalMapDir
File getLocalMapDir()
Definition: AbstractMapManager.java:319
net.sf.gridarta.model.mapmodel.MapModel.clearMap
void clearMap()
Clears this map completely.
net.sf.gridarta.model.mapcontrol.MapControl
Currently nothing more than a marker interface for unification.
Definition: MapControl.java:35
net.sf.gridarta.model.mapcontrol.MapControl.getMapModel
MapModel< G, A, R > getMapModel()
Returns the map model.
net.sf.gridarta.model.maparchobject
Definition: AbstractMapArchObject.java:20
net.sf.gridarta.model.io.MapReader.getMapArchObject
A getMapArchObject()
Returns the MapArchObject read from this MapFileDecode.
net.sf.gridarta.model.mapmanager.AbstractMapManager.pathManager
final PathManager pathManager
The PathManager for converting File instances.
Definition: AbstractMapManager.java:77
net.sf.gridarta.model.mapmanager.AbstractMapManager.removeMapManagerListener
void removeMapManagerListener(@NotNull final MapManagerListener< G, A, R > listener)
Definition: AbstractMapManager.java:287
net.sf.gridarta.model.settings.ProjectSettings.getMapsDirectory
File getMapsDirectory()
Returns the default maps directory.
net.sf.gridarta.model.mapmanager.AbstractMapManager.decodeMapFile
MapReader< G, A > decodeMapFile(@NotNull final File file, final boolean interactive)
Loads a map file.
Definition: AbstractMapManager.java:203
net.sf.gridarta.model.mapmodel.MapModel.getMapFile
MapFile getMapFile()
Returns the map file.
net.sf.gridarta.model.mapmanager.AbstractMapManager.setCurrentMap
void setCurrentMap(@Nullable final MapControl< G, A, R > mapControl)
Definition: AbstractMapManager.java:252
net.sf.gridarta.model.mapmanager.AbstractMapManager.projectSettings
final ProjectSettings projectSettings
The project settings instance.
Definition: AbstractMapManager.java:65
net.sf.gridarta.model.mapmodel.MapModel.addObjectListToMap
void addObjectListToMap(@NotNull Iterable< G > objects)
Adds a list of GameObjects to this map.
net.sf.gridarta.model.face.FaceObjectProvidersListener.facesReloaded
void facesReloaded()
Called whenever the faces have been reloaded.
net.sf.gridarta.model.settings
Definition: AbstractDefaultProjectSettings.java:20
net.sf.gridarta.model.mapmanager.AbstractMapManager.revert
void revert(@NotNull final MapControl< G, A, R > mapControl)
Definition: AbstractMapManager.java:292
it
This document describes some hints and requirements for general development on the CrossfireEditor If you plan to make changes to the editor code or setup please read the following and keep it in derived from a basic editor application called Gridder by Pasi Ker�nen so please communicate with best through the cf devel mailing before considering any fundamental changes About code DO NOT USE TABS No matter what Java development platform you are please configure insert indent Tabs are displayed totally different in every editor and there are millions of different editors out there The insertion of tabs in the source code is messing up the syntax formatting in a way that is UNREPAIRABLE Apart from please keep code indentation accurate This is not just good it helps to keep code readable and in that way dramatically decreases the chance for overlooked bugs Everyone is welcomed to correct indentation errors wherever they are spotted Before you start to do this please double check that your editor is really configured to insert spaces Line feeds may be checked in either in windows or in unix linux style All reasonable text and java editors can deal with both linefeed formats Converting line feeds is but in this case please make sure that only linefeed characters are changed and nothing else is affected Due to the platform independent nature of the editor has the potential to run on almost any given operating system the build process differs greatly between systems as well as java environments In the several people have attempted to add build scripts along with structural changes to optimize the setup on one particular system environment which has led to conflict Please do *not *attempt to change the structure or any directories for the mere purpose of improving a build process or performance in a java environment Build scripts may be placed in the root it would be especially fine if it is just one or two files but the latter is not required Please excuse me for placing such restriction I and many users of the editor greatly appreciate build scripts We just had some real troubles over this issue in the past and I don t want to have them repeated the editor has relatively high performance requirements I ve spent a lot of extra work to keep everything as fast and memory efficient as possible when you add new data fields or calculations in the archetype please make sure they are as efficient as possible and worth both the time and space they consume Now don t be afraid too much No development would be possible without adding calculations and data at all Just bear in mind unlike for many other open source performance does make a difference for the CrossfireEditor The for as many systems as possible In case you are unexperienced with java and note that the graphics look different on every and with every font They also have different sizes proportions and behave different A seemingly trivial and effectless change can wreck havoc for the same GUI run on another system please don t be totally afraid of it
Definition: Developer_README.txt:76
net.sf.gridarta.model.mapmanager.AbstractMapManager.DELETED_OBJECTS_TO_REPORT
static final int DELETED_OBJECTS_TO_REPORT
The maximum number of deleted game objects to report.
Definition: AbstractMapManager.java:53
net.sf.gridarta.model.mapmanager.AbstractMapManager.getOpenedMaps
List< MapControl< G, A, R > > getOpenedMaps()
Definition: AbstractMapManager.java:266