/* * (c) 2000-2009 Carlos G�mez Rodr�guez, todos los derechos reservados / all rights reserved. * Licencia en license/bsd.txt / License in license/bsd.txt */ package eu.irreality.age; //package AetheriaAWT; /** * Informaci�n sobre el mundo como un todo. * * @author Carlos G�mez */ import java.io.*; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.*; import java.util.jar.JarFile; import javax.xml.parsers.*; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.stream.StreamSource; //import javax.xml.transform.*; //import javax.xml.transform.stream.*; //import javax.xml.transform.dom.*; import org.xml.sax.*; import org.w3c.dom.*; import eu.irreality.age.debug.Debug; import eu.irreality.age.debug.ExceptionPrinter; import eu.irreality.age.filemanagement.Paths; import eu.irreality.age.i18n.UIMessages; import eu.irreality.age.messages.Messages; import eu.irreality.age.scripting.ScriptException; import eu.irreality.age.spell.AGESpellChecker; import eu.irreality.age.util.VersionComparator; public class World implements Informador , SupportingCode { private boolean debugMode = true; /**Nombre del mundo.*/ private String worldname; /**Nombre "bonito" del mundo.*/ private String modulename; /**Directorio del mundo.*/ private String worlddir; /**To locate resources.*/ private URL worldurl; /**M�ximo n�mero de habitaciones del mundo.*/ private int maxroom; /**M�ximo n�mero de objetos del mundo.*/ private int maxitem; /**M�ximo n�mero de bichos del mundo.*/ private int maxmob; /**M�ximo n�mero de entidades abstractas del mundo.*/ private int maxabsent; /**M�ximo n�mero de hechizos del mundo.*/ private int maxspell; /**Habitaciones*/ private Room[] room; /**Items*/ private Item[] item; /**Bichos*/ private Mobile[] mob; /**Efectos*/ private AbstractEntity[] absent; /**Hechizos*/ private Spell[] spell; /**Salida del mundo*/ private InputOutputClient io; /**Jugador*/ //private Player player; //NAY!!! Multiplayer rlz!!!! private List playerList = new Vector(); /**Su c�digo*/ private ObjectCode itsCode; /**Autor del mundo.*/ private String author=null; /**Versi�n del mundo.*/ private String version=null; /**Versi�n del parser.*/ private String parserVersion=null; /**Fecha.*/ private String date =null; /**Tipo de mundo. (RPG, aventura...)*/ private String type =null; /**Generador de n�meros aleatorios*/ private java.util.Random aleat; private long semilla; /**Lenguaje*/ private NaturalLanguage lenguaje; /**Tabla de nombres, para convertir nombres a n�meros y viceversa*/ private Map nameTable; /**Sincronizaci�n: ha sido ejecutada la serverintro?*/ public boolean serverIntroExeccedFlag; public Object serverIntroSyncObject = new Object(); /**Tabla de nodos de las entidades creada en la primera fase de las cargas, a la vez que la tabla de nombres. (se consultara para las cargas diferidas)*/ private org.w3c.dom.Element[] itemNode; private org.w3c.dom.Element[] mobNode; private org.w3c.dom.Element[] roomNode; private org.w3c.dom.Element[] absentNode; private org.w3c.dom.Element[] spellNode; /*Configuraci�n visual para clientes a este mundo.*/ private VisualConfiguration vc; /*Lista de ficheros multimedia a enviar a clientes*/ private List fileList = new ArrayList(); //of String //templates para crear Players como DAIO's. (Dynamically Assigned ID Objects) private List playerTemplateNodes = new ArrayList(); //list of org.w3c.dom.Element private HashMap playerTemplateNodesByName = new HashMap(); //map of names to org.w3c.dom.Element //Players que est�n esperando a ser a�adidos al mundo. private List playersToAdd = new Vector(); private BufferedReader logReader; boolean from_log; //input gotten from log //world language String languageCode = NaturalLanguage.DEFAULT_LANGUAGE_CODE; //default messages private Messages messages; public Messages getMessages() { return messages; } /** * Loads a set of messages for this world from an URL. * @param u Location that contains the messages. * @throws IOException If the message file is not found. */ public void loadMessages ( URL u ) throws IOException { Messages m = new Messages(u); m.setWorld(this); messages = m; } /** * Does the necessary processing on the world after finishing loading a log. * This currently amounts to calling each player's endOfLog() method, * and calling the world's onLogLoaded() scripted method if present so that the programmer can customize behaviors * to execute after a log has finished loading. */ public void endOfLog() { from_log = false; List jugadores = getPlayerList(); for ( int i = 0 ; i < jugadores.size() ; i++ ) { Player jugador = (Player) jugadores.get(i); jugador.endOfLog(); } try { execCode("onLogLoaded" , new Object[] {}); } catch ( ScriptException te ) { writeError(ExceptionPrinter.getExceptionReport(te,"onLogLoaded(), world " + this)); } } /** * Opens a log file either in the path directly specified or, if not found, in the saves directory. * @param s * @return * @throws java.io.FileNotFoundException */ public FileInputStream openLogFile ( String s ) throws java.io.FileNotFoundException { FileInputStream logInput = null; try { logInput = new FileInputStream(s); } catch ( FileNotFoundException exc ) { try { logInput = new FileInputStream ( new File ( Paths.SAVE_PATH , s ) ); } catch ( FileNotFoundException exc2 ) { throw(exc); } } return logInput; } /* Multiplayer Log Support (try): 04.03.29 This substitutes Player::prepareLog(String). Prepares (same) log for (all) world's players. First tries the path s as it comes, then tries it relative to the default saves directory. */ public void prepareLog(String s) throws java.io.FileNotFoundException { from_log = true; FileInputStream logInput = openLogFile(s); prepareLog ( logInput ); } /** * Prepare (multiplayer, in theory) log from input stream. * @param is */ public void prepareLog ( InputStream logInput ) { from_log = true; logReader = new BufferedReader ( Utility.getBestInputStreamReader ( logInput ) ); try { logReader.readLine(); //la primera linea no contiene un comando logReader.readLine(); //la segunda tampoco } catch ( java.io.IOException exc ) { write(io.getColorCode("error") + "Excepci�n I/O al leer el log" + io.getColorCode("reset")); } List jugadores = getPlayerList(); for ( int i = 0 ; i < jugadores.size() ; i++ ) { Player jugador = (Player) jugadores.get(i); jugador.prepareLog ( logReader ); } } private static Document dummyDoc = null; //memory optimisation, remove references to the Document from nodes that are to be retained in the World public static Node getDetachedCopy ( Node n ) { try { if ( dummyDoc == null ) dummyDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); return dummyDoc.importNode(n, true); } catch ( Exception exc ) { exc.printStackTrace(); return n; } } /** * Toma la informaci�n del mundo del documento XML. * */ public void loadWorldFromXML ( org.w3c.dom.Node n , final InputOutputClient io , boolean noSerCliente ) throws XMLtoWorldException { this.io = io; boolean jugadorAsignadoACliente = false; //"true" si io ya tiene un jugador asignado. //(en principio, de momento, le asignaremos todos los jugadores que se vean y //si no vemos ninguno le crearemos un DAIO de las templates. //En el futuro, tal vez pasar un array de InputOutputClient, en vez de un //InputOutputClient a secas, para ir asignando clientes a los jugadores. O... algo. write( io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.info") + "\n" + io.getColorCode("reset") ); if ( ! ( n instanceof org.w3c.dom.Element ) ) { throw ( new XMLtoWorldException ( "World node not Element" ) ); } //{n is an Element} org.w3c.dom.Element e = (org.w3c.dom.Element) n; //default values worldname = UIMessages.getInstance().getMessage("load.world.default.name"); version = UIMessages.getInstance().getMessage("load.world.default.version"); parserVersion = UIMessages.getInstance().getMessage("load.world.default.required"); modulename = UIMessages.getInstance().getMessage("load.world.default.modulename"); maxroom = 0 ; maxitem = 0 ; maxmob = 0; //player: have to get player's ID author = UIMessages.getInstance().getMessage("load.world.default.author"); date = UIMessages.getInstance().getMessage("load.world.default.date"); type = UIMessages.getInstance().getMessage("load.world.default.type"); //si hay un worldDir expl�cito, estaremos en un fichero de estado, as� que fijamos worldDir. if ( e.hasAttribute("worldDir") && !e.getAttribute("worldDir").equals(".") ) { worlddir = e.getAttribute("worldDir"); try { worldurl = new URL(worlddir); } catch (MalformedURLException e1) { try { worldurl = new File(worlddir).toURI().toURL(); } catch (MalformedURLException e2) { System.err.println("worldDir attribute seems neither pathname nor URL:"); e1.printStackTrace(); e2.printStackTrace(); } } } //attribs //mandatory XML-attribs exceptions if ( !e.hasAttribute("worldName") ) throw ( new XMLtoWorldException ( "World node lacks attribute worldName" ) ); if ( !e.hasAttribute("moduleName") ) throw ( new XMLtoWorldException ( "Item node lacks attribute moduleName" ) ); //calculate maximum index attrs if nonexistent if ( !e.hasAttribute("maxroom") ) { maxroom = e.getElementsByTagName("Room").getLength(); } if ( !e.hasAttribute("maxitem") ) { maxitem = e.getElementsByTagName("Item").getLength(); } if ( !e.hasAttribute("maxmob") ) { maxmob = e.getElementsByTagName("Mobile").getLength(); Debug.println("Max Mob set to " + maxmob); } if ( !e.hasAttribute("maxabsent") ) { maxabsent = e.getElementsByTagName("AbstractEntity").getLength(); Debug.println("Max Abstract set to " + maxmob); } if ( !e.hasAttribute("maxspell") ) { maxspell = e.getElementsByTagName("Spell").getLength(); Debug.println("Max Spell set to " + maxmob); } //mandatory XML-attribs parsing worldname = e.getAttribute("worldName"); modulename = e.getAttribute("moduleName"); //non-mandatory attribs try { if ( e.hasAttribute("maxroom") ) { maxroom = Integer.valueOf ( e.getAttribute("maxroom") ).intValue(); } } catch ( NumberFormatException nfe ) { ; //retain default value } try { if ( e.hasAttribute("maxitem") ) { maxitem = Integer.valueOf ( e.getAttribute("maxitem") ).intValue(); } } catch ( NumberFormatException nfe ) { ; //retain default value } try { if ( e.hasAttribute("maxmob") ) { maxmob = Integer.valueOf ( e.getAttribute("maxmob") ).intValue(); } } catch ( NumberFormatException nfe ) { ; //retain default value } try { if ( e.hasAttribute("maxabsent") ) { maxabsent = Integer.valueOf ( e.getAttribute("maxabsent") ).intValue(); } } catch ( NumberFormatException nfe ) { ; //retain default value } try { if ( e.hasAttribute("maxspell") ) { maxmob = Integer.valueOf ( e.getAttribute("maxspell") ).intValue(); } } catch ( NumberFormatException nfe ) { ; //retain default value } if ( e.hasAttribute("author") ) author = e.getAttribute("author"); if ( e.hasAttribute("version") ) version = e.getAttribute("version"); if ( e.hasAttribute("parserVersion") ) parserVersion = e.getAttribute("parserVersion"); if ( e.hasAttribute("date") ) date = e.getAttribute("date"); if ( e.hasAttribute("type") ) type = e.getAttribute("type"); //visual client configuration org.w3c.dom.NodeList confNodes = e.getElementsByTagName("VisualConfiguration"); if ( confNodes.getLength() > 0 ) { org.w3c.dom.Element confNode = (org.w3c.dom.Element) confNodes.item(0); vc = new VisualConfiguration ( confNode , worldurl.toString() ); if ( io instanceof ColoredSwingClient ) { Debug.println("VISUAL CONFIGURATION SET TO " + vc); ((ColoredSwingClient)io).setVisualConfiguration ( vc ); } } //multimedia files org.w3c.dom.NodeList fileListNodes = e.getElementsByTagName("FileList"); if ( fileListNodes.getLength() > 0 ) { org.w3c.dom.Element fileListNode = (org.w3c.dom.Element) fileListNodes.item(0); org.w3c.dom.NodeList fileNodes = fileListNode.getElementsByTagName("File"); fileList = new ArrayList(); for ( int i = 0 ; i < fileNodes.getLength() ; i++ ) { if ( ((org.w3c.dom.Element)fileNodes.item(i)).hasAttribute("path") ) { fileList.add ( getWorldDir() + ((org.w3c.dom.Element)fileNodes.item(i)).getAttribute("path") ); } } } //player list //guardaremos las ID's de los jugadores, especificadas como //<PlayerList> <Player id="20000034"> <Player id="20000035"> ... </PlayerList> //en una lista temporal, playerIDs, para luego al cargar los Mobile //saber que �sos son Players. //Modificaci�n: 05.07.25 Player ID's pueden ser Strings. List playerIDs = new ArrayList(); org.w3c.dom.NodeList plNodes = e.getElementsByTagName ( "PlayerList" ); if ( plNodes.getLength() > 0 ) { org.w3c.dom.Element plNode = (org.w3c.dom.Element) plNodes.item(0); org.w3c.dom.NodeList plidnodes = plNode.getElementsByTagName ( "Player" ); for ( int i = 0 ; i < plidnodes.getLength() ; i++ ) { org.w3c.dom.Element playerIDNode = (org.w3c.dom.Element) plidnodes.item(i); if ( playerIDNode.hasAttribute("id") ) { /* int idnumber = Integer.valueOf ( playerIDNode.getAttribute("id") ).intValue(); if ( idnumber > 0 ) playerIDs.add ( new Integer ( idnumber ) ); */ playerIDs.add(playerIDNode.getAttribute("id")); } } } //world (intro) code org.w3c.dom.NodeList codeNodes = e.getElementsByTagName ( "Code" ); if ( codeNodes.getLength() > 0 ) { for ( int i = 0 ; i < codeNodes.getLength() ; i++ ) { Element codeNode = (Element) codeNodes.item(i); if ( codeNode.getParentNode() instanceof Element && ((Element)codeNode.getParentNode()).getTagName().equals("World") ) { try { itsCode = new ObjectCode ( this , codeNode ); } catch ( XMLtoWorldException ex ) { throw ( new XMLtoWorldException ( "Exception at Code node: " + ex.getMessage() ) ); } break; } } } write( io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.language") + "\n" + io.getColorCode("reset") ); //language configuration if ( e.hasAttribute("language") ) languageCode = e.getAttribute("language"); //messages = Messages.getDefaultInstance(languageCode); lenguaje = NaturalLanguage.getInstance(languageCode); messages = Messages.getDefaultInstance(this); //language code taken from lenguaje Thread.currentThread().yield(); //obtener player templates si las hay org.w3c.dom.NodeList playerGenerationNodes = e.getElementsByTagName ( "PlayerGeneration" ); if ( playerGenerationNodes.getLength() > 0 ) { org.w3c.dom.Element playerGenerationNode = (org.w3c.dom.Element) playerGenerationNodes.item(0); org.w3c.dom.NodeList templateNodes = playerGenerationNode.getElementsByTagName ( "Template" ); for ( int i = 0 ; i < templateNodes.getLength() ; i++ ) { org.w3c.dom.Element templateElement = (org.w3c.dom.Element) templateNodes.item(i); //begin: memory optimisation, remove references to the Document templateElement = (Element)getDetachedCopy(templateElement); //end: memory optimisation playerTemplateNodes.add ( templateElement ); if ( templateElement.hasAttribute("name") ) playerTemplateNodesByName.put(templateElement.getAttribute("name"),templateElement); } //i planned to put a Code node here (player generation code). //At the mom't, just suppose there may be a Player generatePlayer ( IOClient io ) //at general world's code node. } //obtener listas con los nodos de las diferentes Rooms, Mobs e Items NodeList roomLists = e.getElementsByTagName("Rooms"); NodeList itemLists = e.getElementsByTagName("Items"); NodeList mobileLists = e.getElementsByTagName("Mobiles"); NodeList absentLists = e.getElementsByTagName("AbstractEntities"); NodeList spellLists = e.getElementsByTagName("Spells"); Element roomListElement , itemListElement , mobileListElement , absentListElement , spellListElement; if ( roomLists.getLength() > 0 ) roomListElement = (Element) roomLists.item(0); else roomListElement = null; if ( itemLists.getLength() > 0 ) itemListElement = (Element) itemLists.item(0); else itemListElement = null; if ( mobileLists.getLength() > 0 ) mobileListElement = (Element) mobileLists.item(0); else mobileListElement = null; if ( absentLists.getLength() > 0 ) absentListElement = (Element) absentLists.item(0); else absentListElement = null; if ( spellLists.getLength() > 0 ) spellListElement = (Element) spellLists.item(0); else spellListElement = null; //{room/item/mobileListElement tienen el Element con la lista de rooms/items/mobs o null si no hay} NodeList roomNodes = roomListElement!=null ? roomListElement.getElementsByTagName("Room") : null; NodeList itemNodes = itemListElement!=null ? itemListElement.getElementsByTagName("Item") : null; NodeList mobileNodes = mobileListElement!=null ? mobileListElement.getElementsByTagName("Mobile") : null; NodeList absentNodes = absentListElement!=null ? absentListElement.getElementsByTagName("AbstractEntity") : null; NodeList spellNodes = spellListElement!=null ? spellListElement.getElementsByTagName("Spell") : null; if ( roomNodes != null && roomNodes.getLength() != maxroom ) write("Warning: " + roomNodes.getLength() + " room nodes while maxroom is " + maxroom); if ( itemNodes != null && itemNodes.getLength() != maxitem ) write("Warning: " + itemNodes.getLength() + " item nodes while maxitem is " + maxitem); if ( mobileNodes != null && mobileNodes.getLength() != maxmob ) write("Warning: " + mobileNodes.getLength() + " mobile nodes while maxmob is " + maxmob); if ( absentNodes != null && absentNodes.getLength() != maxabsent ) write("Warning: " + absentNodes.getLength() + " abstract entity nodes while maxabsent is " + maxabsent); if ( spellNodes != null && spellNodes.getLength() != maxspell ) write("Warning: " + spellNodes.getLength() + " spell nodes while maxspell is " + maxspell); //init roomNode, itemNode, mobNode parallel arrays if ( roomNodes != null ) { roomNode = new Element[roomNodes.getLength()]; for ( int i = 0 ; i < roomNodes.getLength() ; i++ ) roomNode[i] = (Element) roomNodes.item(i); } else { roomNode = new Element[0]; } if ( itemNodes != null ) { itemNode = new Element[itemNodes.getLength()]; for ( int i = 0 ; i < itemNodes.getLength() ; i++ ) itemNode[i] = (Element) itemNodes.item(i); } else { itemNode = new Element[0]; } if ( mobileNodes != null ) { mobNode = new Element[mobileNodes.getLength()]; for ( int i = 0 ; i < mobileNodes.getLength() ; i++ ) mobNode[i] = (Element) mobileNodes.item(i); } else { mobNode = new Element[0]; } if ( absentNodes != null ) { absentNode = new Element[absentNodes.getLength()]; for ( int i = 0 ; i < absentNodes.getLength() ; i++ ) absentNode[i] = (Element) absentNodes.item(i); } else { absentNode = new Element[0]; } if ( spellNodes != null ) { spellNode = new Element[spellNodes.getLength()]; for ( int i = 0 ; i < spellNodes.getLength() ; i++ ) spellNode[i] = (Element) spellNodes.item(i); } else { spellNode = new Element[0]; } //create nametable and init roomNode, itemNode, mobNode parallel arrays write( io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.nametable") + "\n" + io.getColorCode("reset") ); int nameTableSize = maxroom + maxitem + maxmob + maxabsent + maxspell; nameTable = new Hashtable ( nameTableSize > 100 ? nameTableSize : 100 ); int nentries = 0; //add rooms to nametable for ( int i = 0 ; i < roomNode.length ; i++ ) { Element elt = roomNode[i]; //elemento de esta habitaci�n //coger id y name //if ( !elt.hasAttribute("id") || !elt.hasAttribute("name") ) //as of 03.09.15, ID no longer required: if ( !elt.hasAttribute("name") ) throw ( new XMLtoWorldException ( "Room " + i + " without id or name attr" ) ); try { if ( elt.hasAttribute("id") ) nameTable.put ( elt.getAttribute("name") , Integer.valueOf ( elt.getAttribute("id") ) ); else nameTable.put ( elt.getAttribute("name") , new Integer ( i + Utility.room_summand ) ); } catch ( NumberFormatException nfe ) { throw ( new XMLtoWorldException("id attribute not number") ); } nentries++; } //add items to nametable for ( int i = 0 ; i < itemNode.length ; i++ ) { Element elt = itemNode[i]; //elemento de esta habitaci�n //coger id y name if ( !elt.hasAttribute("name") ) throw ( new XMLtoWorldException ( "Item " + i + " without name attr" ) ); try { if ( elt.hasAttribute("id") ) nameTable.put ( elt.getAttribute("name") , Integer.valueOf ( elt.getAttribute("id") ) ); else nameTable.put ( elt.getAttribute("name") , new Integer ( i + Utility.item_summand ) ); } catch ( NumberFormatException nfe ) { throw ( new XMLtoWorldException("id attribute not number") ); } nentries++; } //add mobiles to nametable for ( int i = 0 ; i < mobNode.length ; i++ ) { Element elt = mobNode[i]; //elemento de esta habitaci�n //coger id y name if ( !elt.hasAttribute("name") ) throw ( new XMLtoWorldException ( "Mobile " + i + " without name attr" ) ); try { if ( elt.hasAttribute("id") ) nameTable.put ( elt.getAttribute("name") , Integer.valueOf ( elt.getAttribute("id") ) ); else nameTable.put ( elt.getAttribute("name") , new Integer ( i + Utility.mobile_summand ) ); } catch ( NumberFormatException nfe ) { throw ( new XMLtoWorldException("id attribute not number") ); } nentries++; } //add abstract entities to nametable for ( int i = 0 ; i < absentNode.length ; i++ ) { Element elt = absentNode[i]; //elemento de esta habitaci�n //coger id y name if ( !elt.hasAttribute("name") ) throw ( new XMLtoWorldException ( "AbstractEntity " + i + " without name attr" ) ); try { if ( elt.hasAttribute("id") ) nameTable.put ( elt.getAttribute("name") , Integer.valueOf ( elt.getAttribute("id") ) ); else nameTable.put ( elt.getAttribute("name") , new Integer ( i + Utility.absent_summand ) ); } catch ( NumberFormatException nfe ) { throw ( new XMLtoWorldException("id attribute not number") ); } nentries++; } //add spells to nametable for ( int i = 0 ; i < spellNode.length ; i++ ) { Element elt = spellNode[i]; //elemento de esta habitaci�n //coger id y name if ( !elt.hasAttribute("name") ) throw ( new XMLtoWorldException ( "Spell " + i + " without name attr" ) ); try { if ( elt.hasAttribute("id") ) nameTable.put ( elt.getAttribute("name") , Integer.valueOf ( elt.getAttribute("id") ) ); else nameTable.put ( elt.getAttribute("name") , new Integer ( i + Utility.spell_summand ) ); } catch ( NumberFormatException nfe ) { throw ( new XMLtoWorldException("id attribute not number") ); } nentries++; } //abstract entities actual load write( io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.abstract") + "\n" + io.getColorCode("reset") ); absent = new AbstractEntity[absentNode.length]; for ( int i = 0 ; i < absentNode.length ; i++ ) { //write(io.getColorCode("information")+"."+io.getColorCode("reset")); absent[i] = AbstractEntity.getInstance ( this , absentNode[i] ); if ( absent[i].getID() % 10000000 == 0 ) { absent[i].setID(i+Utility.absent_summand); } } //spells actual load write( io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.spell") + "\n" + io.getColorCode("reset") ); spell = new Spell[spellNode.length]; for ( int i = 0 ; i < spellNode.length ; i++ ) { //write(io.getColorCode("information")+"."+io.getColorCode("reset")); spell[i] = Spell.getInstance ( this , spellNode[i] ); if ( spell[i].getID() % 10000000 == 0 ) { spell[i].setID(i+Utility.spell_summand); } } //items actual load write( io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.item") + "\n" + io.getColorCode("reset") ); item = new Item[itemNode.length]; for ( int i = 0 ; i < itemNode.length ; i++ ) { //write(io.getColorCode("information")+"."+io.getColorCode("reset")); item[i] = Item.getInstance ( this , itemNode[i] ); if ( item[i].getID() % 10000000 == 0 ) { item[i].setID(i+Utility.item_summand); Debug.println("&ID SET" + item[i].getID()); } } //mobiles actual load write( io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.mob") + "\n" + io.getColorCode("reset") ); mob = new Mobile[mobNode.length]; for ( int i = 0 ; i < mobNode.length ; i++ ) { //cambiar para quitar single-player /* Cambiado: Single-player is dead, mon!! if ( i == 0 ) { mob[i] = new Player ( this , io , mobNode[i] ); //esto ya hace el setPlayer Debug.println("Player's been set."); continue; } mob[i] = Mobile.getInstance ( this , mobNode[i] ); */ if ( ( mobNode[i].hasAttribute("id") || mobNode[i].hasAttribute("name") ) && ( playerIDs.contains ( mobNode[i].getAttribute("id") ) || playerIDs.contains ( mobNode[i].getAttribute("name") ) //|| playerIDs.contains ( String.valueOf ( i+Utility.mobile_summand ) ) ) ) { //that Mobile is actually a Player //if there are no player-template-nodes defined, the first player node //acts as a player-template. //and we call the assignPlayer method if it exists to assign a player to the client. //if ( playerTemplateNodes.size() == 0 ) { Element templateElement = (Element) getDetachedCopy(mobNode[i]); playerTemplateNodes.add ( templateElement ); if ( templateElement.hasAttribute("name") ) playerTemplateNodesByName.put(templateElement.getAttribute("name"),templateElement); } if ( !noSerCliente && !jugadorAsignadoACliente ) { ReturnValue retval = new ReturnValue(null); boolean endfound = runAssignPlayerCode(retval,io); if ( retval.getRetVal() != null && !endfound ) { jugadorAsignadoACliente = true; //addPlayer ( (Player)retval.getRetVal() ); mob[i] = ( (Player)retval.getRetVal() ); //if assignPlayer is defined, it doesn't make much sense to define several Players. //mob[i].setRoom(this.getRoom(1)); //TODO change this playersToAdd.add(mob[i]); //We disable the mobile so that it doesn't get an update before it has really been added to the world (room assigned, etc.) //State will be set to IDLE on adding. mob[i].setNewState(Mobile.DISABLED,1); } //player is only assigned directly if assignPlayer() method not defined or returns null. else { mob[i] = new Player ( this , io , mobNode[i] ); //maybe check for client disconnection if player closes client during assignPlayer? addPlayer ( (Player) mob[i] ); jugadorAsignadoACliente = true; } } else { //no somos cliente, servidor dedicado. mob[i] = new Player ( this , io , mobNode[i] ); ((Player)mob[i]).setPlayerName("Player Template"); //we create the mob so it's not null, but we don't do addPlayer. } } else { mob[i] = Mobile.getInstance ( this , mobNode[i] ); } if ( mob[i].getID() % 10000000 == 0 ) { mob[i].setID(i+Utility.mobile_summand); } } //rooms actual load write( io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.room") + "\n" + io.getColorCode("reset") ); room = new Room[roomNode.length]; for ( int i = 0 ; i < roomNode.length ; i++ ) { room[i] = new Room ( this , roomNode[i] ); if ( room[i].getID() % 10000000 == 0 ) { room[i].setID(i+Utility.room_summand); } } //write( io.getColorCode("information") + ( maxroom + maxitem + maxmob + maxspell + maxabsent ) + " entidades cargadas.\n" + io.getColorCode("reset")); write( io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.stats","$number",String.valueOf( maxroom + maxitem + maxmob + maxspell + maxabsent )) + "\n" + io.getColorCode("reset")); //cargas diferidas write( io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.deferred") + "\n" + io.getColorCode("reset") + "\n" ); for ( int i = 0 ; i < maxitem ; i++ ) { item[i].loadInventoryFromXML(this); item[i].readRelationshipListFromXML ( this , itemNode[i] ); } for ( int i = 0 ; i < maxmob ; i++ ) { mob[i].readRelationshipListFromXML ( this , mobNode[i] ); } for ( int i = 0 ; i < maxroom ; i++ ) { room[i].readRelationshipListFromXML ( this , roomNode[i] ); } for ( int i = 0 ; i < maxabsent ; i++ ) { absent[i].readRelationshipListFromXML ( this , absentNode[i] ); } for ( int i = 0 ; i < maxspell ; i++ ) { spell[i].readRelationshipListFromXML ( this , spellNode[i] ); } write( io.getColorCode("information") + "\n" + UIMessages.getInstance().getMessage("load.world.done") + io.getColorCode("reset") + "\n" ); write("\n=== === === === === === === === === === === === === === === ==="); write("\n" + io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.info.intro")); if ( modulename != null ) write("\n" + io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.info.name") + modulename + io.getColorCode("reset")); //write("\n" + io.getColorCode("information") + "[Nombre] " + modulename + io.getColorCode("reset")); if ( type != null ) write("\n" + io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.info.type") + type + io.getColorCode("reset")); //write("\n" + io.getColorCode("information") + "[Tipo] " + type + io.getColorCode("reset")); if ( author != null ) write("\n" + io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.info.author") + author + io.getColorCode("reset")); //write("\n" + io.getColorCode("information") + "[Autor] " + author + io.getColorCode("reset")); if ( version != null ) write("\n" + io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.info.version") + version + io.getColorCode("reset")); //write("\n" + io.getColorCode("information") + "[Versi�n] " + version + io.getColorCode("reset")); if ( date != null ) write("\n" + io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.info.date") + date + io.getColorCode("reset")); //write("\n" + io.getColorCode("information") + "[Fecha] " + date + io.getColorCode("reset")); if ( parserVersion != null ) write("\n" + io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.info.required") + parserVersion + io.getColorCode("reset")); //write("\n" + io.getColorCode("information") + "[Versi�n engine] " + parserVersion + io.getColorCode("reset")); write("\n=== === === === === === === === === === === === === === === ===\n\n"); //warnVersionIfNeeded(null); //set legacy command matching mode if needed: versions in [0,1.0) if ( new VersionComparator().compare(parserVersion,"1.0") < 0 ) this.setCommandMatchingMode(Entity.LEGACY_COMMAND_MATCHING); //set lenient command matching mode if needed: versions in [1.0,1.1.1) if ( new VersionComparator().compare(parserVersion,"1.0") >= 0 && new VersionComparator().compare(parserVersion,"1.1.1") < 0 ) this.setCommandMatchingMode(Entity.LENIENT_COMMAND_MATCHING); if ( !jugadorAsignadoACliente && !noSerCliente ) { //Debug.println("Gonna add player ASAP."); //return world inmediately, do not block Thread th = new Thread() { public void run() { try { Debug.println("Add player wait."); synchronized(serverIntroSyncObject) { while ( !serverIntroExeccedFlag ) { try { serverIntroSyncObject.wait(); } catch ( Exception e ) { e.printStackTrace(); } } } Debug.println("Adding player."); addNewPlayerASAP(io); } catch (XMLtoWorldException xml2we) { io.write("XML to World Exception when assigning player.\n"); xml2we.printStackTrace(); } } }; th.start(); //addNewPlayerASAP ( io ); } //remove nodes for memory, we are not going to need them more itemNode = null; mobNode = null; roomNode = null; absentNode = null; spellNode = null; } /** * @deprecated This used DAT files. Use XML files instead. * @param modulefile * @param io * @param noSerCliente * @throws FileNotFoundException * @throws IOException */ void legacyWorldLoad ( String modulefile , InputOutputClient io , boolean noSerCliente ) throws FileNotFoundException , IOException { //DAT support (ancient!) follows: this.io = io; //si readLine lee null, se acab� el fichero. FileInputStream fp = new FileInputStream(modulefile); java.io.BufferedReader filein = new java.io.BufferedReader ( Utility.getBestInputStreamReader (fp )); String linea=""; String token=""; String zipFile = ""; write( io.getColorCode("information") + "\nCARGA DEL MUNDO EN LA M�QUINA DE ESTADOS DE AETHERIA\n" + io.getColorCode("reset") ); write( io.getColorCode("information") + "\nObteniendo informaci�n de mundo...\n" + io.getColorCode("reset") ); Thread.currentThread().yield(); while( true ) { linea=filein.readLine(); if ( linea == null ) break; token = StringMethods.getTok( linea,1,' ' ); if ( token.equalsIgnoreCase("module") ) worldname=StringMethods.getTok( linea,2,' ' ); else if ( token.equalsIgnoreCase("maxroom") ) maxroom = (Integer.valueOf( StringMethods.getTok( linea,2,' ' )).intValue() ); else if ( token.equalsIgnoreCase("maxitem") ) maxitem = (Integer.valueOf( StringMethods.getTok( linea,2,' ' )).intValue() ); else if ( token.equalsIgnoreCase("maxmob") ) maxmob = (Integer.valueOf( StringMethods.getTok( linea,2,' ' )).intValue() ); else if ( token.equalsIgnoreCase("printthis") ) write(StringMethods.getToks(linea,2,StringMethods.numToks(linea,' '),' ')+"\n"); else if ( token.equalsIgnoreCase("modulename" ) ) modulename=StringMethods.getToks ( linea , 2 , StringMethods.numToks ( linea , ' ' ) , ' ' ); else if ( token.equalsIgnoreCase("author") ) author = StringMethods.getToks(linea,2,StringMethods.numToks(linea,' '),' '); else if ( token.equalsIgnoreCase("version") ) version = StringMethods.getToks(linea,2,StringMethods.numToks(linea,' '),' '); else if ( token.equalsIgnoreCase("date") ) date = StringMethods.getToks(linea,2,StringMethods.numToks(linea,' '),' '); else if ( token.equalsIgnoreCase("parserversion") ) parserVersion = StringMethods.getToks(linea,2,StringMethods.numToks(linea,' '),' '); else if ( token.equalsIgnoreCase("zipfile") ) zipFile = StringMethods.getToks(linea,2,StringMethods.numToks(linea,' '),' '); else if ( token.equalsIgnoreCase("begin_eva_code") ) { //begin EVA code line { String EVACodeString = ""; boolean terminamos = false; while ( !terminamos ) { linea = filein.readLine(); String id_linea = StringMethods.getTok(linea,1,' '); if ( id_linea.equalsIgnoreCase("end_eva_code") ) terminamos=true; //EVA code termination line else { EVACodeString += "\n"; EVACodeString += linea; } } //Debug.println("EVA CODE STRING"); //Debug.println(EVACodeString); itsCode = new ObjectCode ( EVACodeString , "EVA" , this ); } //end EVA code reading } else if ( token.equalsIgnoreCase("begin_bsh_code") ) { //begin EVA code line { String BSHCodeString = ""; boolean terminamos = false; while ( !terminamos ) { linea = filein.readLine(); String id_linea = StringMethods.getTok(linea,1,' '); if ( id_linea.equalsIgnoreCase("end_bsh_code") ) terminamos=true; //EVA code termination line else { BSHCodeString += "\n"; BSHCodeString += linea; } } //Debug.println("EVA CODE STRING"); //Debug.println(EVACodeString); itsCode = new ObjectCode ( BSHCodeString , "BeanShell" , this ); } //end EVA code reading } } // worlddir = Aetheria.maindir + worldname + "/"; //debug info remove //escribir("\nMundo: " + modulename ); //escribir("\nDirectorio: " + worlddir ); //escribir("\nHabitaciones [max]: " + maxroom ); //escribir("\nBichos [max]: " + maxmob ); //escribir("\nObjetos [max]: " + maxitem ); //debug info remove write( io.getColorCode("information") + "\nCargando datos ling��sticos..." + io.getColorCode("reset") ); lenguaje = NaturalLanguage.getInstance(); messages = Messages.getDefaultInstance(languageCode); Thread.currentThread().yield(); //if ( zipFile.equalsIgnoreCase("") ) //{ write(io.getColorCode("information") + "\nCreando tabla de nombres...\n" + io.getColorCode("reset") ); //create nametable int nameTableSize = maxroom + maxitem + maxmob; nameTable = new Hashtable ( nameTableSize > 100 ? nameTableSize : 100 ); int nentries = 0; try { for (int i = 0;i<maxitem;i++) { BufferedReader br = new BufferedReader ( Utility.getBestInputStreamReader ( new FileInputStream ( Utility.itemFile(this,i) ) ) ); //Debug.println("File readin': " + Utility.itemFile(this,i) ); linea = ""; int idnumber = i; for ( int line = 1 ; line < 100 /*&& linea != null*/ ; line++ ) { linea = br.readLine(); //Debug.println(linea); String id_linea = StringMethods.getTok( linea , 1 , ' ' ); linea = StringMethods.getToks( linea , 2 , StringMethods.numToks( linea , ' ' ) , ' ' ); if ( id_linea != null ) { //Debug.println("line"); int nlinea = 0; try { nlinea = Integer.valueOf ( id_linea ).intValue(); } catch ( NumberFormatException nfe ) { ; //despues } //Debug.print(nlinea); if ( nlinea == 1 ) idnumber = Integer.valueOf(linea).intValue(); if ( nlinea == 4 ) { nameTable.put ( linea , new Integer ( Utility.completeItemID ( idnumber ) ) ); //name-number pair nentries++; } } } } } catch ( FileNotFoundException fnfe ) { //escribir("Entries: " + nentries); ; } try { for (int i = 0;i<maxroom;i++) { BufferedReader br = new BufferedReader ( Utility.getBestInputStreamReader ( new FileInputStream ( Utility.roomFile(this,i) ) ) ); //Debug.println("File readin': " + Utility.itemFile(this,i) ); linea = ""; int idnumber = i; for ( int line = 1 ; line < 100 /*&& linea != null*/ ; line++ ) { linea = br.readLine(); //Debug.println(linea); String id_linea = StringMethods.getTok( linea , 1 , ' ' ); linea = StringMethods.getToks( linea , 2 , StringMethods.numToks( linea , ' ' ) , ' ' ); if ( id_linea != null ) { //Debug.println("line"); int nlinea = 0; try { nlinea = Integer.valueOf ( id_linea ).intValue(); } catch ( NumberFormatException nfe ) { ; //despues } //Debug.print(nlinea); if ( nlinea == 1 ) idnumber = Integer.valueOf(linea).intValue(); if ( nlinea == 4 ) { nameTable.put ( linea , new Integer ( Utility.completeRoomID ( idnumber ) ) ); //name-number pair nentries++; } } } } } catch ( FileNotFoundException fnfe ) { //escribir("Entries: " + nentries); ; } try { for (int i = 0;i<maxmob;i++) { BufferedReader br = new BufferedReader ( Utility.getBestInputStreamReader ( new FileInputStream ( Utility.mobFile(this,i) ) ) ); //Debug.println("File readin': " + Utility.itemFile(this,i) ); linea = ""; int idnumber = i; for ( int line = 1 ; line < 100 /*&& linea != null*/ ; line++ ) { linea = br.readLine(); //Debug.println(linea); String id_linea = StringMethods.getTok( linea , 1 , ' ' ); linea = StringMethods.getToks( linea , 2 , StringMethods.numToks( linea , ' ' ) , ' ' ); if ( id_linea != null ) { //Debug.println("line"); int nlinea = 0; try { nlinea = Integer.valueOf ( id_linea ).intValue(); } catch ( NumberFormatException nfe ) { ; //despues } //Debug.print(nlinea); if ( nlinea == 1 ) idnumber = Integer.valueOf(linea).intValue(); if ( nlinea == 4 ) { nameTable.put ( linea , new Integer ( Utility.completeMobileID ( idnumber ) ) ); //name-number pair nentries++; } } } } } catch ( FileNotFoundException fnfe ) { write(io.getColorCode("information") + "Entradas: " + nentries + "\n" + io.getColorCode("reset") ); } write(io.getColorCode("information") + "Inicializando items...\n" + io.getColorCode("reset") ); item = new Item [maxitem] ; int i=0; try { for (;i<maxitem;i++) { //item[i] = new Item(this,Utility.itemFile(this,i)); //Debug.println(Utility.itemFile(this,i)); item[i] = Item.getInstance ( this , Utility.itemFile(this,i) ); } } catch ( FileNotFoundException nomasitems ) { //escribir("\nParamos de cargar objetos en " + i + "\n" ); maxitem = i; } catch ( IOException npi ) { System.err.println("No puedo abrir el objeto " + i ); } write( io.getColorCode("information") + "Inicializando bichos...\n" + io.getColorCode("reset") ); mob = new Mobile [maxmob] ; i=1; /*pues el Mobile numero 0 (00000000.ae) es el jugador*/ try { for (;i<maxmob;i++) { //item[i] = new Item(this,Utility.itemFile(this,i)); mob[i] = Mobile.getInstance ( this , Utility.mobFile(this,i) ); } } catch ( FileNotFoundException nomasmobs ) { //escribir("\nParamos de cargar bichos en " + i + "\n" ); maxmob = i; } catch ( IOException npi ) { System.err.println("No puedo abrir el bicho " + i ); } write( io.getColorCode("information") + "Inicializando habitaciones...\n" + io.getColorCode("reset") ); room = new Room [maxroom] ; i=0; try { for (;i<maxroom;i++) { room[i] = new Room(this, Utility.roomFile(this,i)); } } catch ( FileNotFoundException nomashabitaciones ) { //escribir("\nParamos de cargar habitaciones en " + i + "\n" ); maxroom = i; } catch ( IOException npi ) { System.err.println("No puedo abrir la habitaci�n " + i ); } write( io.getColorCode("information") + ( maxroom + maxitem + maxmob ) + " entidades cargadas.\n" ); write( io.getColorCode("information") + "Completando cargas diferidas..." + io.getColorCode("reset") ); for ( i = 1 ; i < maxitem ; i++ ) { item[i].loadInventory(this); } //} //else //warning: this "else" branch is not implemented. Should not use zipfiles at the moment!!! //{ /* worlddir = ""; escribir(io.getColorCode("information") + "\nInicializando items...\n" + io.getColorCode("reset") ); item = new Item [maxitem] ; int i=0; try { for (;i<maxitem;i++) { //item[i] = new Item(this,Utility.itemFile(this,i)); //Debug.println(Utility.itemFile(this,i)); item[i] = Item.getInstance ( this , Utility.itemFile(this,i) ); } } catch ( FileNotFoundException nomasitems ) { //escribir("\nParamos de cargar objetos en " + i + "\n" ); maxitem = i; } catch ( IOException npi ) { Debug.println("No puedo abrir el objeto " + i ); } escribir( io.getColorCode("information") + "Inicializando bichos...\n" + io.getColorCode("reset") ); mob = new Mobile [maxmob] ; i=1; //pues el Mobile numero 0 (00000000.ae) es el jugador try { for (;i<maxmob;i++) { //item[i] = new Item(this,Utility.itemFile(this,i)); mob[i] = Mobile.getInstance ( this , Utility.mobFile(this,i) ); } } catch ( FileNotFoundException nomasmobs ) { //escribir("\nParamos de cargar bichos en " + i + "\n" ); maxmob = i; } catch ( IOException npi ) { Debug.println("No puedo abrir el bicho " + i ); } escribir( io.getColorCode("information") + "Inicializando habitaciones...\n" + io.getColorCode("reset") ); room = new Room [maxroom] ; i=0; try { for (;i<maxroom;i++) { room[i] = new Room(this, Utility.roomFile(this,i)); } } catch ( FileNotFoundException nomashabitaciones ) { //escribir("\nParamos de cargar habitaciones en " + i + "\n" ); maxroom = i; } catch ( IOException npi ) { Debug.println("No puedo abrir la habitaci�n " + i ); } escribir( io.getColorCode("information") + ( maxroom + maxitem + maxmob ) + " entidades cargadas.\n" ); escribir( io.getColorCode("information") + "Completando cargas diferidas..." + io.getColorCode("reset") ); for ( i = 1 ; i < maxitem ; i++ ) { item[i].loadInventory(this); } */ //} write( io.getColorCode("information") + "\nMundo inicializado." + io.getColorCode("reset") + "\n" ); write("\n=== === === === === === === === === === === === === === === ==="); write("\n" + io.getColorCode("information") + "Informaci�n de Juego:"); if ( modulename != null ) write("\n" + io.getColorCode("information") + "[Nombre] " + modulename + io.getColorCode("reset")); if ( type != null ) write("\n" + io.getColorCode("information") + "[Tipo] " + type + io.getColorCode("reset")); if ( author != null ) write("\n" + io.getColorCode("information") + "[Autor] " + author + io.getColorCode("reset")); if ( version != null ) write("\n" + io.getColorCode("information") + "[Versi�n] " + version + io.getColorCode("reset")); if ( date != null ) write("\n" + io.getColorCode("information") + "[Fecha] " + date + io.getColorCode("reset")); if ( parserVersion != null ) write("\n" + io.getColorCode("information") + "[Versi�n engine] " + parserVersion + io.getColorCode("reset")); write("\n=== === === === === === === === === === === === === === === ===\n"); } /** * Obtains an XML DOM document from an input stream. * Changed the way of obtaining it on 2012-09-08, as the old form (DocumentBuilder:parse(InputStream)) seemed to cause problems * with XML includes. * @param is * @return * @throws TransformerException */ public org.w3c.dom.Document getXMLFromStream ( InputStream is , URI systemId ) throws TransformerException { Transformer t = TransformerFactory.newInstance().newTransformer(); Source s = new StreamSource(is,systemId.toString()); DOMResult r = new DOMResult(); t.transform(s,r); return (org.w3c.dom.Document)r.getNode(); } /** * Toma la informaci�n del mundo del stream dado. * @param is Stream de donde se leen los datos XML del mundo, que puede ser un stream obtenido de un fichero local de mundo, de una URL, etc. * @param systemId Provides the relative path for URLs in XML. * @param io * @param noSerCliente * @throws ParserConfigurationException * @throws IOException * @throws SAXException * @throws XMLtoWorldException */ public void loadWorldFromStream ( InputStream is , URI systemId , InputOutputClient io , boolean noSerCliente ) throws ParserConfigurationException, SAXException, IOException, TransformerException, XMLtoWorldException { org.w3c.dom.Document d = null; //DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); io.write(io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.tree") + "\n" + io.getColorCode("reset") ); //d = db.parse( is ); d = getXMLFromStream( is , systemId ); org.w3c.dom.Element n = d.getDocumentElement(); loadWorldFromXML ( n , io , noSerCliente ); } public World ( URL url , InputOutputClient io , boolean noSerCliente ) throws IOException { InputStream is = null; if ( /*url.toString().toLowerCase().endsWith(".xml")*/ !url.toString().toLowerCase().endsWith(".agz") && !url.toString().toLowerCase().endsWith(".zip") ) { if ( !url.toString().startsWith("jar:") && !url.toString().startsWith("zip:") ) { worlddir = url.toString().substring(0,url.toString().lastIndexOf("/")+1); worldurl = new URL(worlddir); } else { //worlddir = url.toString().substring(url.toString().indexOf("!")+1); //worlddir = worlddir.toString().substring(0,worlddir.toString().lastIndexOf("/")+1); worlddir = url.toString().substring(0,url.toString().lastIndexOf("/")+1); worldurl = new URL(worlddir); } is = url.openStream(); } else { //we assume jar file url //worlddir = "jar:"+url+"!/"; //worlddir = ""; //getResource will work //TODO doesn't work //seems to work now (2013.01.04 - r638). Maybe I wasn't doing it right. worlddir = "jar:"+url.toString()+"!/"; worldurl = new URL(worlddir); //URLClassLoader ucl = new URLClassLoader ( new URL[] { url } , this.getClass().getClassLoader() ); is = getResourceAsStream("world.xml"); //is = ucl.getResourceAsStream("world.xml"); if ( is == null ) is = getResourceAsStream("world.agw"); if ( is == null ) throw new IOException("Could not find resource named world.xml or world.agz in zipped URL " + url); //this.setResourceJarFile(url); } try { loadWorldFromStream ( is , url.toURI() , io , noSerCliente ); } catch ( ParserConfigurationException pce ) { pce.printStackTrace(); throw new IOException(pce); } catch ( TransformerException te ) { te.printStackTrace(); throw new IOException(te); } catch ( SAXException se ) //parse() { se.printStackTrace(); throw new IOException(se); } catch ( IOException ioe ) //parse() { throw (ioe); } catch ( XMLtoWorldException x2we ) { write( UIMessages.getInstance().getMessage("load.world.xml.exception") + " " + x2we.getMessage() ); //throw ( new IOException ( "Excepci�n al leer mundo de XML: " + x2we.getMessage() ) ); } catch (URISyntaxException use) { use.printStackTrace(); } } /** * Toma la informaci�n sobre el mundo del fichero de m�dulo. * * @param modulefile El fichero del que toma la informaci�n para crear el mundo. */ public World ( String modulefile , InputOutputClient io , boolean noSerCliente ) throws FileNotFoundException,IOException { //XML world init worlddir = new File(new File(modulefile).getParent()).getPath() + File.separatorChar; worldurl = new File(modulefile).getParentFile().toURI().toURL(); /* System.err.println("Mod " + new File(modulefile)); System.err.println("Par " + new File(modulefile).getParentFile()); System.err.println("Uri " + new File(modulefile).getParentFile().toURI()); System.err.println("Url " + new File(modulefile).getParentFile().toURI().toURL()); */ io.write( io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.xml") + "\n" + io.getColorCode("reset") ); try { //br = new BufferedReader ( new InputStreamReader ( new FileInputStream ( new File ( modulefile ) ) , "ISO-8859-1" ) ); //InputSource is = new InputSource(br); //InputSource is = new InputSource( new FileInputStream( new File ( modulefile ) ) ); File f = new File ( modulefile ); InputStream is = new FileInputStream ( f ); loadWorldFromStream ( is , f.toURI() , io , noSerCliente ); } catch ( FileNotFoundException fnfe ) { throw ( fnfe ); } catch ( ParserConfigurationException pce ) { pce.printStackTrace(); throw new IOException(pce); } catch ( TransformerException te ) { te.printStackTrace(); throw new IOException(te); } catch ( SAXException se ) //parse() { se.printStackTrace(); throw new IOException(se); } catch ( IOException ioe ) //parse() { throw (ioe); } catch ( XMLtoWorldException x2we ) { write( UIMessages.getInstance().getMessage("load.world.xml.exception") + " " + x2we.getMessage() ); //throw ( new IOException ( "Excepci�n al leer mundo de XML: " + x2we.getMessage() ) ); } } /* Nay. Multiplayer! public void setPlayer ( Player p ) { player = p; //remove this, multiple players should be allowed later. mob[0] = p; } */ /** * Devuelve el directorio del mundo. Full pathname. * */ public String getWorldPath( ) { return worlddir; } /*Devuelve el directorio del mundo. S�lo nombre+separador.*/ public String getWorldDir( ) { return new File(worlddir).getName() + File.separatorChar; } public int getMaxRoom ( ) { return maxroom; } public int getMaxItem ( ) { return maxitem; } public int getMaxMob ( ) { return maxmob; } public int getMaxAbstractEntity ( ) { return maxabsent; } public int getMaxSpell ( ) { return maxspell; } /** * Devuelve la habitaci�n del mundo con la ID dada. * * @param roomid la ID de habitaci�n. */ public Room getRoom ( int roomid ) { if ( roomid % 10000000 >= room.length ) return null; return room [roomid % 10000000 ]; //siete ult dig } public List getRooms() { List rooms = new ArrayList(); for ( int i = 0 ; i < maxroom ; i++ ) { rooms.add ( getRoom(i) ); } return rooms; } public Room getRoom ( String ident ) { try { return getRoom ( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer)nameTable.get(ident); if ( i == null ) return null; Room theRoom = getRoom ( i.intValue() ); //the following check is needed in case someone uses getRoom() by mistake with the unique name of another entity (like a Mobile). //In this case, the low-level getRoom() would return the room with the same relative ID as the requested Mobile. //Also, if the Room is not initialized yet, theRoom will be null here. if ( theRoom != null && theRoom.getUniqueName().equals(ident) ) return theRoom; else return null; } } //para el constructor del Path public int roomNameToID ( String roomName ) { Integer i = (Integer)nameTable.get(roomName); if ( i != null ) { return i.intValue(); } else return -1; } /** * Obtain an Entity in the world from its numerical ID. * @param id * @return */ public Entity getEntity ( int id ) { if ( id >= Utility.spell_summand ) return getSpell(id); else if ( id >= Utility.absent_summand ) return getAbstractEntity(id); else if ( id >= Utility.item_summand ) return getItem(id); else if ( id >= Utility.mobile_summand ) return getMobile(id); else if ( id >= Utility.room_summand ) return getRoom(id); else return null; } /** * Obtiene una entidad del mundo a partir de su nombre. * @param ident * @return */ public Entity getEntity ( String ident ) { int oid; try { return getEntity ( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer)nameTable.get(ident); if ( i != null ) { return getEntity ( i.intValue() ); } else return null; } } /** * Devuelve el item del mundo con la ID dada. * * @param la ID del item. Podemos ponerla con el prefijo 3 (8 d�gitos) u omiti�ndolo. */ public Item getItem ( int itemid ) { if ( itemid % 10000000 >= item.length ) return null; return item [ itemid % 10000000 ] ; //devuelve solo los siete ultimos digitos, //asi acepta ID's de tipo //30xxxxxx, 31xxxxxx (ID's de objeto generico, arma, etc.) //devolviendo el item de pos 1xxxxxx, 0xxxxxx en array... //o simple numero de item de forma xxxxxxx } public Item getItem ( String ident ) { try { return getItem ( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer)nameTable.get(ident); if ( i == null ) return null; Item theItem = getItem ( i.intValue() ); //the following check is needed in case someone uses getItem() by mistake with the unique name of another entity (like a Mobile). //In this case, the low-level getItem() would return the item with the same relative ID as the requested Mobile. //Also, if the Item is not initialized yet, theItem will be null here. if ( theItem != null && theItem.getUniqueName().equals(ident) ) return theItem; else return null; } } /** * Devuelve el bicho del mundo con la ID dada. * * @param la ID del bicho. Podemos ponerla con el prefijo 4 (8 d�gitos) u omiti�ndolo. */ public Mobile getMob ( int mobid ) { if ( mobid % 10000000 >= mob.length ) return null; return mob [ mobid % 10000000 ] ; //devuelve solo los siete ultimos digitos, //asi acepta ID's de tipo //30xxxxxx, 31xxxxxx (ID's de objeto generico, arma, etc.) //devolviendo el item de pos 1xxxxxx, 0xxxxxx en array... //o simple numero de item de forma xxxxxxx } public Mobile getMobile ( String ident ) { return getMob ( ident ); } public Mobile getMobile ( int id ) { return getMob( id ); } public Mobile getMob ( String ident ) { try { return getMob ( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer)nameTable.get(ident); if ( i == null ) return null; Mobile theMob = getMob ( i.intValue() ); //this check is needed in case someone uses getMob() by mistake with the unique name of another entity (like a Room). //In this case, the low-level getMob() would return the mobile with the same relative ID as the requested Room. //Also, if the Mobile is not initialized yet, theMob will be null here. if ( theMob != null && theMob.getUniqueName().equals(ident) ) return theMob; else return null; } } public EntityList getAllMobiles ( ) { EntityList el = new EntityList(); for ( int i = 0 ; i < maxmob ; i++ ) { if ( mob[i] != null ) //purely defensive check el.addEntity(mob[i]); } return el; } public EntityList getAllItems ( ) { EntityList el = new EntityList(); for ( int i = 0 ; i < maxitem ; i++ ) { if ( item[i] != null ) //purely defensive check el.addEntity(item[i]); } return el; } public EntityList getAllRooms ( ) { EntityList el = new EntityList(); for ( int i = 0 ; i < maxroom ; i++ ) { if ( room[i] != null ) //purely defensive check el.addEntity(room[i]); } return el; } public EntityList getAllSpells ( ) { EntityList el = new EntityList(); for ( int i = 0 ; i < maxspell ; i++ ) { if ( spell[i] != null ) //purely defensive check el.addEntity(spell[i]); } return el; } /** * Devuelve el abstract entity del mundo con la ID dada. * * @param la ID del abstract entity. Podemos ponerla con el prefijo 4 (8 d�gitos) u omiti�ndolo. */ public AbstractEntity getAbstractEntity ( int absentid ) { if ( absentid % Utility.absent_summand >= absent.length ) return null; return absent [ absentid % Utility.absent_summand ] ; //devuelve solo los siete ultimos digitos, //asi acepta ID's de tipo //40xxxxxx, 41xxxxxx (ID's de objeto generico, arma, etc.) //devolviendo el item de pos 1xxxxxx, 0xxxxxx en array... //o simple numero de item de forma xxxxxxx } public AbstractEntity getAbstractEntity ( String ident ) { int oid; try { return getAbstractEntity ( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer)nameTable.get(ident); if ( i == null ) return null; AbstractEntity theAbstractEntity = getAbstractEntity ( i.intValue() ); //the following check is needed in case someone uses getAbstractEntity() by mistake with the unique name of another entity (like a Mobile). //In this case, the low-level getAbstractEntity() would return the abstract entity with the same relative ID as the requested Mobile. //Also, if the AbstractEntity is not initialized yet, theAbstractEntity will be null here. if ( theAbstractEntity != null && theAbstractEntity.getUniqueName().equals(ident) ) return theAbstractEntity; else return null; } } /** * Devuelve el hechizo del mundo con la ID dada. * * @param la ID del abstract entity. Podemos ponerla con el prefijo 4 (8 d�gitos) u omiti�ndolo. */ public Spell getSpell ( int spellid ) { if ( spellid % Utility.spell_summand >= spell.length ) return null; return spell [ spellid % Utility.spell_summand ] ; //devuelve solo los siete ultimos digitos, //asi acepta ID's de tipo //40xxxxxx, 41xxxxxx (ID's de objeto generico, arma, etc.) //devolviendo el item de pos 1xxxxxx, 0xxxxxx en array... //o simple numero de item de forma xxxxxxx } public Spell getSpell ( String ident ) { try { return getSpell ( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer)nameTable.get(ident); if ( i == null ) return null; Spell theSpell = getSpell ( i.intValue() ); //the following check is needed in case someone uses getSpell() by mistake with the unique name of another entity (like a Mobile). //In this case, the low-level getSpell() would return the spell with the same relative ID as the requested Mobile. //Also, if the Spell is not initialized yet, theSpell will be null here. if ( theSpell != null && theSpell.getUniqueName().equals(ident) ) return theSpell; else return null; } } /** * Devuelve al jugador * * */ /* Nay! Multiplayer! public Player getPlayer ( ) { return player; } */ /** * Devuelve el objeto del mundo con la ID dada, ya sea habitaci�n, bicho, hechizo, etc. * * @param la ID del objeto. Evidentemente, ha de venir completa (con sus ocho d�gitos). */ public Entity getObject ( int objectid ) { //HAY QUE CAMBIAR ESTA FUNCI�N PARA SOPORTAR PREFIJOS CONFIGURABLES if ( objectid == 20000000 ) return getMob(objectid); if ( objectid < 20000000 ) return getRoom(objectid); if ( objectid < 30000000 ) return getMob(objectid); if ( objectid < 40000000 ) return getItem(objectid); if ( objectid < 50000000 ) return getAbstractEntity(objectid); if ( objectid < 60000000 ) return getSpell(objectid); return null; } /** * Devuelve el objeto del mundo con el identificador dada, que puede ser la propia ID * del objeto (un entero) dada en forma de string o un string que se convierte a ID * mediante la tabla de nombres. */ public Entity getObject ( String ident ) { int oid; try { return getObject( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer) nameTable.get(ident); if ( i != null ) return getObject ( i.intValue() ); else return null; } } public InputOutputClient getIO() { return io; } public org.w3c.dom.Element getItemNode ( int itemid ) { return itemNode [ itemid % 10000000 ] ; } public org.w3c.dom.Element getMobileNode ( int mobid ) { return mobNode [ mobid % 10000000 ] ; } public org.w3c.dom.Element getRoomNode ( int roomid ) { return roomNode [ roomid % 10000000 ] ; } public org.w3c.dom.Element getAbstractEntityNode ( int absentid ) { return absentNode [ absentid % 10000000 ] ; } public org.w3c.dom.Element getSpellNode ( int spellid ) { return spellNode [ spellid % 10000000 ] ; } public org.w3c.dom.Element getItemNode ( String ident ) { int oid; try { return getItemNode ( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer)nameTable.get(ident); if ( i != null ) return getItemNode ( i.intValue() ); else return null; } } public org.w3c.dom.Element getMobileNode ( String ident ) { int oid; try { return getMobileNode ( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer)nameTable.get(ident); if ( i != null ) return getMobileNode ( i.intValue() ); else return null; } } public org.w3c.dom.Element getRoomNode ( String ident ) { int oid; try { return getRoomNode ( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer)nameTable.get(ident); if ( i != null ) return getRoomNode ( i.intValue() ); else return null; } } public org.w3c.dom.Element getAbstractEntityNode ( String ident ) { int oid; try { return getAbstractEntityNode ( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer)nameTable.get(ident); if ( i != null ) return getAbstractEntityNode ( i.intValue() ); else return null; } } public org.w3c.dom.Element getSpellNode ( String ident ) { int oid; try { return getSpellNode ( Integer.parseInt(ident) ); } catch ( NumberFormatException nfe ) { Integer i = (Integer)nameTable.get(ident); if ( i != null ) return getSpellNode ( i.intValue() ); else return null; } } //de informador /** * @deprecated Use {@link #write(String)} instead */ public void escribir ( String s ) { write(s); } //de informador public void write ( String s ) { io.write(s); } public void setIO ( InputOutputClient es ) { io = es; } /**Devuelve el nombre "bonito" del mundo.*/ public String getModuleName ( ) { return modulename; } /*ejecuta el codigo del mundo correspondiente a la rutina dada si existe. Si no existe, simplemente no ejecuta nada y devuelve false.*/ /**Legacy method, currently unused.*/ public boolean execCode ( String routine , String dataSegment ) throws EVASemanticException { if ( itsCode != null ) return itsCode.run ( routine , dataSegment ); else return false; } /** * Tries to execute the BSH code corresponding to the given scripted routine. * If the routine does not exist, this method returns false. * If the routine does exist, this method executes it and: * - returns true if it finished normally with end(), * - returns false if it finished normally without end(), * - throws a ScriptException if it produced an uncaught exception. * This method does not provide a way of obtaining the return value returned by the scripted routine. */ public boolean execCode ( String routine , Object[] args ) throws ScriptException { if ( itsCode != null ) return itsCode.run ( routine , this , args ); else return false; } /** * Tries to execute the BSH code corresponding to the given scripted routine. * If the routine does not exist, this method returns false. * If the routine does exist, this method executes it and: * - returns true if it finished normally with end(), * - returns false if it finished normally without end(), * - throws a ScriptException if it produced an uncaught exception. * In addition, the return value of the routine (if applicable) is wrapped into the retval parameter. */ public boolean execCode ( String routine , Object[] args , ReturnValue retval ) throws ScriptException { //S/ystem.out.println("Mobile code runnin'."); //Debug.println("Its Code: " + itsCode); if ( itsCode != null ) return itsCode.run ( routine , this , args , retval ); else return false; } /** * @deprecated Use {@link #getLanguage()} instead */ public NaturalLanguage getLang() { return getLanguage(); } public NaturalLanguage getLanguage() { return lenguaje; } /** * Changes the language of this World to the language with the given code. * Note that this includes changing the instance of Messages associated with the world. * @param languageCode */ public void setLanguage ( String languageCode ) { lenguaje = NaturalLanguage.getInstance(languageCode); Messages.clearCache(this); //so that the default instance changes to the default messages for the new language messages = Messages.getDefaultInstance(this); //language code taken from lenguaje spellChecker = null; //will be initted again in the next call to getSpellChecker(). namesForDirections = null; //will be initted again when a direction name gets requested. } public void setRandomNumberSeed ( ) { Debug.println("Setting world's random generator."); semilla = (new java.util.Date()).getTime(); aleat = new java.util.Random( semilla ); Debug.println("Seed set to " + semilla); for ( int i = 0 ; i < maxroom ; i++ ) { room[i].loadNumberGenerator(this); } for ( int i = 0 ; i < maxmob ; i++ ) { mob[i].loadNumberGenerator(this); } for ( int i = 0 ; i < maxitem ; i++ ) { //Debug.println("Generator load item " + i + ": " + item[i] + ":" /* + item[i].constructName2OneItem() */ ); item[i].loadNumberGenerator(this); } } public void setRandomNumberSeed ( InputStream logStream ) { BufferedReader logReader = new BufferedReader ( Utility.getBestInputStreamReader ( logStream ) ); try { logReader.readLine(); //la primera linea no contiene la semilla //la segunda s� try { semilla = Long.valueOf ( logReader.readLine() ).longValue(); } catch ( NumberFormatException e ) { System.err.println("Read " + logReader.readLine() + ", expected random number seed" ); throw e; } aleat = new java.util.Random( semilla ); } catch ( java.io.IOException exc ) { write("Excepci�n I/O al leer el log"); } for ( int i = 0 ; i < maxroom ; i++ ) { room[i].loadNumberGenerator(this); } for ( int i = 0 ; i < maxmob ; i++ ) { mob[i].loadNumberGenerator(this); } for ( int i = 0 ; i < maxitem ; i++ ) { item[i].loadNumberGenerator(this); } for ( int i = 0 ; i < maxabsent ; i++ ) { absent[i].loadNumberGenerator(this); } for ( int i = 0 ; i < maxspell ; i++ ) { spell[i].loadNumberGenerator(this); } } public void setRandomNumberSeed (String logfile) throws java.io.FileNotFoundException { FileInputStream logInput = openLogFile(logfile); setRandomNumberSeed(logInput); } public long getRandomNumberSeed ( ) { return semilla; } public java.util.Random getRandom() { return aleat; } public List getPlayerList() { return playerList; } //OBSOLETE public Player getPlayer() { return (Player) playerList.get(0); } public boolean isLoadingLog() { return from_log; } public org.w3c.dom.Document getXMLRepresentation ( ) throws javax.xml.parsers.ParserConfigurationException { org.w3c.dom.Document doc = javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); org.w3c.dom.Element suElemento = doc.createElement( "World" ); suElemento.setAttribute ( "worldName" , String.valueOf( worldname ) ); suElemento.setAttribute ( "moduleName" , String.valueOf( modulename ) ); suElemento.setAttribute ( "worldDir" , String.valueOf( worlddir ) ); suElemento.setAttribute ( "maxroom" , String.valueOf( maxroom ) ); suElemento.setAttribute ( "maxitem" , String.valueOf( maxitem ) ); suElemento.setAttribute ( "maxmob" , String.valueOf( maxmob ) ); //suElemento.setAttribute ( "player" , String.valueOf( player.getID() ) ); suElemento.setAttribute ( "author" , String.valueOf( author ) ); suElemento.setAttribute ( "version" , String.valueOf( version ) ); suElemento.setAttribute ( "parserVersion" , String.valueOf( parserVersion ) ); suElemento.setAttribute ( "date" , String.valueOf( date ) ); suElemento.setAttribute ( "type" , String.valueOf( type ) ); //visual configuration if ( vc != null ) suElemento.appendChild(vc.getXMLRepresentation(doc)); //player list org.w3c.dom.Element playerListElement = doc.createElement ( "PlayerList" ); for ( int i = 0 ; i < playerList.size() ; i++ ) { org.w3c.dom.Element playerElement = doc.createElement ( "Player" ); if ( ((Player)playerList.get(i)).getUniqueName() != null ) playerElement.setAttribute("id",String.valueOf(((Player)playerList.get(i)).getUniqueName())); else playerElement.setAttribute("id",String.valueOf(((Player)playerList.get(i)).getID())); playerListElement.appendChild(playerElement); } suElemento.appendChild(playerListElement); //multimedia files org.w3c.dom.Element fileListElement = doc.createElement ( "FileList" ); for ( int i = 0 ; i < fileList.size() ; i++ ) { org.w3c.dom.Element fileElement = doc.createElement ( "File" ); fileElement.setAttribute("path",(String)fileList.get(i)); fileListElement.appendChild(fileElement); } suElemento.appendChild(fileListElement); //object code if ( itsCode != null ) suElemento.appendChild(itsCode.getXMLRepresentation(doc)); //player generation element org.w3c.dom.Element pgElement = doc.createElement("PlayerGeneration"); for ( int i = 0 ; i < playerTemplateNodes.size() ; i++ ) { //org.w3c.dom.Element templateElt = (org.w3c.dom.Element) doc.importNode ( (org.w3c.dom.Element) playerTemplateNodes.get(i) , true ); //doc.renameNode //templateElt.setNodeValue("Template"); //because it could be named "Player" if we created it from the 1st player by default. org.w3c.dom.Element templateElt = doc.createElement("Template"); //because node could be named "Mobile" if we created it from the 1st player by default. //We rename it by cloning the children Element theOriginalElt = (org.w3c.dom.Element) playerTemplateNodes.get(i); NodeList children = theOriginalElt.getChildNodes(); for ( int j = 0 ; j < children.getLength() ; j++ ) { Node child = children.item(j); Node importedChild = doc.importNode(child,true); templateElt.appendChild ( importedChild ); } NamedNodeMap attrs = theOriginalElt.getAttributes(); for ( int j = 0 ; j < attrs.getLength() ; j++ ) { org.w3c.dom.Node attr = (org.w3c.dom.Node) attrs.item(j); templateElt.setAttribute(attr.getNodeName(), attr.getNodeValue()); } pgElement.appendChild ( templateElt ); } suElemento.appendChild ( pgElement ); //entity lists elements org.w3c.dom.Element roomsElement = doc.createElement("Rooms"); org.w3c.dom.Element itemsElement = doc.createElement("Items"); org.w3c.dom.Element mobilesElement = doc.createElement("Mobiles"); org.w3c.dom.Element absentsElement = doc.createElement("AbstractEntities"); org.w3c.dom.Element spellsElement = doc.createElement("Spells"); for ( int i = 0 ; i < /*maxroom*/ maxroom ; i++ ) { roomsElement.appendChild ( room[i].getXMLRepresentation(doc)); } for ( int i = 0 ; i < /*maxitem*/ maxitem ; i++ ) { itemsElement.appendChild ( item[i].getXMLRepresentation(doc)); } for ( int i = 0 ; i < /*maxmob*/ maxmob ; i++ ) { Debug.println("Mob " + i); if ( mob[i] != null ) //en avents. no cargadas con XML y dem�s modernismos mobilesElement.appendChild ( mob[i].getXMLRepresentation(doc)); } for ( int i = 0 ; i < /*maxabsent*/ maxabsent ; i++ ) { absentsElement.appendChild ( absent[i].getXMLRepresentation(doc)); } for ( int i = 0 ; i < /*maxspell*/ maxspell ; i++ ) { spellsElement.appendChild ( spell[i].getXMLRepresentation(doc)); } suElemento.appendChild(roomsElement); suElemento.appendChild(itemsElement); suElemento.appendChild(mobilesElement); suElemento.appendChild(absentsElement); suElemento.appendChild(spellsElement); doc.appendChild(suElemento); return doc; } //add an item dynamically public void addItemAssigningID ( Item newItem ) { if ( item.length <= maxitem ) { Item[] newArray; if ( item.length > 2 ) //para que lo incremente el 1.5 newArray = new Item[ (int)((double)item.length * (double)1.5) ]; else newArray = new Item[4]; for ( int i = 0 ; i < maxitem ; i++ ) newArray[i] = item[i]; item = newArray; } //{length of item is > maxitem} item [ maxitem ] = newItem; newItem.setID ( maxitem ); newItem.setWorld( this ); if ( newItem.getUniqueName() != null ) nameTable.put( newItem.getUniqueName(), new Integer ( maxitem + Utility.item_summand ) ); maxitem++; // Debug.println("Maxitem is now " + maxitem); newItem.loadNumberGenerator(this); // Debug.println("Assigned generator to " + newItem + ": " + getRandom()); } public Item addCloneOfItem ( Item ourItem ) { //Item newIt = (Item) ourItem.clone(); //newIt.setInstanceOf ( ourItem.getID() ); return ourItem.createNewInstance(this,true,true); //addItemAssigningID ( newIt ); } //add a mobile dynamically public void addMobileAssigningID ( Mobile newMob ) { if ( mob.length <= maxmob ) { Mobile[] newArray; if ( mob.length > 2 ) //si no, multiplicar por 1.5 no incrementa newArray = new Mobile[ (int)((double)mob.length * (double)1.5) ]; else newArray = new Mobile[4]; for ( int i = 0 ; i < maxmob ; i++ ) newArray[i] = mob[i]; mob = newArray; } //{length of mob is > maxmob} mob [ maxmob ] = newMob; newMob.setID ( maxmob ); if ( newMob.getUniqueName() != null ) nameTable.put( newMob.getUniqueName(), new Integer ( maxmob + Utility.mobile_summand ) ); maxmob++; newMob.loadNumberGenerator(this); } //add a room dynamically public void addRoomAssigningID ( Room newRoom ) { if ( room.length <= maxroom ) { Room[] newArray; if ( room.length > 2 ) //si no, multiplicar por 1.5 no incrementa newArray = new Room[ (int)((double)room.length * (double)1.5) ]; else newArray = new Room[4]; for ( int i = 0 ; i < maxroom ; i++ ) newArray[i] = room[i]; room = newArray; } //{length of mob is > maxmob} room [ maxroom ] = newRoom; newRoom.setID ( maxroom ); if ( newRoom.getUniqueName() != null ) nameTable.put( newRoom.getUniqueName(), new Integer ( maxroom + Utility.room_summand ) ); maxroom++; newRoom.loadNumberGenerator(this); } public void addAbstractEntityAssigningID ( AbstractEntity newAbsEnt ) { if ( absent.length <= maxabsent ) { AbstractEntity[] newArray; if ( absent.length > 2 ) //si no, multiplicar por 1.5 no incrementa newArray = new AbstractEntity[ (int)((double)absent.length * (double)1.5) ]; else newArray = new AbstractEntity[4]; for ( int i = 0 ; i < maxabsent ; i++ ) newArray[i] = absent[i]; absent = newArray; } //{length of mob is > maxmob} absent [ maxabsent ] = newAbsEnt; newAbsEnt.setID ( maxabsent ); if ( newAbsEnt.getUniqueName() != null ) nameTable.put( newAbsEnt.getUniqueName(), new Integer ( maxabsent + Utility.absent_summand ) ); maxabsent++; newAbsEnt.loadNumberGenerator(this); } public Player createPlayerFromTemplate ( InputOutputClient io ) throws XMLtoWorldException { if ( playerTemplateNodes == null || playerTemplateNodes.size() < 1 ) return null; else return new Player ( this , io , (org.w3c.dom.Element) playerTemplateNodes.get(0) ); } public Player createPlayerFromTemplate ( InputOutputClient io , String templateName ) throws XMLtoWorldException { Element playerTemplateNode = (Element) playerTemplateNodesByName.get(templateName); if ( playerTemplateNode == null ) return null; else return new Player ( this , io , (org.w3c.dom.Element) playerTemplateNode ); } /** * Runs the world's BSH routine to assign a player to a client. * Return value of the routine is stored in the retval argument. * @return True if beanshell code hit end(), false if not. */ public boolean runAssignPlayerCode ( ReturnValue retval , InputOutputClient io ) { boolean ejecutado = false; try { Debug.println("Before exec code"); ejecutado = execCode( "assignPlayer" , new Object[] { io } , retval ); Debug.println("After exec code"); } catch (ScriptException bshte) { writeError("bsh.TargetError found at assignPlayer routine\n" ); writeError(ExceptionPrinter.getExceptionReport(bshte)); Debug.println ( bshte.printTargetError(bshte) ); writeError( bshte.printTargetError(bshte) ); io.write(ExceptionPrinter.getExceptionReport(bshte)); System.err.println("ARGH"); bshte.printStackTrace(); } return ejecutado; } public void addNewPlayerASAP ( InputOutputClient io ) throws XMLtoWorldException { //if there is beanshell code to assign players, exec it /* System.err.println("addNewPlayerASAP for " + io); for ( int i = 0 ; i < playerList.size() ; i++ ) { Player pl = (Player) playerList.get(i); System.err.println(pl); } if ( this.getMobile("Elsincara") != null ) { System.err.println("Elsincara is on " + this.getMobile("Elsincara").getRoom()); } if ( this.getRoom("Sala oeste") != null ) { System.err.println(this.getRoom("Sala oeste").getMobiles()); } if ( this.getRoom("Sala este") != null ) { System.err.println(this.getRoom("Sala este").getMobiles()); } */ ReturnValue retval = new ReturnValue(null); /* boolean ejecutado = false; try { Debug.println("Before exec code"); ejecutado = execCode( "assignPlayer" , new Object[] { io } , retval ); Debug.println("After exec code"); } catch (bsh.TargetError bshte) { writeError("bsh.TargetError found at assignPlayer routine\n" ); writeError(ExceptionPrinter.getExceptionReport(bshte)); Debug.println ( bshte.printTargetError(bshte) ); writeError( bshte.printTargetError(bshte) ); bshte.printStackTrace(); } */ boolean ejecutado = runAssignPlayerCode(retval,io); if ( retval.getRetVal() != null ) //devolvi� un jugador { Player p = (Player)retval.getRetVal(); if ( playerList.contains(p) ) //si nos devuelven un jugador existente en la player-list, ser� que est� disabled y quiere reconectar. { p.reconnect(io); return; } else { synchronized ( this ) { playersToAdd.add(p); } return; } } else if ( ejecutado ) //hizo end(), sobrecarga comportamiento por defecto { return; } //comportamiento por defecto synchronized ( this ) //general method desynchronized, for it can include calls to blocking I/O (enter your player name, password, etc.) { Player pl = createPlayerFromTemplate ( io ); if ( pl != null ) //playersToAdd.add ( createPlayerFromTemplate ( io ) ); //TODO: why two times? playersToAdd.add(pl); else { io.write("Player template generated a null player. No player creation code [assignPlayer], player list or player templates defined?"); io.write("addNewPlayerASAP() was unsuccessful."); return; } } io.write("Player enqueued to be added...\n"); } /** * If there is a room with unique name "limbo" or "Limbo", then that's considered the world's Limbo. * If not, then by default the Limbo is the room numbered 0. * @return */ public Room getLimbo() { Room r = getRoom("limbo"); if ( r != null ) return r; r = getRoom("Limbo"); if ( r != null ) return r; return getRoom(0); } public void executePlayerIntro( Player p ) { warnVersionIfNeeded(p); //exec player intro routine try { execCode("intro",""); //EVA (obsolete) //without state info execCode("intro", new Object[] {p}); //with state info execCode("intro", new Object[] {p,new Boolean(this.comesFromLoadedState())}); } catch (EVASemanticException esm) //EVA { write("EVASemanticException found at intro routine" ); } catch (ScriptException bshte) { write("bsh.TargetError found at intro routine\n" ); writeError(ExceptionPrinter.getExceptionReport(bshte)); } } public void update ( ) { for ( int i = 0 ; i < getMaxRoom() ; i++ ) { if ( getRoom(i) != null ) { getRoom(i).update(this); } } for ( int i = 0 ; i < getMaxMob() ; i++ ) //inc. 0: el Player. { if ( getMob(i) != null ) { getMob(i).update(this); } } for ( int i = 0 ; i < getMaxItem() ; i++ ) { if ( getItem(i) != null ) getItem(i).update(this); } for ( int i = 0 ; i < getMaxAbstractEntity() ; i++ ) { if ( getAbstractEntity(i) != null ) getAbstractEntity(i).update(this); } for ( int i = 0 ; i < getMaxSpell() ; i++ ) { if ( getSpell(i) != null ) getSpell(i).update(this); } if ( ! ( playersToAdd.isEmpty() ) ) { for ( int i = 0 ; i < playersToAdd.size() ; i++ ) { Player p = (Player) playersToAdd.get(i); Debug.println("The " + i + "th Player is " + p ); addMobileAssigningID ( p ); //(has already an IO client associated) //Room startingRoom = p.getRoom(); //startingRoom.addMob ( p ); Room startingRoom; if ( p.getPropertyValueAsString("room") != null ) startingRoom = getRoom(p.getPropertyValueAsString("room")); else startingRoom = getRoom(1); //startingRoom.addMob ( p ); p.setRoom(startingRoom); if ( p.getState() == Mobile.DISABLED ) p.setNewState(Mobile.IDLE,1); addPlayer ( p ); p.getClient().write("Has sido a�adido al mundo.\n"); p.getRoom().reportActionAuto(p,null,"De repente, $1 aparece de la nada.\n",false); write("New player joined the game.\n"); //exec player intro routine executePlayerIntro(p); } playersToAdd = new Vector(); } } /**Indicates whether we have loaded a state in this World.*/ private boolean fromState = false; public boolean comesFromLoadedState() { return fromState; } public void loadState ( String statefname ) throws FileNotFoundException,ParserConfigurationException,SAXException,IOException,XMLtoWorldException { //File f = new File ( statefname ); //despu�s haremos diff, y todo el rollo... //De momento, xml y a tirar p'alante. //BufferedReader br; org.w3c.dom.Document d = null; room=null; item=null; mob=null; absent=null; spell=null; playerList=new Vector(); /*//older code is older //br = new BufferedReader ( new InputStreamReader ( new FileInputStream ( f ) , "ISO-8859-1" ) ); InputSource is = new InputSource(br); //DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); io.write(io.getColorCode("information") + "Obteniendo �rbol DOM de los datos XML [estado]...\n" + io.getColorCode("reset") ); d = db.parse(is); */ DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); io.write(io.getColorCode("information") + UIMessages.getInstance().getMessage("load.world.tree.state") + "\n" + io.getColorCode("reset") ); FileInputStream fis = null; try { fis = new FileInputStream(new File(statefname)); } catch (FileNotFoundException fnfe ) { try { fis = new FileInputStream(new File(Paths.SAVE_PATH,statefname)); } catch ( FileNotFoundException fnfe2 ) { throw(fnfe); } } d = db.parse( fis ); //marks that this world comes from loading a state fromState = true; org.w3c.dom.Element n = d.getDocumentElement(); loadWorldFromXML ( n , io , false ); //be a client! (provisional) } public int getNumberOfConnectedPlayers ( ) { int addedPlayers=0; for ( int i = 0 ; i < playerList.size() ; i++ ) { Player cur = (Player) playerList.get(i); if ( cur.getState() != Mobile.DISABLED ) addedPlayers++; } //Debug.println("Added: " + playerList + "(" + addedPlayers + ")"); //Debug.println("To add: " + playersToAdd); return addedPlayers + playersToAdd.size(); } public VisualConfiguration getVisualConfiguration() { return vc; } public List getFileList ( ) { return fileList; } public void addPlayer ( Player p ) { //(new Exception()).printStackTrace(); playerList.add ( p ); if ( from_log ) { p.prepareLog(logReader); } } public void writeWithTemplate ( String colorTemplate , String s ) { write ( io.getColorCode(colorTemplate) + s + io.getColorCode("reset") ); } public void writeImportant ( String s ) { writeWithTemplate("important",s); } public void writeError ( String s ) { writeWithTemplate("error",s); if ( debugMode ) { System.err.print(s); } } public String toString() { StringBuffer sb = new StringBuffer(); sb.append("[World: "); if ( worldname != null && worldname.length() > 0 ) sb.append(worldname); else sb.append("(unnamed world)"); sb.append(", internal handle "); sb.append(super.toString()); sb.append("]"); return sb.toString(); } //**class loader used by getResource and getResourceAsStream methods*/ //currently unused, and maybe better to keep it that way due to applet security restrictions when creating a class loader private ClassLoader resourceLoader; /** * Sets the jar file inside which world resources (multimedia files, etc.) can reside. * @param jarFileURL */ //currently unused, and maybe better to keep it that way due to applet security restrictions when creating a class loader private void setResourceJarFile ( URL jarFileURL ) { URLClassLoader ucl = new URLClassLoader ( new URL[] {jarFileURL} , this.getClass().getClassLoader() ); resourceLoader = ucl; } //currently unused, and maybe better to keep it that way due to applet security restrictions when creating a class loader private ClassLoader getDefaultResourceLoader() { try { return new URLClassLoader ( new URL[] { new File ( this.getWorldPath() ).toURI().toURL() } , this.getClass().getClassLoader() ); } catch (MalformedURLException e) { e.printStackTrace(); return null; } } /** * Fetches an URL for a global resource (a resource that is not particular to a worl but shared by all worlds in AGE, such as * language files, etc.) * @param path * @return */ public URL getGlobalResource ( String path ) throws Exception { try { return this.getClass().getClassLoader().getResource(path); } catch ( Exception e ) { throw(e); } } public InputStream getGlobalResourceAsStream ( String path ) { return this.getClass().getClassLoader().getResourceAsStream(path); } public URL getResource ( String path ) { try { return new URL ( worldurl , path ); } catch (MalformedURLException e) { return null; } /* if ( resourceLoader == null ) resourceLoader = getDefaultResourceLoader(); //return resourceLoader.getResource(this.getWorldPath()+path); return resourceLoader.getResource(path); */ } public InputStream getResourceAsStream ( String path ) { try { return new URL ( worldurl , path ).openStream(); } catch (MalformedURLException e) { return null; } catch (IOException e) { return null; } /* if ( resourceLoader == null ) resourceLoader = getDefaultResourceLoader(); //return resourceLoader.getResourceAsStream(this.getWorldPath()+path); return resourceLoader.getResourceAsStream(path); */ } public void setDebugMode ( boolean debugMode ) { this.debugMode = debugMode; } public boolean isDebugMode () { return debugMode; } /** * Give an explicit warning if the version required by the world is more recent than the AGE version being used. * Pass a player to warn the player, else the server is warned. */ public void warnVersionIfNeeded(Player p) { if ( new VersionComparator().compare(GameEngineThread.getVersionNumber(),parserVersion) < 0 ) { if ( p == null ) { /* writeError("\n\nAVISO IMPORTANTE:\n"); writeError("Est�s usando la versi�n " + GameEngineThread.getVersionNumber() + " de AGE, y este mundo ha sido pensado para la versi�n " + parserVersion + " y superiores.\n"); writeError("El mundo puede no funcionar, desc�rgate la �ltima versi�n de AGE en http://code.google/com/p/aetheria para jugarlo.\n\n"); */ writeError( UIMessages.getInstance().getMessage("age.version.warning.header") + "\n" ); writeError( UIMessages.getInstance().getMessage("age.version.warning.2","$curversion",GameEngineThread.getVersionNumber(),"$reqversion",parserVersion) ); writeError( " " ); writeError( UIMessages.getInstance().getMessage("age.download.url") + "\n\n" ); } else { /* p.writeError("\n\nAVISO IMPORTANTE:\n"); p.writeError("Est�s usando la versi�n " + GameEngineThread.getVersionNumber() + " de AGE, y este mundo ha sido pensado para la versi�n " + parserVersion + " y superiores.\n"); p.writeError("El mundo puede no funcionar, desc�rgate la �ltima versi�n de AGE en http://code.google/com/p/aetheria para jugarlo.\n\n"); p.waitKeyPress(); */ p.writeError( UIMessages.getInstance().getMessage("age.version.warning.header") + "\n" ); p.writeError( UIMessages.getInstance().getMessage("age.version.warning.2","$curversion",GameEngineThread.getVersionNumber(),"$reqversion",parserVersion) ); p.writeError( " " ); p.writeError( UIMessages.getInstance().getMessage("age.download.url") + "\n\n" ); p.waitKeyPress(); } } } public String getRequiredAGEVersion() { return parserVersion; } //go back to legacy if things fail public int commandMatchingMode = Entity.MODERATE_COMMAND_MATCHING; /** * values should be static constants from class Entity. * @param matchingMode */ public void setCommandMatchingMode ( int matchingMode ) { commandMatchingMode = matchingMode; } public int getCommandMatchingMode() { return commandMatchingMode; } private AGESpellChecker spellChecker; public AGESpellChecker getSpellChecker() { if ( spellChecker == null ) spellChecker = new AGESpellChecker(this,getLanguage()); return spellChecker; } public ObjectCode getAssociatedCode() { return itsCode; } public String getParserVersion() { return parserVersion; } /** * Returns a String starting with base that has not been used as a unique name in this World. * @param base * @return */ public String generateUnusedUniqueName ( String base ) { for ( ;; ) //generate random names until one is unused { String candidate = ((base==null)?"":base) + UUID.randomUUID().toString(); if ( getEntity(candidate) == null ) return candidate; } } /** * @return Whether the world is running at least the given version of the parser. */ public boolean versionAtLeast ( String version ) { return new VersionComparator().compare(getParserVersion(),version) >= 0; } private List[] namesForDirections = null; /** * This is the right way of obtaining the names of a direction in a multilanguage way. */ public List getNamesForDirection ( int direction ) { if ( direction < 0 || direction > 9 ) return null; if ( namesForDirections == null ) namesForDirections = new List[10]; if ( namesForDirections[direction] == null ) { namesForDirections[direction] = doGetNamesForDirection(direction); } return namesForDirections[direction]; } /** * Get the name of a standard direction in a multilanguage way, without caching. * @param direction * @return */ private List doGetNamesForDirection ( int direction ) { List result = new ArrayList(); switch ( direction ) { case Path.NORTE: result.add( getMessages().getMessage("direction.n") ); //result.add("n"); break; case Path.SUR: result.add( getMessages().getMessage("direction.s") ); //result.add("s"); break; case Path.OESTE: result.add( getMessages().getMessage("direction.w") ); //result.add("o"); break; case Path.ESTE: result.add( getMessages().getMessage("direction.e") ); //result.add("e"); break; case Path.SUDESTE: result.add( getMessages().getMessage("direction.se") ); //not added I think //result.add("sudeste"); //result.add("se"); //result.add("sureste"); //alias break; case Path.SUROESTE: result.add( getMessages().getMessage("direction.sw") ); //not added I think //result.add("sudoeste"); //alias //result.add("so"); //result.add("suroeste"); break; case Path.NORDESTE: result.add( getMessages().getMessage("direction.ne") ); //not added I think //result.add("nordeste"); //result.add("ne"); //result.add("noreste"); //alias break; case Path.NOROESTE: result.add( getMessages().getMessage("direction.nw") ); //not added I think //result.add("noroeste"); //result.add("no"); break; case Path.ARRIBA: result.add( getMessages().getMessage("direction.u") ); //result.add("arriba"); //result.add("ar"); break; case Path.ABAJO: result.add( getMessages().getMessage("direction.d") ); //result.add("abajo"); //result.add("ab"); break; } return result; } /** * Parses arguments to see if they denote a standard exit direction, and returns it (NO_DIRECTION for none). * Inspired on moderateMatchesCommand from class Entity. * @param arguments * @return */ public int argumentsToDirection ( String arguments ) { for ( int direction = 0 ; direction <= 9 ; direction++ ) { List referenceNameList = getNamesForDirection(direction); Iterator it = referenceNameList.iterator(); int j = 0; //current token being read, starting at 1 (we set to 0 here because we're going to do j++ inside the while loop) //while ( st.hasMoreTokens() ) while ( it.hasNext() ) { j++; String currentReferenceName = // st.nextToken(); (String) it.next(); int position = arguments.toLowerCase().indexOf(currentReferenceName.toLowerCase()); if ( position < 0 ) //does not match continue; if ( position != 0 && !Character.isWhitespace(arguments.charAt(position-1)) ) //matches but starts at a place other than beginning/whitespace continue; if ( position+currentReferenceName.length() != arguments.length() && !Character.isWhitespace(arguments.charAt(position+currentReferenceName.length())) ) //matches but ends at a place other than end/whitespace continue; //if we have reached this point, the match is acceptable return direction; } } return Path.NO_DIRECTION; } }