Gridarta Editor
AbstractArchetypeParser.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2015 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.io;
21 
22 import java.io.BufferedReader;
23 import java.io.IOException;
24 import java.util.List;
37 import net.sf.japi.swing.action.ActionBuilder;
38 import net.sf.japi.swing.action.ActionBuilderFactory;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.annotations.Nullable;
41 
47 public abstract class AbstractArchetypeParser<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>, B extends AbstractArchetypeBuilder<G, A, R>> implements ArchetypeParser<G, A, R> {
48 
52  @NotNull
53  private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta");
54 
58  @NotNull
59  private final B archetypeBuilder;
60 
64  @NotNull
66 
70  @NotNull
72 
80  this.archetypeBuilder = archetypeBuilder;
81  this.animationObjects = animationObjects;
82  this.archetypeSet = archetypeSet;
83  }
84 
85  @Override
86  public void parseArchetypeFromStream(@NotNull final BufferedReader in, @Nullable final R prototype, @Nullable final String line, @Nullable final String archName, @NotNull final String panelName, @NotNull final String folderName, @NotNull final String archPath, @NotNull final List<G> invObjects, @NotNull final ErrorViewCollector errorViewCollector) throws IOException {
87  archetypeBuilder.init(prototype, errorViewCollector);
88  final boolean isInternPath;
89  // path is needed when we don't read from collection because there is no editor_folder in arc files
90  @Nullable final String path;
91  if (!archetypeSet.isLoadedFromArchive() && archName == null) {
92  final String tmpPath = archPath + "/";
93  isInternPath = tmpPath.startsWith("/intern/");
94  path = tmpPath;
95  } else {
96  isInternPath = false;
97  path = "";
98  }
99 
100  String thisLine2;
101  if (line == null) {
102  thisLine2 = in.readLine();
103  } else {
104  thisLine2 = line; // pre read "Object" from artifacts file loader
105  }
106 
108  @Nullable R firstArch = null;
109  boolean archMore = false;
110  R lastArch = null;
111  boolean reportError = true;
112 
113 LOOP:
114  while (true) {
115  while (true) {
116  if (thisLine2 == null) {
117  break LOOP;
118  }
119 
120  final String thisLine = thisLine2.trim();
121  if (thisLine.startsWith("#") || thisLine.isEmpty()) {
122  thisLine2 = in.readLine();
123  continue;
124  }
125 
126  if (thisLine.equals("More")) {
127  if (firstArch == null) {
128  firstArch = lastArch;
129  }
130  archMore = true;
131  } else if (isStartLine(thisLine)) {
132  break;
133  } else if (!thisLine.isEmpty() && thisLine.charAt(0) != '#') {
134  if (reportError) {
135  reportError = false;
136  errorViewCollector.addWarning(ErrorViewCategory.ARCHETYPE_INVALID, "unexpected line: " + thisLine);
137  }
138  }
139 
140  thisLine2 = in.readLine();
141  }
142 
143  final String archetypeName = archName == null ? thisLine2.trim().substring(7) : archName;
144  archetypeBuilder.reInit(archetypeName);
145  if (!archMore) {
146  if (firstArch != null) {
147  finishParseArchetype(firstArch);
148  }
149  firstArch = null;
150  }
151 
153 
154  @NotNull String editorFolder = archPath.isEmpty() ? "default" : archPath;
155  while (true) {
156  thisLine2 = in.readLine();
157  if (thisLine2 == null) {
158  errorViewCollector.addError(ErrorViewCategory.ARCHETYPE_INVALID, "missing 'end' line");
159  break LOOP;
160  }
161 
162  final String thisLine = thisLine2.trim();
163  if (thisLine.startsWith("#") || thisLine.isEmpty()) {
164  continue;
165  }
166 
167  if (processLine(in, thisLine, thisLine2, archetypeBuilder, errorViewCollector, invObjects)) {
168  // ignore
169  } else if (isStartLine(thisLine)) {
170  errorViewCollector.addWarning(ErrorViewCategory.ARCHETYPE_INVALID, ACTION_BUILDER.format("logInventoryInDefArch", thisLine));
171  } else if (thisLine.equals("end")) {
172  break;
173  } else if (thisLine.equals("msg")) {
174  parseMsg(in, errorViewCollector);
175  } else if (thisLine.equals("anim")) {
176  parseAnim(in, errorViewCollector, path);
177  } else if (thisLine.startsWith("visibility ")) {
178  errorViewCollector.addWarning(ErrorViewCategory.ARCHETYPE_INVALID, "Ignoring obsolete 'visibility' attribute: " + archetypeBuilder.getArchetypeName());
179  } else if (thisLine.startsWith("magicmap ")) {
180  errorViewCollector.addWarning(ErrorViewCategory.ARCHETYPE_INVALID, "Ignoring obsolete 'magicmap' attribute: " + archetypeBuilder.getArchetypeName());
181  } else if (thisLine.startsWith("x ")) {
182  if (!archMore && !archetypeBuilder.getArchetypeName().equals(START_ARCH_NAME)) {
183  errorViewCollector.addWarning(ErrorViewCategory.ARCHETYPE_INVALID, ACTION_BUILDER.format("logFoundCoordInDefArchSingleSquareOrHead", "x", archetypeBuilder.getArchetypeName()));
184  archetypeBuilder.addObjectText(thisLine);
185  } else {
186  archetypeBuilder.setMultiX(Integer.parseInt(thisLine.substring(2)));
187  }
188  } else if (thisLine.startsWith("y ")) {
189  if (!archMore && !archetypeBuilder.getArchetypeName().equals(START_ARCH_NAME)) {
190  errorViewCollector.addWarning(ErrorViewCategory.ARCHETYPE_INVALID, ACTION_BUILDER.format("logFoundCoordInDefArchSingleSquareOrHead", "y", archetypeBuilder.getArchetypeName()));
191  archetypeBuilder.addObjectText(thisLine);
192  } else {
193  archetypeBuilder.setMultiY(Integer.parseInt(thisLine.substring(2)));
194  }
195  } else if (thisLine.startsWith("editor_folder ")) {
196  editorFolder = thisLine.substring(14).trim();
197  } else {
198  archetypeBuilder.addObjectText(thisLine);
199  }
200  }
201 
202  final R archetype = archetypeBuilder.finish();
203 
204  if (firstArch != null) {
205  firstArch.addTailPart(archetype);
206  } else if (addToPanel(isInternPath, editorFolder, archetype)) {
207  final String panel;
208  final String folder;
209  if (!archetypeSet.isLoadedFromArchive() || archName != null) {
210  panel = panelName;
211  folder = folderName;
212  } else {
213  final String[] names = StringUtils.PATTERN_SLASH.split(editorFolder, 3);
214  panel = names[0];
215  folder = names[names.length >= 2 ? 1 : 0];
216  }
217  archetype.setEditorFolder(panel + "/" + folder);
218  } else {
219  archetype.setEditorFolder(GameObject.EDITOR_FOLDER_INTERN);
220  }
221  finishParseArchetypePart(firstArch, archetype, errorViewCollector);
222  try {
223  archetypeSet.addArchetype(archetype);
224  } catch (final DuplicateArchetypeException ex) {
225  errorViewCollector.addWarning(ErrorViewCategory.ARCHETYPE_INVALID, ex.getMessage());
226  }
227 
228  archMore = false;
229 
230  if (archName != null) {
231  archetype.setArtifact();
232  if (prototype != null) {
233  archetype.addObjectText(AttributeListUtils.diffArchTextKeys(archetype, prototype));
234  }
235  break;
236  }
237  lastArch = archetype;
238  reportError = true;
239 
240  thisLine2 = in.readLine();
241  }
242 
243  if (firstArch != null) {
244  finishParseArchetype(firstArch);
245  }
246  }
247 
254  private void parseMsg(@NotNull final BufferedReader in, @NotNull final ErrorViewCollector errorViewCollector) throws IOException {
255  final StringBuilder msgText = new StringBuilder();
256 
257  while (true) {
258  final String thisLine2 = in.readLine();
259  if (thisLine2 == null) {
260  errorViewCollector.addError(ErrorViewCategory.ARCHETYPE_INVALID, "Truncated archetype: msg not terminated by endmsg");
261  return;
262  }
263 
264  final String thisLine3 = thisLine2.trim();
265  if (thisLine3.equals("endmsg")) {
266  break;
267  }
268 
269  // keep leading whitespace
270  msgText.append(thisLine2).append("\n");
271  }
272 
273  if (msgText.length() > 0) {
274  archetypeBuilder.setMsgText(msgText.toString());
275  }
276  }
277 
285  private void parseAnim(@NotNull final BufferedReader in, @NotNull final ErrorViewCollector errorViewCollector, @NotNull final String path) throws IOException {
286  final StringBuilder animText = new StringBuilder();
287 
288  while (true) {
289  final String thisLine2 = in.readLine();
290  if (thisLine2 == null) {
291  errorViewCollector.addError(ErrorViewCategory.ARCHETYPE_INVALID, "Truncated animation: anim not terminated by mina");
292  return;
293  }
294 
295  final String thisLine3 = thisLine2.trim();
296  if (thisLine3.startsWith("#") || thisLine3.isEmpty()) {
297  continue;
298  }
299 
300  if (thisLine3.equals("mina")) {
301  break;
302  }
303 
304  animText.append(thisLine3).append("\n");
305  }
306 
307  final String animationName = "_" + archetypeBuilder.getArchetypeName();
308  try {
309  animationObjects.addAnimationObject(animationName, animText.toString(), path + animationName);
310  } catch (final DuplicateAnimationException e) {
311  errorViewCollector.addWarning(ErrorViewCategory.ARCHETYPE_INVALID, ACTION_BUILDER.format("logDuplicateAnimation", e.getDuplicate().getAnimName()));
312  } catch (final IllegalAnimationException ex) {
313  errorViewCollector.addWarning(ErrorViewCategory.ARCHETYPE_INVALID, "illegal animation: " + ex.getAnimationObject().getPath());
314  }
315  }
316 
320  protected abstract void initParseArchetype();
321 
327  protected abstract boolean isStartLine(@NotNull String line);
328 
340  protected abstract boolean processLine(@NotNull BufferedReader in, @NotNull String line, @NotNull String line2, @NotNull B archetypeBuilder, @NotNull ErrorViewCollector errorViewCollector, @NotNull List<G> invObjects) throws IOException;
341 
349  protected abstract void finishParseArchetypePart(@Nullable R firstArch, @NotNull R archetype, @NotNull ErrorViewCollector errorViewCollector);
350 
355  protected abstract void finishParseArchetype(@NotNull R archetype);
356 
364  protected abstract boolean addToPanel(boolean isInternPath, @NotNull String editorFolder, @NotNull R archetype);
365 
366 }
net.sf.gridarta.model.io.AbstractArchetypeParser.finishParseArchetypePart
abstract void finishParseArchetypePart(@Nullable R firstArch, @NotNull R archetype, @NotNull ErrorViewCollector errorViewCollector)
net.sf.gridarta.utils.StringUtils.PATTERN_SLASH
static final Pattern PATTERN_SLASH
Definition: StringUtils.java:79
net.sf.gridarta.model.anim.AnimationObjects.addAnimationObject
void addAnimationObject(@NotNull String animName, @NotNull String list, @NotNull String path)
net.sf.gridarta
net.sf.gridarta.model.io.AbstractArchetypeParser
Definition: AbstractArchetypeParser.java:47
net.sf.gridarta.model.anim.AnimationObjects
Definition: AnimationObjects.java:30
net.sf.gridarta.model.anim.DuplicateAnimationException
Definition: DuplicateAnimationException.java:27
net.sf.gridarta.model.io.AbstractArchetypeParser.finishParseArchetype
abstract void finishParseArchetype(@NotNull R archetype)
net.sf
net.sf.gridarta.model.anim.DuplicateAnimationException.getDuplicate
AnimationObject getDuplicate()
Definition: DuplicateAnimationException.java:52
net.sf.gridarta.model.io.AttributeListUtils
Definition: AttributeListUtils.java:30
net.sf.gridarta.model.archetype
Definition: AbstractArchetype.java:20
net.sf.gridarta.model.gameobject.GameObject
Definition: GameObject.java:36
net.sf.gridarta.model.io.AbstractArchetypeParser.ACTION_BUILDER
static final ActionBuilder ACTION_BUILDER
Definition: AbstractArchetypeParser.java:53
net.sf.gridarta.model.anim.AnimationObject.getAnimName
String getAnimName()
net.sf.gridarta.model.io.AbstractArchetypeParser.initParseArchetype
abstract void initParseArchetype()
net.sf.gridarta.model.io.ArchetypeParser
Definition: ArchetypeParser.java:36
net.sf.gridarta.model.io.AbstractArchetypeParser.processLine
abstract boolean processLine(@NotNull BufferedReader in, @NotNull String line, @NotNull String line2, @NotNull B archetypeBuilder, @NotNull ErrorViewCollector errorViewCollector, @NotNull List< G > invObjects)
net.sf.gridarta.model.io.AbstractArchetypeParser.parseAnim
void parseAnim(@NotNull final BufferedReader in, @NotNull final ErrorViewCollector errorViewCollector, @NotNull final String path)
Definition: AbstractArchetypeParser.java:285
net.sf.gridarta.model.io.AbstractArchetypeParser.AbstractArchetypeParser
AbstractArchetypeParser(@NotNull final B archetypeBuilder, @NotNull final AnimationObjects animationObjects, @NotNull final ArchetypeSet< G, A, R > archetypeSet)
Definition: AbstractArchetypeParser.java:79
net.sf.gridarta.model.io.ArchetypeParser< G, A, R >::START_ARCH_NAME
String START_ARCH_NAME
Definition: ArchetypeParser.java:41
net.sf.gridarta.model.gameobject
Definition: AbstractGameObject.java:20
net.sf.gridarta.model.io.AttributeListUtils.diffArchTextKeys
static String diffArchTextKeys(@NotNull final BaseObject<?, ?, ?, ?> gameObject, @NotNull final BaseObject<?, ?, ?, ?> archetype)
Definition: AttributeListUtils.java:72
net.sf.gridarta.model.anim.IllegalAnimationException
Definition: IllegalAnimationException.java:29
net
net.sf.gridarta.model.archetypeset.ArchetypeSet.addArchetype
void addArchetype(@NotNull R archetype)
net.sf.gridarta.model.errorview
Definition: ErrorView.java:20
net.sf.gridarta.model.errorview.ErrorViewCollector
Definition: ErrorViewCollector.java:31
net.sf.gridarta.model.io.AbstractArchetypeParser.parseMsg
void parseMsg(@NotNull final BufferedReader in, @NotNull final ErrorViewCollector errorViewCollector)
Definition: AbstractArchetypeParser.java:254
net.sf.gridarta.model.errorview.ErrorViewCategory
Definition: ErrorViewCategory.java:28
net.sf.gridarta.model.maparchobject.MapArchObject
Definition: MapArchObject.java:40
net.sf.gridarta.model.errorview.ErrorViewCategory.ARCHETYPE_INVALID
ARCHETYPE_INVALID
Definition: ErrorViewCategory.java:50
net.sf.gridarta.model.archetypeset.ArchetypeSet
Definition: ArchetypeSet.java:37
net.sf.gridarta.utils.StringUtils
Definition: StringUtils.java:31
net.sf.gridarta.model.archetype.AbstractArchetypeBuilder
Definition: AbstractArchetypeBuilder.java:40
net.sf.gridarta.model.gameobject.GameObject.EDITOR_FOLDER_INTERN
String EDITOR_FOLDER_INTERN
Definition: GameObject.java:42
net.sf.gridarta.model.io.AbstractArchetypeParser.animationObjects
final AnimationObjects animationObjects
Definition: AbstractArchetypeParser.java:65
net.sf.gridarta.model.io.AbstractArchetypeParser.addToPanel
abstract boolean addToPanel(boolean isInternPath, @NotNull String editorFolder, @NotNull R archetype)
net.sf.gridarta.model
net.sf.gridarta.model.archetype.Archetype
Definition: Archetype.java:41
net.sf.gridarta.model.io.AbstractArchetypeParser.archetypeBuilder
final B archetypeBuilder
Definition: AbstractArchetypeParser.java:59
net.sf.gridarta.model.archetypeset.ArchetypeSet.isLoadedFromArchive
boolean isLoadedFromArchive()
net.sf.gridarta.model.data.NamedObject.getPath
String getPath()
net.sf.gridarta.model.anim
Definition: AbstractAnimationObjects.java:20
net.sf.gridarta.model.archetype.DuplicateArchetypeException
Definition: DuplicateArchetypeException.java:29
net.sf.gridarta.model.maparchobject
Definition: AbstractMapArchObject.java:20
net.sf.gridarta.model.io.AbstractArchetypeParser.archetypeSet
final ArchetypeSet< G, A, R > archetypeSet
Definition: AbstractArchetypeParser.java:71
net.sf.gridarta.model.archetypeset
Definition: ArchetypeSet.java:20
net.sf.gridarta.model.io.AbstractArchetypeParser.parseArchetypeFromStream
void parseArchetypeFromStream(@NotNull final BufferedReader in, @Nullable final R prototype, @Nullable final String line, @Nullable final String archName, @NotNull final String panelName, @NotNull final String folderName, @NotNull final String archPath, @NotNull final List< G > invObjects, @NotNull final ErrorViewCollector errorViewCollector)
Definition: AbstractArchetypeParser.java:86
net.sf.gridarta.model.anim.IllegalAnimationException.getAnimationObject
NamedObject getAnimationObject()
Definition: IllegalAnimationException.java:58
net.sf.gridarta.utils
Definition: ActionBuilderUtils.java:20
net.sf.gridarta.model.io.AbstractArchetypeParser.isStartLine
abstract boolean isStartLine(@NotNull String line)