 |
Gridarta Editor
|
Go to the documentation of this file.
20 package net.sf.gridarta.model.mapmodel;
22 import java.awt.Point;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Objects;
31 import java.util.concurrent.CopyOnWriteArrayList;
48 import org.apache.log4j.Category;
49 import org.apache.log4j.Logger;
50 import org.jetbrains.annotations.NotNull;
51 import org.jetbrains.annotations.Nullable;
76 private final transient Object
syncLock =
new Object();
212 public void mapMetaChanged() {
217 public void mapSizeChanged(@NotNull
final Size2D mapSize) {
233 public DefaultMapModel(@NotNull
final AutojoinLists<G, A, R> autojoinLists, @NotNull
final A
mapArchObject, @NotNull
final ArchetypeChooserModel<G, A, R> archetypeChooserModel, @NotNull
final GameObjectFactory<G, A, R> gameObjectFactory, @NotNull
final GameObjectMatchers gameObjectMatchers, @NotNull
final InsertionMode topmostInsertionMode) {
270 for (
final G gameObject : objects) {
271 if (!gameObject.isInContainer()) {
293 if (newSize.equals(mapSize)) {
304 final Collection<GameObject<G, A, R>> objectsToDelete =
new HashSet<>();
305 if (mapSize.
getWidth() > newSize.getWidth()) {
310 if (mapSize.
getHeight() > newSize.getHeight()) {
334 final Iterator<MapSquare<G, A, R>>
it = mapSquares.iterator();
335 while (
it.hasNext()) {
337 if (mapSquare.
getMapX() >= mapSize.getWidth() || mapSquare.
getMapY() >= mapSize.getHeight()) {
349 final Iterator<G> it2 = gameObjects.iterator();
350 while (it2.hasNext()) {
353 if (topGameObject.getContainer() ==
null || topGameObject.getMapX() >= mapSize.getWidth() || topGameObject.getMapY() >= mapSize.getHeight()) {
387 LOG.error(
"beginSquareChange: square (" + mapSquare +
") is about to change outside a transaction");
397 LOG.error(
"endSquareChange: square (" + mapSquare +
") was changed outside a transaction");
398 final Set<MapSquare<G, A, R>> mapSquares =
new HashSet<>(1);
399 mapSquares.add(mapSquare);
413 LOG.error(
"beginGameObjectChange: game object (" + gameObject.getBestName() +
"@" + mapSquare +
") is about to change outside a transaction");
423 LOG.error(
"endGameObjectChange: game object (" + gameObject.getBestName() +
"@" + gameObject.getMapSquare() +
") was changed outside a transaction");
424 final Set<G> gameObjects =
new HashSet<>(1);
425 gameObjects.add(gameObject);
437 LOG.error(
"transientGameObjectChange: game object (" + gameObject.getBestName() +
"@" + gameObject.getMapSquare() +
") was changed outside a transaction");
438 final Set<G> gameObjects =
new HashSet<>(1);
439 gameObjects.add(gameObject);
459 throw new IllegalStateException(
"A transaction must only be used by one thread. " +
transactionThread +
" " + Thread.currentThread());
473 throw new IllegalStateException(
"Tried to end a transaction but no transaction was open.");
492 final Collection<MapSquare<G, A, R>> mapSquares =
new HashSet<>(
changedSquares);
495 if (mapSquare !=
null) {
496 mapSquares.add(mapSquare);
508 if (gameObject.isHead()) {
509 for (G env = gameObject; env !=
null; env = env.getContainerGameObject()) {
562 listener.mapSquaresChanged(mapSquares);
572 if (!gameObjects.isEmpty()) {
576 listener.mapObjectsChanged(gameObjects, transientGameObjects);
587 listener.mapSizeChanged(newSize);
596 listener.preBeginTransaction();
607 listener.beginTransaction(
name);
626 listener.postEndTransaction();
636 listener.mapFileChanged(oldMapFile);
645 listener.modifiedChanged();
652 if (gameObject.isInContainer()) {
666 final Point point =
new Point(part.getMultiX(), part.getMultiY());
667 point.translate(pos.x, pos.y);
674 final String temp = part.getArchetypeName();
676 if (node.getArchetype().getArchetypeName().equals(temp)) {
690 listener.errorsChanged(
errors);
711 final G newGameObject;
713 if (nextGameObject ==
null || nextGameObjectEnv ==
null) {
715 if (newGameObject ==
null) {
723 if (gameObject == nextGameObject) {
728 for (
int i = 0; i < position - 1; i++) {
729 newGameObject.moveDown();
733 nextGameObjectEnv.
addLast(newGameObject);
734 if (templateBaseObject instanceof
Archetype) {
739 return newGameObject;
749 final R realArchetype = baseObject.getArchetype();
750 final R effectiveArchetype;
754 if (gameObject !=
null) {
759 if (effectiveArchetype ==
null) {
763 effectiveArchetype = realArchetype;
772 final List<G> parts =
new ArrayList<>();
773 for (R archetypePart = effectiveArchetype; archetypePart !=
null; archetypePart = archetypePart.getMultiNext()) {
775 if (archetypePart == effectiveArchetype) {
777 part.setArchetype(archetypePart);
781 if (direction !=
null) {
784 if (!parts.isEmpty()) {
785 parts.get(0).addTailPart(part);
790 for (
final G part : parts) {
791 final int mapX = pos.x + part.getArchetype().getMultiX();
792 final int mapY = pos.y + part.getArchetype().getMultiY();
796 final G head = parts.get(0);
807 LOG.error(
"addGameObjectToMap: trying to insert game object out of map bounds at " + pos.x +
"/" + pos.y +
", map bounds is " +
mapArchObject.getMapSize());
815 public void moveEnv(@NotNull
final G gameObject, @NotNull
final Point pos, @NotNull
final G nextGameObject) {
816 if (!nextGameObject.isHead()) {
817 throw new IllegalArgumentException(
"can't move tail part of a multi-part object");
819 assert !gameObject.isMulti();
821 if (nextGameObject.isInContainer()) {
822 nextGameObjectContainer = nextGameObject.getContainer();
823 if (nextGameObjectContainer ==
null) {
824 throw new IllegalArgumentException(
"can't move into container object");
831 throw new IllegalArgumentException(
"can't move into a game object in another map");
834 nextGameObjectContainer.
insertAfter(nextGameObject, gameObject);
837 if (!nextGameObject.isInContainer() && gameObject.getArchetype().isMulti()) {
838 final Point tmp =
new Point();
839 for (R archetypeTail = gameObject.getArchetype().getMultiNext(); archetypeTail !=
null; archetypeTail = archetypeTail.getMultiNext()) {
841 gameObject.addTailPart(gameObjectTail);
842 tmp.x = pos.x + archetypeTail.getMultiX();
843 tmp.y = pos.y + archetypeTail.getMultiY();
851 if (!gameObject.isHead() || !prevGameObject.isHead()) {
852 throw new IllegalArgumentException(
"can't move tail part of a multi-part object");
856 gameObject.removeTailParts();
857 prevGameObject.addFirst(gameObject);
861 public boolean isAreaEmpty(
final int left,
final int top,
final int width,
final int height) {
862 final Point point =
new Point();
863 for (
int x = left; x < left + width; x++) {
865 for (
int y = top; y < top + height; y++) {
881 for (
final Iterable<G> mapSquare :
this) {
896 if (Objects.equals(
this.mapFile,
mapFile)) {
915 if (thisMapFile ==
null) {
919 if (newMapFile.
equals(thisMapFile)) {
928 final List<G> gameObjects =
new ArrayList<>();
929 for (
final Iterable<G> mapSquare :
this) {
930 for (
final G gameObject : mapSquare) {
931 if (gameObject.isHead()) {
932 gameObjects.add(gameObject);
958 for (
final Iterable<G> mapSquare :
this) {
959 for (
final G gameObject : mapSquare) {
960 gameObject.facesReloaded();
969 public void nextPoint(
final Point point,
final int direction) {
973 if (point.x >= mapSize.
getWidth()) {
1011 assert gameObject.isHead();
1012 if (checkType == 0) {
1018 final int editType = gameObject.getEditType();
1020 final int newEditType = retainedEditType |
calculateEditType(gameObject, checkType);
1021 gameObject.setEditType(newEditType);
1033 final int matcherEditType = matcher.getEditType();
1034 if ((matcherEditType & checkType) != 0 && matcher.isMatching(gameObject)) {
1035 editType |= matcherEditType;
1053 if (archetype.isMulti()) {
1058 if (autojoinList ==
null) {
1063 final boolean isMainIndex = autojoinList.
isMainIndex(archetype);
1065 if (gameObject !=
null) {
1066 final R gameObjectArchetype = gameObject.getArchetype();
1067 final boolean isExistingMainIndex = autojoinList.
isMainIndex(gameObjectArchetype);
1070 if (isExistingMainIndex) {
1077 if (isExistingMainIndex) {
1081 if (gameObjectArchetype == archetype) {
1095 final R newArchetype = isMainIndex ? autojoinList.
getArchetype(newIndex) : archetype;
1096 if (gameObject !=
null) {
1097 gameObject.setArchetype(newArchetype);
1103 private int joinInsert(@NotNull
final Point point, @NotNull
final AutojoinList<G, A, R> autojoinList,
final int dx,
final int dy,
final int dir,
final int reverseDir,
final int altIndex) {
1104 final Point tmp =
new Point(point.x + dx, point.y + dy);
1110 if (gameObject ==
null) {
1115 final int index = autojoinList.getAlternativeIndex(archetype);
1117 return (index & reverseDir) == 0 ? 0 : dir;
1120 final int archetypeIndex = autojoinList.getIndex(archetype);
1122 if ((altIndex & dir) == 0) {
1123 newIndex = archetypeIndex & ~reverseDir;
1125 newIndex = archetypeIndex | reverseDir;
1127 gameObject.
setArchetype(autojoinList.getArchetype(newIndex));
1139 private void joinDelete(@NotNull
final Point point, @NotNull
final R archetype) {
1140 if (archetype.isMulti()) {
1145 if (autojoinList ==
null) {
1149 final boolean isMainIndex = autojoinList.
isMainIndex(archetype);
1158 private void joinDelete(@NotNull
final Point point, @NotNull
final AutojoinList<G, A, R> autojoinList,
final int dx,
final int dy,
final int reverseDir,
final int dir,
final int altIndex) {
1159 if ((altIndex & reverseDir) == 0) {
1163 final Point tmp =
new Point(point.x + dx, point.y + dy);
1169 if (gameObject ==
null) {
1186 for (
final G gameObject :
getMapSquare(point).reverse()) {
1206 final R archetype = gameObject.getArchetype();
int getMapY()
Returns the y coordinate on the map.
int getWidth()
Returns the width of the area.
Size2D getMapSize()
Returns the size of this map grid in map squares.
A MapModel reflects the data of a map.
List< G > getAllGameObjects()
Exception thrown if the destination path points to the source map.
Abstract factory for creating GameObject instances.
Implementation of MapModel that covers the similarities between crossfire and daimonin.
DefaultMapModel(@NotNull final AutojoinLists< G, A, R > autojoinLists, @NotNull final A mapArchObject, @NotNull final ArchetypeChooserModel< G, A, R > archetypeChooserModel, @NotNull final GameObjectFactory< G, A, R > gameObjectFactory, @NotNull final GameObjectMatchers gameObjectMatchers, @NotNull final InsertionMode topmostInsertionMode)
Creates a new instance.
boolean isMultiArchFittingToMap(@NotNull final Archetype< G, A, R > archetype, @NotNull final Point pos, final boolean allowDouble)
final transient Object syncLock
Sync Lock Object.
void fireMapSizeChanged(@NotNull final Size2D newSize)
Fires a map size changed event.
MapSquare< G, A, R > getMapSquareOptional()
Returns the MapSquare this game object is part of.
void resize(@NotNull final Size2D newSize)
Resizes the map grid to a new size.
final Set< G > transientChangedGameObjects
The ArrayList with transient changed gameObjects.
Point getMapLocation()
Returns the coordinate on the map.
final transient MapArchObjectListener mapArchObjectListener
The MapArchObjectListener used to detect changes in {} and set the #modified} flag accordingly.
void mapSquaresChanged(@NotNull final Iterable< MapSquare< G, A, R >> mapSquares)
Called whenever some game objects have changed.
final AutojoinLists< G, A, R > autojoinLists
The AutojoinLists for performing autojoining.
int getMapX()
Returns the x coordinate on the map.
void fireEndTransaction()
Fires an end transaction event.
The view of the archetype chooser.
The result of an insertion operation involving autojoining.
int getAlternativeIndex(@NotNull final R archetype)
Returns the index of an Archetype if it is an alternative archetype for any direction.
final LightMapModelTracker< G, A, R > lightMapModelTracker
The LightMapModelTracker tracking this instance.
Base package of all Gridarta classes.
void updateEditType(@NotNull final GameObject< G, A, R > gameObject, final int checkType)
Updates the edit type of a GameObject.
ErrorCollector< G, A, R > errors
The errors of this map model.
void discardInvalidMapSquares(@NotNull final Iterable< MapSquare< G, A, R >> mapSquares, @NotNull final Size2D mapSize)
Discards map squares that are out of map bounds.
boolean isMainIndex(@NotNull final R archetype)
Returns the index of an Archetype if it is a main archetype for any direction.
void setModified()
Marks the map as being modified.
void fireEvents()
Delivers all pending events.
void addMapModelListener(@NotNull final MapModelListener< G, A, R > listener)
void fireBeginTransaction(@NotNull final String name)
Fires a begin transaction event.
final List< MapModelListener< G, A, R > > mapModelListeners
The registered MapModelListeners.
Interface for listeners listening on map arch object changes.
void firePreBeginTransaction()
Fire a pre-begin transaction event.
void mapSizeChanging(@NotNull final Size2D newSize, @NotNull final Size2D oldSize)
Called whenever the tracked map is about to change size.
G insertBaseObject(@NotNull final BaseObject< G, A, R, ?> baseObject, @NotNull final Point pos, final boolean allowMany, final boolean join, @NotNull final InsertionMode insertionMode)
final Collection< MapTransactionListener< G, A, R > > mapTransactionListeners
The registered MapTransactionListeners.
void clearMap()
This implementation is very safe by recreating every single MapSquare as new empty square with the tr...
final ArchetypeChooserModel< G, A, R > archetypeChooserModel
The ArchetypeChooserModel to use when inserting directional game objects.
void endSquareChange(@NotNull final MapSquare< G, A, R > mapSquare)
MapFile getMapFile(@NotNull final MapPath mapPath)
boolean equals(@Nullable final Object obj)
InsertionResult< G, A, R > joinInsert(@NotNull final Point point, @NotNull final R archetype)
Does autojoining on insertion of a game object on the map.
int calculateEditType(@NotNull final GameObject<?, ?, ?> gameObject, final int checkType)
Returns the edit type for a GameObject.
Iterator< MapSquare< G, A, R > > iterator()
Reflects a game object (object on a map).
void fireMapSquaresChangedEvent(final Set< MapSquare< G, A, R >> mapSquares)
Fires a map squares changed event.
void fireGameObjectsChangedEvent(@NotNull final Set< G > gameObjects, @NotNull final Set< G > transientGameObjects)
Fires a game objects changed event.
boolean isAreaEmpty(final int left, final int top, final int width, final int height)
MapSquare< G, A, R > getMapSquare(final int x, final int y)
Returns the MapSquare at a given location.
AutojoinList< G, A, R > getAutojoinList(@NotNull final Archetype< G, A, R > archetype)
Returns an AutojoinList for a given archetype.
void joinDelete(@NotNull final Point point, @NotNull final AutojoinList< G, A, R > autojoinList, final int dx, final int dy, final int reverseDir, final int dir, final int altIndex)
final SavedSquares< G, A, R > savedSquares
Records unchanged square contents for all squares in {}.
void endAllTransactions()
GameObject< G, A, R > findMainGameObjectOfAutojoinList(@NotNull final Point point, @NotNull final AutojoinList< G, A, R > autojoinList)
Looks for an archetype at map-position point which is the main archetypes part of an autojoin list.
void moveInv(@NotNull final G gameObject, @NotNull final GameObject< G, A, R > prevGameObject)
final MapSquareGrid< G, A, R > mapGrid
The map, containing all arches grid-wise.
void beginSquareChange(@NotNull final MapSquare< G, A, R > mapSquare)
Integer getDirection()
Returns the default direction for game objects created from archetypes.
R getArchetype()
Returns the Archetype this GameObject is based on.
Decorates an arbitrary GameObjectMatcher with a localized name that is suitable for the user interfac...
GameObjects are the objects based on Archetypes found on maps.
static final Category LOG
The Logger for printing log messages.
boolean isEmpty()
Returns whether the map is empty.
int getHeight()
Returns the height of the area.
void clear()
Forgets all saved squares.
void endGameObjectChange(@NotNull final G gameObject)
void resizeMapInt(@NotNull final Size2D newSize)
Resizes the map grid after the map size has changed.
void addGameObjectToMap(@NotNull final G gameObject, @NotNull final Point pos, @NotNull final InsertionMode insertionMode)
G findGameObjectOfAutojoinList(@NotNull final Point point, @NotNull final AutojoinList< G, A, R > autojoinList)
Looks for an archetype at map-position point which is part of an autojoin list.
void recordMapSquare(@NotNull final MapSquare< G, A, R > mapSquare)
Records a map square as changed.
void removeMapTransactionListener(@NotNull final MapTransactionListener< G, A, R > listener)
Classes related to matching {GameObjects}, so called { net.sf.gridarta.model.match....
void fireModifiedChanged()
Fires a map size changed event.
void collectHeads(final int minX, final int minY, final int maxX, final int maxY, @NotNull final Collection< GameObject< G, A, R >> objectsToDelete)
Adds all head parts for game object within an area to a collection.
Interface for MapArchObjects.
void discardInvalidGameObjects(@NotNull final Iterable< G > gameObjects, @NotNull final Size2D mapSize)
Discards game objects that are out of map bounds.
Maintains GameObjectMatcher instances.
void removeGameObject(@NotNull final G gameObject, final boolean join)
transient Thread transactionThread
The thread that performs the current transaction.
MapSquare< G, A, R > getMapSquare(@NotNull final Point pos)
boolean isAnyTransactionActive()
An interface for classes that collect errors.
Represents a maps directory local map path.
int transactionDepth
The transaction depth.
Exception thrown if an operation is attempted on an unsaved map.
This package contains the framework for validating maps.
Contains a list of (typically wall-)arches which do autojoining.
int getTransactionDepth()
final GameObjectMatchers gameObjectMatchers
The GameObjectMatchers to use.
void endTransaction(final boolean fireEvent)
The location of a map file with a map directory.
Manages a mapping between archetypes to AutojoinLists.
void commitTransaction()
Performs ending a transaction.
MapModel< G, A, R > getMapModel()
Returns the MapModel this map square is part of.
void firePostEndTransaction()
Fires a post-end transaction event.
int activeEditType
Contains the edit types that have already been (requested and) calculated (edit types get calculated ...
void insertAfter(@Nullable final G previousGameObject, @NotNull final G gameObject)
Adds a game object after another.
void prependMapModelListener(@NotNull final MapModelListener< G, A, R > listener)
ErrorCollector< G, A, R > getErrors()
void nextPoint(final Point point, final int direction)
int joinInsert(@NotNull final Point point, @NotNull final AutojoinList< G, A, R > autojoinList, final int dx, final int dy, final int dir, final int reverseDir, final int altIndex)
final GameObjectFactory< G, A, R > gameObjectFactory
The GameObjectFactory for creating GameObjects.
boolean modified
Set if the map has changed since last save.
void beginGameObjectChange(@NotNull final G gameObject)
void addLast(@NotNull G gameObject)
Add the given GameObject at the end of this Container.
G getTopContainer()
Get the topmost container of this GameObject (in Game sense, which means being in a MapSquare isn't,...
void addActiveEditType(final int editType)
final A mapArchObject
The MapArchObject associated with this model.
void beginTransaction(@NotNull final String name)
final Set< MapSquare< G, A, R > > changedSquares
The ArrayList with changed squares.
void addObjectListToMap(@NotNull final Iterable< G > objects)
MapFile mapFile
The backing map file.
final Set< G > changedGameObjects
The ArrayList with changed gameObjects.
R getArchetype(final int index)
Simple error collector that just collects the error in a collection for later retrieval through itera...
void joinDelete(@NotNull final Point point, @NotNull final R archetype)
Does autojoining on deletion of a GameObject on the map.
T getMultiNext()
Returns the next of this multi-part object.
void moveEnv(@NotNull final G gameObject, @NotNull final Point pos, @NotNull final G nextGameObject)
void fireMapFileChanged(@Nullable final MapFile oldMapFile)
Firess a map file changed event.
static final long serialVersionUID
The serial version UID.
G insertArchToMap(@NotNull final BaseObject< G, A, R, ?> templateBaseObject, @Nullable final G nextGameObject, @NotNull final Point pos, final boolean join)
@xxx I'm too complex
void setMapFile(@Nullable final MapFile mapFile)
Base class for classes that contain GameObjects as children in the sense of containment.
void transientGameObjectChange(@NotNull final G gameObject)
void addMapTransactionListener(@NotNull final MapTransactionListener< G, A, R > listener)
The class Size2D represents a 2d rectangular area.
void removeMapModelListener(@NotNull final MapModelListener< G, A, R > listener)
G getGameObject()
Returns the GameObject that has been modified.
void setErrors(@NotNull final ErrorCollector< G, A, R > errors)
abstract MapSquare< G, A, R > getMapSquare()
Returns the MapSquare this game object is part of.
MapSquare< G, A, R > getMapSquare()
Returns the MapSquare this game object is part of.
R getArchetype()
Returns the Archetype that should be inserted.
void setArchetype(@NotNull R archetype)
Set the Archetype of this GameObject.
Iterator for iterating over all squares of a model.
final InsertionMode topmostInsertionMode
The "topmost" InsertionMode.
void createInventory(@NotNull GameObject< G, A, R > gameObject, @NotNull Iterable< G > archetype)
Copies inventory objects from an archetype into a game object.
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
String DIRECTION
The attribute name of the object's direction.
G getContainerGameObject()
Returns the environment game object if this game object is in the inventory or.