package com.planet_ink.coffee_mud.Libraries; import com.planet_ink.coffee_mud.core.interfaces.*; import com.planet_ink.coffee_mud.core.*; import com.planet_ink.coffee_mud.core.CMSecurity.DbgFlag; import com.planet_ink.coffee_mud.core.collections.*; import com.planet_ink.coffee_mud.Libraries.interfaces.*; import com.planet_ink.coffee_mud.Libraries.interfaces.CatalogLibrary.CataData; import com.planet_ink.coffee_mud.Libraries.interfaces.CatalogLibrary.RoomContent; import com.planet_ink.coffee_mud.Libraries.interfaces.DatabaseEngine.PlayerData; import com.planet_ink.coffee_mud.Libraries.interfaces.XMLLibrary.XMLTag; import com.planet_ink.coffee_mud.Abilities.interfaces.*; import com.planet_ink.coffee_mud.Areas.interfaces.*; import com.planet_ink.coffee_mud.Behaviors.interfaces.*; import com.planet_ink.coffee_mud.CharClasses.interfaces.*; import com.planet_ink.coffee_mud.Commands.interfaces.*; import com.planet_ink.coffee_mud.Common.interfaces.*; import com.planet_ink.coffee_mud.Exits.interfaces.*; import com.planet_ink.coffee_mud.Items.interfaces.*; import com.planet_ink.coffee_mud.Locales.interfaces.*; import com.planet_ink.coffee_mud.MOBS.interfaces.*; import com.planet_ink.coffee_mud.Races.interfaces.*; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.*; /* Copyright 2008-2019 Bo Zimmerman Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ public class CMCatalog extends StdLibrary implements CatalogLibrary { @Override public String ID() { return "CMCatalog"; } protected String commonBuilderTemplateKey= "SYSTEM_BTEMPLATE"; protected String templatePersonalSection = commonBuilderTemplateKey + "_PERSONAL"; protected String templateSharedSection = commonBuilderTemplateKey + "_SHARED"; public DVector icatalog = new DVector(2); public DVector mcatalog = new DVector(2); public volatile CMFile.CMVFSDir catalogFileMobsRoot = null; public volatile CMFile.CMVFSDir catalogFileItemsRoot = null; public void changeCatalogFlag(final Physical P, final boolean truefalse) { if(P==null) return; if(CMath.bset(P.basePhyStats().disposition(),PhyStats.IS_CATALOGED)) { if(!truefalse) { P.basePhyStats().setDisposition(CMath.unsetb(P.basePhyStats().disposition(),PhyStats.IS_CATALOGED)); P.phyStats().setDisposition(CMath.unsetb(P.phyStats().disposition(),PhyStats.IS_CATALOGED)); } } else if(truefalse) { P.basePhyStats().setDisposition(CMath.setb(P.basePhyStats().disposition(),PhyStats.IS_CATALOGED)); P.phyStats().setDisposition(CMath.setb(P.phyStats().disposition(),PhyStats.IS_CATALOGED)); } } protected Object getCatalogObject(final DVector list, final String name, final int dim) { synchronized(list) { try { if(list.size()==0) return null; int start=0; int end=list.size()-1; while(start<=end) { final int mid=(end+start)/2; final int comp=((Environmental)list.elementAt(mid,1)).Name().compareToIgnoreCase(name); if(comp==0) return list.elementAt(mid,dim); else if(comp>0) end=mid-1; else start=mid+1; } } catch(final Exception e) { } return null; } } protected void addCatalogReplace(final DVector DV, final String category, final Physical P) { int start=0; int end=DV.size()-1; final String name=P.Name(); int lastStart=0; int lastEnd=DV.size()-1; int comp=-1; int mid=-1; while(start<=end) { mid=(end+start)/2; comp=((Environmental)DV.elementAt(mid,1)).Name().compareToIgnoreCase(name); if(comp==0) break; else if(comp>0) { lastEnd=end; end=mid-1; } else { lastStart=start; start=mid+1; } } if(comp==0) { if((P instanceof DBIdentifiable) &&((DBIdentifiable)DV.elementAt(mid,1)).databaseID().length()>0) ((DBIdentifiable)P).setDatabaseID(((DBIdentifiable)DV.elementAt(mid,1)).databaseID()); ((Environmental)DV.elementAt(mid,1)).destroy(); DV.setElementAt(mid,1,P); } else { final CataData data=new CataDataImpl(""); if(category!=null) data.setCategory(category); if(mid>=0) { for(comp=lastStart;comp<=lastEnd;comp++) { if(((Environmental)DV.elementAt(comp,1)).Name().compareToIgnoreCase(name)>0) { DV.insertElementAt(comp,P,data); return; } } } DV.addElement(P,data); } } public String[] makeCatalogNames(final String catName, final DVector catalog) { final List<String> nameList=new ArrayList<String>(catalog.size()); for(int x=0;x<catalog.size();x++) { if((catName==null)||(catName.equals(((CataData)catalog.elementAt(x, 2)).category()))) nameList.add(((Environmental)catalog.elementAt(x, 1)).Name()); } return nameList.toArray(new String[0]); } public String[] makeCatalogCatagories(final DVector catalog) { final List<String> catalogList=new SortedListWrap<String>(new ArrayList<String>(2)); for(int x=0;x<catalog.size();x++) { if(!catalogList.contains(((CataData)catalog.elementAt(x, 2)).category())) catalogList.add(((CataData)catalog.elementAt(x, 2)).category()); } return catalogList.toArray(new String[catalogList.size()]); } @Override public String[] getCatalogItemNames() { return makeCatalogNames(null, icatalog); } @Override public String[] getCatalogItemNames(final String cataName) { return makeCatalogNames(cataName, icatalog); } @Override public String[] getCatalogMobNames() { return makeCatalogNames(null, mcatalog); } @Override public String[] getCatalogMobNames(final String cataName) { return makeCatalogNames(cataName, mcatalog); } @Override public String[] getMobCatalogCatagories() { return makeCatalogCatagories(mcatalog); } @Override public String[] getItemCatalogCatagories() { return makeCatalogCatagories(icatalog); } @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public Item[] getCatalogItems() { final List<Item> itemsV=(List)icatalog.getDimensionList(1); return itemsV.toArray(new Item[itemsV.size()]); } @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public MOB[] getCatalogMobs() { final List<MOB> mobsV=(List)mcatalog.getDimensionList(1); return mobsV.toArray(new MOB[mobsV.size()]); } @Override public boolean isCatalogObj(final Environmental E) { if(E instanceof MOB) return getCatalogMob(E.Name()) != null; if(E instanceof Item) return getCatalogItem(E.Name()) != null; return false; } @Override public boolean isCatalogObj(final String name) { Object o=getCatalogMob(name); if(o==null) o=getCatalogItem(name); return o!=null; } @Override public Item getCatalogItem(final String called) { return (Item) getCatalogObject(icatalog, called, 1); } @Override public MOB getCatalogMob(final String called) { return (MOB) getCatalogObject(mcatalog, called, 1); } @Override public CataData getCatalogItemData(final String called) { return (CataData) getCatalogObject(icatalog, called, 2); } @Override public CataData getCatalogMobData(final String called) { return (CataData) getCatalogObject(mcatalog, called, 2); } @Override public Vector<RoomContent> roomContent(final Room R) { Item I=null; MOB M=null; Environmental E=null; ShopKeeper SK=null; List<Environmental> shops=null; Environmental shopItem=null; final Vector<RoomContent> content =new Vector<RoomContent>(); if(R!=null) { shops=CMLib.coffeeShops().getAllShopkeepers(R,null); for(int s=0;s<shops.size();s++) { E=shops.get(s); if(E==null) continue; SK=CMLib.coffeeShops().getShopKeeper(E); if(SK==null) continue; for(final Iterator<Environmental> i=SK.getShop().getStoreInventory();i.hasNext();) { shopItem=i.next(); if(shopItem instanceof Physical) content.addElement(new RoomContentImpl((Physical)shopItem,SK)); } } for(int i=0;i<R.numItems();i++) { I=R.getItem(i); if(I!=null) content.addElement(new RoomContentImpl(I)); } for(int m=0;m<R.numInhabitants();m++) { M=R.fetchInhabitant(m); if(M==null) continue; for(int i=0;i<M.numItems();i++) { I=M.getItem(i); if(I!=null) content.addElement(new RoomContentImpl(I,M)); } content.addElement(new RoomContentImpl(M)); } } return content; } @Override public void updateRoomContent(final String roomID, final List<RoomContent> content) { final List<Environmental> updatables=new LinkedList<Environmental>(); final List<Environmental> deletables=new LinkedList<Environmental>(); for(final RoomContent C : content) { if(C.deleted()) { if(C.holder()!=null) { if(!updatables.contains(C.holder())) updatables.add(C.holder()); } else if(!updatables.contains(C.P())) deletables.add(C.P()); } else if(C.isDirty()) { if(C.holder()!=null) { if(!updatables.contains(C.holder())) updatables.add(C.holder()); } else if(!updatables.contains(C.P())) updatables.add(C.P()); } } for(final Environmental E : deletables) { updatables.remove(E); if((!(E instanceof DBIdentifiable)) ||(!((DBIdentifiable)E).canSaveDatabaseID()) ||(((DBIdentifiable)E).databaseID().trim().length()==0)) continue; if(E instanceof MOB) { CMLib.database().DBDeleteMOB(roomID,(MOB)E); this.catalogFileMobsRoot=null; } else { CMLib.database().DBDeleteItem(roomID,(Item)E); this.catalogFileItemsRoot=null; } } for(final Environmental E : updatables) { if(E instanceof ShopKeeper) { final ShopKeeper SK=(ShopKeeper)E; final Vector<Environmental> newShop=new Vector<Environmental>(); for(final RoomContent C : content) { if((C.holder()==SK)&&(!C.deleted())) newShop.addElement(C.P()); } final CoffeeShop shop=(SK instanceof Librarian)?((Librarian)SK).getBaseLibrary():SK.getShop(); shop.resubmitInventory(newShop); } } for(final Environmental E : updatables) { if((!(E instanceof DBIdentifiable)) ||(!((DBIdentifiable)E).canSaveDatabaseID()) ||(((DBIdentifiable)E).databaseID().trim().length()==0)) continue; if(E instanceof MOB) { CMLib.database().DBUpdateMOB(roomID,(MOB)E); this.catalogFileMobsRoot=null; } else { CMLib.database().DBUpdateItem(roomID,(Item)E); this.catalogFileItemsRoot=null; } } } @Override public void addCatalog(final Physical PA) { addCatalog(null,PA); } @Override public void addCatalog(final String category, Physical PA) { if((PA==null) ||(!(PA instanceof DBIdentifiable)) ||(!((DBIdentifiable)PA).canSaveDatabaseID())) return; synchronized(getSync(PA).intern()) { changeCatalogFlag(PA,true); final Physical origP=PA; PA=(Physical)origP.copyOf(); submitToCatalog(PA); if(PA instanceof Item) { CMLib.database().DBCreateThisItem("CATALOG_ITEMS",(Item)PA); this.catalogFileItemsRoot=null; } else if(PA instanceof MOB) { CMLib.database().DBCreateThisMOB("CATALOG_MOBS",(MOB)PA); this.catalogFileMobsRoot=null; } final CataData data=getCatalogData(PA); if(data!=null) { if(category != null) data.setCategory(category); data.addReference(origP); } } } @Override public void submitToCatalog(final Physical P) { submitToCatalog(null,P); } public void submitToCatalog(final String category, final Physical P) { if((P==null) ||(!(P instanceof DBIdentifiable)) ||(!((DBIdentifiable)P).canSaveDatabaseID())) return; CMLib.threads().deleteAllTicks(P); synchronized(getSync(P).intern()) { if(getCatalogObj(P)!=null) return; changeCatalogFlag(P,false); P.text(); // to get cataloged status into xml if(P instanceof Item) { synchronized(icatalog) { addCatalogReplace(icatalog,category,P); } } else if(P instanceof MOB) { synchronized(mcatalog) { addCatalogReplace(mcatalog,category,P); } } } } @Override public void delCatalog(Physical P) { if(P==null) return; P=getCatalogObj(P); if(P==null) return; final CataData data=getCatalogData(P); if(P instanceof Item) { synchronized(icatalog) { icatalog.removeElement(P); } CMLib.database().DBDeleteItem("CATALOG_ITEMS",(Item)P); this.catalogFileItemsRoot=null; } else if(P instanceof MOB) { synchronized(mcatalog) { mcatalog.removeElement(P); } CMLib.database().DBDeleteMOB("CATALOG_MOBS",(MOB)P); this.catalogFileMobsRoot=null; } if(data!=null) { final ArrayList<Room> rooms=new ArrayList<Room>(); for(final Enumeration<Physical> e=data.enumeration();e.hasMoreElements();) { final Physical P2=e.nextElement(); final Room R=CMLib.map().getStartRoom(P2); if((R!=null)&&(!rooms.contains(R))) rooms.add(R); changeCatalogUsage(P2,false); } for(Room R : rooms) { List<RoomContent> contents=roomContent(R); for(final RoomContent content : contents) { if((CMLib.flags().isCataloged(content.P())) &&(content.P().Name().equalsIgnoreCase(P.Name()))) { if(((P instanceof MOB)&&(content.P() instanceof MOB)) ||((P instanceof Item)&&(content.P() instanceof Item))) changeCatalogFlag(content.P(),false); } } R=CMLib.coffeeMaker().makeNewRoomContent(R,false); contents=roomContent(R); boolean dirty=false; for(final RoomContent content : contents) { if((CMLib.flags().isCataloged(content.P())) &&(content.P().Name().equalsIgnoreCase(P.Name()))) { if(((P instanceof MOB)&&(content.P() instanceof MOB)) ||((P instanceof Item)&&(content.P() instanceof Item))) { changeCatalogFlag(content.P(),false); content.flagDirty(); dirty=true; } } } if(dirty) updateRoomContent(R.roomID(),contents); R.destroy(); } } } @Override public void updateCatalogCategory(final Physical modelP, final String newCat) { if((modelP==null) ||(!(modelP instanceof DBIdentifiable)) ||(!((DBIdentifiable)modelP).canSaveDatabaseID())) return; synchronized(getSync(modelP).intern()) { final CataData data=getCatalogData(modelP); if(data!=null) { data.setCategory(newCat.toUpperCase().trim()); if(modelP instanceof MOB) { CMLib.database().DBUpdateMOB("CATALOG_MOBS",(MOB)modelP); this.catalogFileMobsRoot=null; } else { CMLib.database().DBUpdateItem("CATALOG_ITEMS",(Item)modelP); this.catalogFileItemsRoot=null; } } } } @Override public void updateCatalog(final Physical modelP) { if((modelP==null) ||(!(modelP instanceof DBIdentifiable)) ||(!((DBIdentifiable)modelP).canSaveDatabaseID())) return; synchronized(getSync(modelP).intern()) { changeCatalogFlag(modelP,false); Physical cataP=(Physical)modelP.copyOf(); cataP.text(); // to get cataloged status into xml if(modelP!=getCatalogObj(modelP)) changeCatalogFlag(modelP,true); if(cataP instanceof Item) { synchronized(icatalog) { addCatalogReplace(icatalog,null,cataP); } } else if(cataP instanceof MOB) { synchronized(mcatalog) { addCatalogReplace(mcatalog,null,cataP); } } cataP=getCatalogObj(cataP); if(cataP instanceof MOB) { CMLib.database().DBUpdateMOB("CATALOG_MOBS",(MOB)cataP); this.catalogFileMobsRoot=null; } else { CMLib.database().DBUpdateItem("CATALOG_ITEMS",(Item)cataP); this.catalogFileItemsRoot=null; } final CataData data = getCatalogData(cataP); if(data!=null) data.delReference(cataP); SHashSet<Physical> ignored=null; if(data!=null) ignored=new SHashSet<Physical>(data.enumeration()); else ignored=new SHashSet<Physical>(1); Physical P; for(final Iterator<Physical> i=ignored.iterator();i.hasNext();) { P=i.next(); if((!P.amDestroyed()) &&(CMLib.flags().isCataloged(P)) &&(cataP!=P) &&(P.Name().equalsIgnoreCase(cataP.Name()))) { P.setMiscText(P.text()); changeCatalogFlag(P,true); } } final Vector<Environmental> all=new Vector<Environmental>(); final String srchStr="$"+cataP.Name()+"$"; final boolean isMob=(cataP instanceof MOB); if(cataP instanceof MOB) { all.addAll(CMLib.map().findInhabitants(CMLib.map().rooms(),null, srchStr, 50)); all.addAll(CMLib.map().findShopStock(CMLib.map().rooms(),null, srchStr, 50)); } else { all.addAll(CMLib.map().findRoomItems(CMLib.map().rooms(),null, srchStr, true, 50)); all.addAll(CMLib.map().findInventory(CMLib.map().rooms(),null, srchStr, 50)); all.addAll(CMLib.map().findInventory(null,null, srchStr, 50)); all.addAll(CMLib.map().findShopStockers(CMLib.map().rooms(),null, srchStr, 50)); all.addAll(CMLib.map().findShopStockers(null,null, srchStr, 50)); } final HashSet<ShopKeeper> doneShops=new HashSet<ShopKeeper>(); ShopKeeper SK=null; for (final Environmental environmental : all) { P=(Physical)environmental; if((CMLib.flags().isCataloged(P)) &&(!ignored.contains(P)) &&(((isMob)&&(P instanceof MOB))||((!isMob)&&(P instanceof Item))) &&(cataP.Name().equalsIgnoreCase(P.Name()))) { ignored.add(P); P.setMiscText(P.text()); changeCatalogFlag(P,true); } SK=CMLib.coffeeShops().getShopKeeper(P); if((SK!=null)&&(!doneShops.contains(SK))) { doneShops.add(SK); propogateShopChange(SK,ignored,cataP); } } } } @Override public void newInstance(final Physical P) { synchronized(getSync(P).intern()) { final PhyStats stats=P.basePhyStats(); if((stats!=null)&&(CMath.bset(stats.disposition(),PhyStats.IS_CATALOGED))) { final CataData data=getCatalogData(P); if(data!=null) data.addReference(P); } } } @Override public void bumpDeathPickup(final Physical P) { synchronized(getSync(P).intern()) { final PhyStats stats=P.basePhyStats(); if((stats!=null)&&(CMath.bset(stats.disposition(),PhyStats.IS_CATALOGED))) { final CataData data=getCatalogData(P); if(data!=null) data.bumpDeathPickup(); } } } @Override public void changeCatalogUsage(final Physical P, final boolean toCataloged) { synchronized(getSync(P).intern()) { if((P!=null) &&(P.basePhyStats()!=null) &&(!P.amDestroyed())) { if(toCataloged) { changeCatalogFlag(P,true); final CataData data=getCatalogData(P); if(data!=null) data.addReference(P); } else if(CMLib.flags().isCataloged(P)) { changeCatalogFlag(P,false); final CataData data=getCatalogData(P); if(data!=null) data.delReference(P); } } } } protected void propogateShopChange(final ShopKeeper SK, final Set<Physical> ignored, final Physical cataP) { final boolean isMob=(cataP instanceof MOB); Environmental E=null; boolean changes=false; final Vector<Environmental> newShop=new Vector<Environmental>(); for(final Iterator<Environmental> i=SK.getShop().getStoreInventory();i.hasNext();) { E=i.next(); if(!ignored.contains(E) && (E instanceof Physical)) { ignored.add((Physical)E); if((isMob) &&(E instanceof MOB) &&(CMLib.flags().isCataloged(E)) &&(cataP.Name().equalsIgnoreCase(E.Name()))) { E.setMiscText(E.text()); changes = true; } if((!isMob) &&(E instanceof Item) &&(CMLib.flags().isCataloged(E)) &&(cataP.Name().equalsIgnoreCase(E.Name()))) { E.setMiscText(E.text()); changes = true; } } newShop.add(E); } if(changes) SK.getShop().resubmitInventory(newShop); } @Override public CataData getCatalogData(final Physical P) { if(P==null) return null; return (P instanceof MOB)?getCatalogMobData(P.Name()):getCatalogItemData(P.Name()); } @Override public Physical getCatalogObj(final Physical P) { if(P==null) return null; return (P instanceof MOB)?getCatalogMob(P.Name()):getCatalogItem(P.Name()); } @Override public void setCategory(final Physical P, final String category) { final CataData data=getCatalogData(P); if((data!=null)&&(category!=null)) data.setCategory(category); } @Override public void updateCatalogIntegrity(final Physical P) { synchronized(getSync(P).intern()) { if(checkCatalogIntegrity(P)!=null) { changeCatalogFlag(P,false); P.text(); } } } private final String getSync(final String name, final boolean mobType) { return ((mobType) ? "CATASYNC_MOB_" : "CATASYNC_ITEM_") + name.toUpperCase(); } private final String getSync(final Environmental E) { return getSync(E.Name(), E instanceof MOB); } @Override public StringBuffer checkCatalogIntegrity(final Physical P) { if(P==null) return null; synchronized(getSync(P).intern()) { if(CMLib.flags().isCataloged(P)) { final CataData data=getCatalogData(P); final Physical cataE=getCatalogObj(P); if((cataE==null)||(data==null)) { if(!CMProps.getBoolVar(CMProps.Bool.MUDSTARTED)) return null; // if catalog isn't fully loaded, this can be a false correction if(data!=null) data.delReference(P); changeCatalogFlag(P,false); P.text(); return null; } else { StringBuffer diffs=null; changeCatalogFlag(P,false); if(!cataE.sameAs(P)) { diffs=new StringBuffer(""); for(int i=0;i<cataE.getStatCodes().length;i++) { if((!cataE.getStat(cataE.getStatCodes()[i]).equals(P.getStat(cataE.getStatCodes()[i])))) diffs.append(cataE.getStatCodes()[i]+","); } } if((P instanceof MOB)&&(cataE instanceof MOB)) { boolean firstChecked=false; if(diffs==null) diffs=new StringBuffer(""); for(final Pair<Clan,Integer> p : ((MOB)P).clans()) { if((((MOB)cataE).getClanRole(p.first.clanID())==null) ||(((MOB)cataE).getClanRole(p.first.clanID()).second.intValue()!=p.second.intValue())) firstChecked=true; } for(final Pair<Clan,Integer> p : ((MOB)cataE).clans()) { if((((MOB)P).getClanRole(p.first.clanID())==null) ||(((MOB)P).getClanRole(p.first.clanID()).second.intValue()!=p.second.intValue())) firstChecked=true; } if(firstChecked) diffs.append("CLANID,"); } changeCatalogFlag(P,true); data.addReference(P); return diffs; } } else { final CataData data=getCatalogData(P); if(data!=null) data.delReference(P); return null; } } } @Override public Item getDropItem(final MOB M, final boolean live) { if(M==null) return null; CatalogLibrary.CataData data=null; List<Item> selections=null; synchronized(icatalog) { try { for(int d=0;d<icatalog.size();d++) { data=(CatalogLibrary.CataData)icatalog.elementAt(d,2); if((data.getRate()>0.0) &&(data.getWhenLive()==live) &&(Math.random() <= data.getRate()) &&(CMLib.masking().maskCheck(data.getMaskV(),M,true))) { if(selections==null) selections=new ArrayList<Item>(); selections.add((Item)icatalog.elementAt(d,1)); } } } catch(final IndexOutOfBoundsException e) { } } if(selections==null) return null; Item I=selections.get(CMLib.dice().roll(1,selections.size(),-1)); I=(Item)I.copyOf(); changeCatalogUsage(I,true); return I; } @Override public CataData sampleCataData(final String xml) { return new CataDataImpl(xml); } @Override public boolean activate() { if(serviceClient==null) { name="THCatalog"+Thread.currentThread().getThreadGroup().getName().charAt(0); serviceClient=CMLib.threads().startTickDown(this, Tickable.TICKID_SUPPORT|Tickable.TICKID_SOLITARYMASK, MudHost.TIME_SAVETHREAD_SLEEP, 1); } return true; } @Override public boolean tick(final Tickable ticking, final int tickID) { try { if(!CMSecurity.isDisabled(CMSecurity.DisFlag.CATALOGTHREAD)) { tickStatus=Tickable.STATUS_ALIVE; isDebugging=CMSecurity.isDebugging(DbgFlag.CATALOGTHREAD); setThreadStatus(serviceClient,"checking catalog references."); String[] names = getCatalogItemNames(); for (final String name2 : names) { final CataData data=getCatalogItemData(name2); data.cleanHouse(); } names = getCatalogMobNames(); for (final String name2 : names) { final CataData data=getCatalogMobData(name2); data.cleanHouse(); } } } finally { tickStatus=Tickable.STATUS_NOT; setThreadStatus(serviceClient,"sleeping"); } return true; } @Override public boolean shutdown() { icatalog=new DVector(2); mcatalog=new DVector(2); if(CMLib.threads().isTicking(this, TICKID_SUPPORT|Tickable.TICKID_SOLITARYMASK)) { CMLib.threads().deleteTick(this, TICKID_SUPPORT|Tickable.TICKID_SOLITARYMASK); serviceClient=null; } return true; } protected void forceTick() { serviceClient.tickTicker(true); } protected static class RoomContentImpl implements RoomContent { private Physical obj=null; private boolean dirty=false; private Environmental holder=null; public RoomContentImpl(final Physical P) { obj = P; } public RoomContentImpl(final Physical P, final Environmental E) { obj = P; holder = E; } @Override public Physical P() { return obj; } @Override public void flagDirty() { dirty = true; } @Override public Environmental holder() { return holder; } @Override public boolean isDirty() { return dirty; } @Override public boolean deleted() { return obj.amDestroyed(); } } protected static class CataDataImpl implements CataData { public String lmaskStr = null; public String category = ""; public boolean live = false; public double rate = 0.0; public volatile int deathPickup = 0; public SVector<WeakReference<Physical>> refs = new SVector<WeakReference<Physical>>(1); public boolean noRefs = CMProps.getBoolVar(CMProps.Bool.CATALOGNOCACHE) || CMSecurity.isDisabled(CMSecurity.DisFlag.CATALOGCACHE); public MaskingLibrary.CompiledZMask lmaskV = null; public CataDataImpl(final String catadata) { build(catadata); } private Vector<Physical> makeVector() { final Vector<Physical> V=new Vector<Physical>(refs.size()); WeakReference<Physical> R=null; for(int r=0;r<refs.size();r++) { R=refs.elementAt(r); if(R!=null) { final Physical o=R.get(); if((o!=null) &&(!o.amDestroyed()) &&(CMath.bset(o.basePhyStats().disposition(),PhyStats.IS_CATALOGED))) V.addElement(o); } } return V; } @Override public String category() { return category; } @Override public void setCategory(final String cat) { if(cat!=null) category=cat; else category=""; } protected RoomnumberSet getLocations() { final Vector<Physical> items=makeVector(); final RoomnumberSet homes=(RoomnumberSet)CMClass.getCommon("DefaultRoomnumberSet"); final RoomnumberSet set=(RoomnumberSet)CMClass.getCommon("DefaultRoomnumberSet"); Room R=null; for(final Environmental E : items) { R=CMLib.map().getStartRoom(E); if(R==null) R=CMLib.map().roomLocation(E); if(R==null) continue; if((E instanceof Item) &&(((Item)E).owner() instanceof MOB) &&(!((MOB)((Item)E).owner()).isMonster())) continue; if(CMLib.law().getLandTitle(R)!=null) homes.add(CMLib.map().getExtendedRoomID(R)); else set.add(CMLib.map().getExtendedRoomID(R)); } if(set.roomCountAllAreas()>0) return set; return homes; } @Override public String randomRoom() { final RoomnumberSet set=getLocations(); if(set.roomCountAllAreas()==0) return ""; return set.random(); } @Override public String mostPopularArea() { final RoomnumberSet set=getLocations(); final Iterator<String> e=set.getAreaNames(); if(!e.hasNext()) return ""; String maxArea=e.next(); int maxCount=set.roomCount(maxArea); for(;e.hasNext();) { final String area=e.next(); final int count=set.roomCount(area); if(count>maxCount) { maxCount=count; maxArea=area; } } final Area A=CMLib.map().getArea(maxArea); if(A!=null) return A.Name(); return maxArea; } @Override public int numReferences() { int num=0; for(int r=0;r<refs.size();r++) { if(refs.elementAt(r).get()!=null) num++; } return num; } @Override public Enumeration<Physical> enumeration() { return makeVector().elements(); } @Override public int getDeathsPicksups() { return deathPickup; } @Override public void bumpDeathPickup() { deathPickup++; } @Override public synchronized void cleanHouse() { if(noRefs) { refs.clear(); return; } Environmental o=null; try { for(int r=refs.size()-1;r>=0;r--) { o=refs.elementAt(r).get(); if((o==null)||o.amDestroyed()||(!CMLib.flags().isCataloged(o))) refs.removeElementAt(r); } } catch (final ArrayIndexOutOfBoundsException ex) { } } @Override public Physical getLiveReference() { if(noRefs) return null; Physical o=null; try { for(int r=0;r<refs.size();r++) { o=refs.elementAt(r).get(); if((o!=null)&&(CMLib.flags().isInTheGame(o,true))) return o; } } catch (final Exception e) { } return null; } @Override public synchronized void addReference(final Physical P) { if(noRefs) return; if(isReference(P)) return; Environmental o=null; for(int r=0;r<refs.size();r++) { o=refs.elementAt(r).get(); if(o==null) { refs.setElementAt(new WeakReference<Physical>(P),r); return; } } refs.addElement(new WeakReference<Physical>(P)); } @Override public boolean isReference(final Physical P) { for(int r=0;r<refs.size();r++) { if(refs.elementAt(r).get()==P) return true; } return false; } @Override public synchronized void delReference(final Physical P) { if(!isReference(P)) return; Environmental o=null; for(int r=0;r<refs.size();r++) { o=refs.elementAt(r).get(); if(o==P) { refs.removeElementAt(r); return; } } } protected CataDataImpl(final String _lmask, final String _rate, final boolean _live) { this(_lmask,CMath.s_pct(_rate),_live); } protected CataDataImpl(final String _lmask, final double _rate, final boolean _live) { live=_live; lmaskStr=_lmask; lmaskV=null; if(lmaskStr.length()>0) lmaskV=CMLib.masking().maskCompile(lmaskStr); rate=_rate; } @Override public MaskingLibrary.CompiledZMask getMaskV() { return lmaskV; } @Override public String getMaskStr() { return lmaskStr; } @Override public boolean getWhenLive() { return live; } @Override public double getRate() { return rate; } @Override public void setMaskStr(final String s) { lmaskStr=s; if(s.trim().length()==0) lmaskV=null; else lmaskV=CMLib.masking().maskCompile(s); } @Override public void setWhenLive(final boolean l) { live = l; } @Override public void setRate(final double r) { rate = r; } @Override public String data(final String name) { final StringBuffer buf=new StringBuffer(""); buf.append("<CATALOGDATA "); if(name != null) buf.append("NAME=\""+CMLib.xml().parseOutAngleBracketsAndQuotes(name)+"\" "); buf.append("CATAGORY=\""+CMLib.xml().parseOutAngleBracketsAndQuotes(category)+"\">"); buf.append("<RATE>"+CMath.toPct(rate)+"</RATE>"); buf.append("<LMASK>"+CMLib.xml().parseOutAngleBrackets(lmaskStr)+"</LMASK>"); buf.append("<LIVE>"+live+"</LIVE>"); buf.append("</CATALOGDATA>"); return buf.toString(); } @Override public void build(final String catadata) { List<XMLLibrary.XMLTag> V=null; if((catadata!=null)&&(catadata.length()>0)) { V=CMLib.xml().parseAllXML(catadata); final XMLTag piece=CMLib.xml().getPieceFromPieces(V,"CATALOGDATA"); if((piece!=null)&&(piece.contents()!=null)&&(piece.contents().size()>0)) { category=CMLib.xml().restoreAngleBrackets(piece.getParmValue( "CATAGORY")); if(category==null) category=""; lmaskStr=CMLib.xml().restoreAngleBrackets(piece.getValFromPieces("LMASK")); final String ratestr=piece.getValFromPieces("RATE"); rate=CMath.s_pct(ratestr); lmaskV=null; if(lmaskStr.length()>0) lmaskV=CMLib.masking().maskCompile(lmaskStr); live=CMath.s_bool(piece.getValFromPieces("LIVE")); } } else { lmaskV=null; lmaskStr=""; live=false; rate=0.0; } } } protected CMFile.CMVFSDir getCatalogMobsRoot(final CMFile.CMVFSDir rootRoot) { if(catalogFileMobsRoot == null) { final CMFile.CMVFSDir newRoot=getCatalogRoot(mcatalog, "mobs", rootRoot); if(newRoot==null) return null; catalogFileMobsRoot=newRoot; } return catalogFileMobsRoot; } protected CMFile.CMVFSDir getCatalogItemsRoot(final CMFile.CMVFSDir rootRoot) { if(catalogFileItemsRoot == null) { final CMFile.CMVFSDir newRoot=getCatalogRoot(icatalog, "items", rootRoot); if(newRoot==null) return null; catalogFileItemsRoot=newRoot; } return catalogFileItemsRoot; } @Override public CMFile.CMVFSDir getCatalogRoot(final CMFile.CMVFSDir root) { return new CMFile.CMVFSDir(root,root.getPath()+"catalog/") { private CMFile.CMVFSFile[] myFiles = null; private CMFile.CMVFSFile[] oldFiles = null; @Override protected CMFile.CMVFSFile[] getFiles() { if((myFiles==null)||(oldFiles!=super.files)||(catalogFileItemsRoot==null)||(catalogFileMobsRoot==null)) { oldFiles=super.files; final CMFile.CMVFSDir mdir = getCatalogMobsRoot(this); final CMFile.CMVFSDir idir = getCatalogItemsRoot(this); final int xtra=((mdir==null)?0:1)+((idir==null)?0:1); if(super.files!=null) myFiles=Arrays.copyOf(super.files, super.files.length+xtra); else myFiles=new CMFile.CMVFSFile[xtra]; if(xtra==2) { myFiles[myFiles.length-2]=mdir; myFiles[myFiles.length-1]=idir; } else if(mdir != null) myFiles[myFiles.length-1]=mdir; else if(idir != null) myFiles[myFiles.length-1]=idir; Arrays.sort(myFiles,CMFile.CMVFSDir.fcomparator); } return myFiles; } }; } protected CMFile.CMVFSDir getCatalogRoot(final DVector catalog, final String rootName, final CMFile.CMVFSDir rootRoot) { if(catalog.size()==0) return null; final CMFile.CMVFSDir catalogFileRoot=new CMFile.CMVFSDir(rootRoot, 48, rootRoot.getPath()+rootName+"/"); final HashMap<String,List<Physical>> usedCats=new HashMap<String,List<Physical>>(); for(int i=0;i<catalog.size();i++) { final Physical obj=(Physical)catalog.elementAt(i, 1); final CataData data=(CataData)catalog.elementAt(i, 2); catalogFileRoot.add(new CMFile.CMVFSFile(catalogFileRoot.getPath()+obj.Name().replace(' ','_')+".cmare",48,System.currentTimeMillis(),"SYS") { @Override public Object readData() { if(obj instanceof MOB) return CMLib.coffeeMaker().getMobXML((MOB)obj); else if(obj instanceof Item) return CMLib.coffeeMaker().getItemXML((Item)obj); else return null; } }); if(!usedCats.containsKey(data.category())) usedCats.put(data.category(), new Vector<Physical>()); final List<Physical> list=usedCats.get(data.category()); list.add(obj); } catalogFileRoot.add(new CMFile.CMVFSFile(catalogFileRoot.getPath()+"all.cmare",48,System.currentTimeMillis(),"SYS") { @Override public Object readData() { final String tagName=(catalog.elementAt(0,1) instanceof MOB)?"MOBS":"ITEMS"; final StringBuilder str=new StringBuilder("<"+tagName+">"); for(int i=0;i<catalog.size();i++) { final Physical obj=(Physical)catalog.elementAt(i, 1); if(obj instanceof MOB) str.append(CMLib.coffeeMaker().getMobXML((MOB)obj)); else if(obj instanceof Item) str.append(CMLib.coffeeMaker().getItemXML((Item)obj)); } str.append("</"+tagName+">"); return str.toString(); } }); for(final String cat : usedCats.keySet()) { CMFile.CMVFSDir catagoryRoot=catalogFileRoot; if(cat.length()==0) { catagoryRoot=new CMFile.CMVFSDir(catalogFileRoot, 48, catalogFileRoot.getPath()+"uncategorized/"); catalogFileRoot.add(catagoryRoot); } else { catagoryRoot=new CMFile.CMVFSDir(catalogFileRoot, 48, catalogFileRoot.getPath()+cat.toLowerCase()+"/"); catalogFileRoot.add(catagoryRoot); } final List<Physical> objs=usedCats.get(cat); if(objs.size()>0) { for(final Physical obj : objs) { catagoryRoot.add(new CMFile.CMVFSFile(catagoryRoot.getPath()+obj.Name().replace(' ','_')+".cmare",48,System.currentTimeMillis(),"SYS") { @Override public Object readData() { if(obj instanceof MOB) return CMLib.coffeeMaker().getMobXML((MOB)obj); else if(obj instanceof Item) return CMLib.coffeeMaker().getItemXML((Item)obj); else return null; } }); } } catagoryRoot.add(new CMFile.CMVFSFile(catagoryRoot.getPath()+"all.cmare",48,System.currentTimeMillis(),"SYS") { @Override public Object readData() { final String tagName=(objs.get(0) instanceof MOB)?"MOBS":"ITEMS"; final StringBuilder str=new StringBuilder("<"+tagName+">"); for(final Physical obj : objs) { if(obj instanceof MOB) str.append(CMLib.coffeeMaker().getMobXML((MOB)obj)); else if(obj instanceof Item) str.append(CMLib.coffeeMaker().getItemXML((Item)obj)); } str.append("</"+tagName+">"); return str.toString(); } }); } return catalogFileRoot; } @Override public String makeValidNewBuilderTemplateID(final String ID) { if((ID==null)||(ID.trim().length()==0)||(ID.indexOf(' ')>=0)) return null; int x=ID.indexOf('_'); if(x<0) return ID.toUpperCase().trim(); if(x==0) return null; String possPlayer = ID.substring(0,x); if(CMLib.players().playerExists(possPlayer)||CMLib.players().accountExists(possPlayer)) return null; return ID.toUpperCase().trim(); } public Map<String,PlayerData> getBuilderTemplates(final String playerName) { final Map<String, PlayerData> allMyTemplates=new Hashtable<String, PlayerData>(); if((playerName==null) ||(playerName.length()==0)) return allMyTemplates; List<PlayerData> pDat = CMLib.database().DBReadPlayerData(playerName, templatePersonalSection); List<PlayerData> sDat = CMLib.database().DBReadPlayerSectionData(templateSharedSection); for(final PlayerData PD : pDat) allMyTemplates.put(PD.key().substring(commonBuilderTemplateKey.length()+1+PD.who().length()+1).toUpperCase().trim(), PD); for(final PlayerData PD : sDat) { if(PD.who().equalsIgnoreCase(playerName)) allMyTemplates.put(PD.key().substring(commonBuilderTemplateKey.length()+1+PD.who().length()+1).toUpperCase().trim().trim(), PD); else allMyTemplates.put(PD.key().substring(commonBuilderTemplateKey.length()+1).toUpperCase().trim(), PD); } return allMyTemplates; } @Override public List<Triad<String, String, String>> getBuilderTemplateList(final String playerName) { List<Triad<String, String, String>> list = new Vector<Triad<String, String, String>>(); final Map<String, PlayerData> PDs=getBuilderTemplates(playerName); if((PDs!=null)&&(PDs.size()>0)) { for(final String ID : PDs.keySet()) { final PlayerData pData = PDs.get(ID); CMClass.CMObjectType typ=CMLib.coffeeMaker().getUnknownTypeFromXML(pData.xml()); if(typ == null) typ=CMClass.CMObjectType.WEBMACRO; final String typName; if(!pData.who().equalsIgnoreCase(playerName)) typName="*"+typ.toString(); else if(pData.section().equals(templateSharedSection)) typName="+"+typ.toString(); else typName=" "+typ.toString(); final String name=CMLib.coffeeMaker().getUnknownNameFromXML(pData.xml()); list.add(new Triad<String, String, String>(ID,typName,name)); } } return list; } @Override public Environmental getBuilderTemplateObject(final String playerName, final String ID) { if((ID==null)||(ID.length()==0)) return null; final PlayerData PD=getBuilderTemplates(playerName).get(ID.toUpperCase().trim()); if(PD==null) return null; return CMLib.coffeeMaker().getUnknownFromXML(PD.xml()); } @Override public boolean addNewBuilderTemplateObject(final String playerName, final String ID, final Environmental E) { final StringBuffer xml=CMLib.coffeeMaker().getUnknownXML(E); if(xml==null) return false; CMLib.database().DBCreatePlayerData(playerName, templatePersonalSection, commonBuilderTemplateKey+"_"+playerName.toUpperCase().trim()+"_"+ID.toUpperCase().trim(), xml.toString()); return true; } @Override public boolean deleteBuilderTemplateObject(final String playerName, final String ID) { CMLib.database().DBDeletePlayerData(playerName, templatePersonalSection, commonBuilderTemplateKey+"_"+playerName.toUpperCase().trim()+"_"+ID.toUpperCase().trim()); CMLib.database().DBDeletePlayerData(playerName, templateSharedSection, commonBuilderTemplateKey+"_"+playerName.toUpperCase().trim()+"_"+ID.toUpperCase().trim()); return true; } @Override public boolean toggleBuilderTemplateObject(final String playerName, final String ID) { if((ID==null)||(ID.length()==0)) return false; final PlayerData PD=getBuilderTemplates(playerName).get(ID.toUpperCase().trim()); if(PD==null) return false; if(!PD.who().equalsIgnoreCase(playerName)) return false; if(PD.section().equals(templatePersonalSection)) { CMLib.database().DBDeletePlayerData(PD.who(), PD.section(), PD.key()); CMLib.database().DBCreatePlayerData(PD.who(), templateSharedSection, PD.key(), PD.xml()); return true; } else if(PD.section().equals(templateSharedSection)) { CMLib.database().DBDeletePlayerData(PD.who(), PD.section(), PD.key()); CMLib.database().DBCreatePlayerData(PD.who(), templatePersonalSection, PD.key(), PD.xml()); return true; } else return false; } }