package com.planet_ink.coffee_mud.Common;
import com.planet_ink.coffee_mud.core.interfaces.*;
import com.planet_ink.coffee_mud.core.*;
import com.planet_ink.coffee_mud.core.collections.*;
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.Common.interfaces.AccountStats.Agent;
import com.planet_ink.coffee_mud.Common.interfaces.TimeClock.TimePeriod;
import com.planet_ink.coffee_mud.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.AbilityMapper.AbilityMapping;
import com.planet_ink.coffee_mud.Libraries.interfaces.AchievementLibrary.Achievement;
import com.planet_ink.coffee_mud.Libraries.interfaces.AchievementLibrary.Tracker;
import com.planet_ink.coffee_mud.Libraries.interfaces.XMLLibrary.XMLTag;
import com.planet_ink.coffee_mud.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.StdMOB;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;
import java.nio.ByteBuffer;
import java.util.*;
/*
Copyright 2010-2016 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 DefaultPlayerAccount implements PlayerAccount
{
@Override
public String ID()
{
return "DefaultPlayerAccount";
}
@Override
public String name()
{
return ID();
}
protected SHashSet<String> friends = new SHashSet<String>();
protected SHashSet<String> ignored = new SHashSet<String>();
protected SVector<String> players = new SVector<String>();
protected String accountName = "";
protected String lastIP = "";
protected long lastDateTime = System.currentTimeMillis();
protected long lastUpdated = 0;
protected String email = "";
protected String password = "";
protected String notes = "";
protected long accountExpiration = 0;
protected int bonusCommonSk = 0;
protected int bonusCraftSk = 0;
protected int bonusNonCraftSk = 0;
protected int bonusLanguages = 0;
protected int bonusCharStatPt = 0;
protected int bonusCharLimit = 0;
protected int bonusCharOnlineLimit= 0;
protected String[] xtraValues = null;
protected Set<AccountFlag> acctFlags = new SHashSet<AccountFlag>();
protected volatile MOB fakePlayerM = null;
protected long[] prideExpireTime = new long[TimeClock.TimePeriod.values().length];
protected int[][] prideStats = new int[TimeClock.TimePeriod.values().length][AccountStats.PrideStat.values().length];
protected SVector<PlayerLibrary.ThinPlayer> thinPlayers = new SVector<PlayerLibrary.ThinPlayer>();
protected Map<String,Tracker> achievementers = new STreeMap<String,Tracker>();
protected CMUniqNameSortSVec<Tattoo> tattoos = new CMUniqNameSortSVec<Tattoo>(1);
public DefaultPlayerAccount()
{
super();
xtraValues=CMProps.getExtraStatCodesHolder(this);
}
@Override
public CMObject newInstance()
{
try
{
return getClass().newInstance();
}
catch(final Exception e)
{
return new DefaultPlayerStats();
}
}
@Override public void initializeClass(){}
@Override
public CMObject copyOf()
{
try
{
final DefaultPlayerAccount O=(DefaultPlayerAccount)this.clone();
O.friends=friends.copyOf();
O.ignored=ignored.copyOf();
O.xtraValues=(xtraValues==null)?null:(String[])xtraValues.clone();
return O;
}
catch(final CloneNotSupportedException e)
{
return new DefaultPlayerStats();
}
}
@Override
public String getLastIP()
{
return lastIP;
}
@Override
public void setLastIP(String ip)
{
lastIP=ip;
}
@Override
public String getEmail()
{
if(email==null)
return "";
return email;
}
@Override
public void setEmail(String newAdd)
{
email=newAdd;
}
@Override
public long getLastUpdated()
{
return lastUpdated;
}
@Override
public void setLastUpdated(long time)
{
lastUpdated=time;
}
@Override
public long getLastDateTime()
{
return lastDateTime;
}
@Override
public void setLastDateTime(long C)
{
lastDateTime=C;
}
@Override
public String getPasswordStr()
{
return password;
}
@Override
public void setPassword(String newPassword)
{
if(CMProps.getBoolVar(CMProps.Bool.HASHPASSWORDS)
&&(!CMLib.encoder().isARandomHashString(newPassword)))
password=CMLib.encoder().makeRandomHashString(newPassword);
else
password=newPassword;
}
@Override
public boolean matchesPassword(String checkPass)
{
return CMLib.encoder().passwordCheck(checkPass, password);
}
@Override
public String getNotes()
{
return notes;
}
@Override
public void setNotes(String newnotes)
{
notes=newnotes;
}
protected SHashSet<String> getHashFrom(String str)
{
final SHashSet<String> h=new SHashSet<String>();
int x=str.indexOf(';');
while(x>=0)
{
final String fi=str.substring(0,x).trim();
if(fi.length()>0)
h.add(fi);
str=str.substring(x+1);
x=str.indexOf(';');
}
if(str.trim().length()>0)
h.add(str.trim());
return h;
}
@Override
public Set<String> getFriends()
{
return friends;
}
@Override
public Set<String> getIgnored()
{
return ignored;
}
@Override
public void bumpPrideStat(PrideStat stat, int amt)
{
final long now=System.currentTimeMillis();
if(stat!=null)
for(final TimeClock.TimePeriod period : TimeClock.TimePeriod.values())
{
if(period==TimeClock.TimePeriod.ALLTIME)
prideStats[period.ordinal()][stat.ordinal()]+=amt;
else
{
if(now>prideExpireTime[period.ordinal()])
{
for(final AccountStats.PrideStat stat2 : AccountStats.PrideStat.values())
prideStats[period.ordinal()][stat2.ordinal()]=0;
prideExpireTime[period.ordinal()]=period.nextPeriod();
}
prideStats[period.ordinal()][stat.ordinal()]+=amt;
}
}
}
@Override
public int getPrideStat(TimePeriod period, PrideStat stat)
{
if((period==null)||(stat==null))
return 0;
return prideStats[period.ordinal()][stat.ordinal()];
}
@Override
public MOB getAccountMob()
{
if(fakePlayerM!=null)
return fakePlayerM;
synchronized(this)
{
if(fakePlayerM!=null)
return fakePlayerM;
fakePlayerM=CMClass.getMOB("StdMOB");
fakePlayerM.setName(getAccountName());
fakePlayerM.setPlayerStats((PlayerStats)CMClass.getCommon("DefaultPlayerStats"));
fakePlayerM.playerStats().setAccount(this);
fakePlayerM.playerStats().setEmail(getEmail());
fakePlayerM.basePhyStats().setLevel(1);
fakePlayerM.recoverPhyStats();
return fakePlayerM;
}
}
protected String getPrivateList(Set<String> h)
{
if((h==null)||(h.size()==0))
return "";
final StringBuffer list=new StringBuffer("");
for (final String string : h)
list.append((string)+";");
return list.toString();
}
@Override
public String getXML()
{
final StringBuffer rest=new StringBuffer("");
final String[] codes=getStatCodes();
final XMLLibrary libXML = CMLib.xml();
for (final String code2 : codes)
{
final String code=code2.toUpperCase();
final String value = getStat(code);
if(value.length()==0)
rest.append("<"+code+" />");
else
rest.append("<"+code+">"+libXML.parseOutAngleBrackets(value)+"</"+code+">");
}
rest.append("<NEXTPRIDEPERIODS>").append(CMParms.toTightListString(prideExpireTime)).append("</NEXTPRIDEPERIODS>");
rest.append("<PRIDESTATS>");
for(final TimeClock.TimePeriod period : TimeClock.TimePeriod.values())
rest.append(CMParms.toTightListString(prideStats[period.ordinal()])).append(";");
rest.append("</PRIDESTATS>");
rest.append("<ACHIEVEMENTS");
for(Iterator<Tracker> i=achievementers.values().iterator();i.hasNext();)
{
final Tracker T = i.next();
if(T.getAchievement().isSavableTracker() && (T.getCount(null) != 0))
rest.append(" ").append(T.getAchievement().getTattoo()).append("=").append(T.getCount(null));
// getCount(null) should be ok, because it's only the un-savable trackers that need the mob obj
}
rest.append(" />");
rest.append("<TATTOOS>").append(CMParms.toListString(tattoos)).append("</TATTOOS>");
rest.append("<ACCSTATS>")
.append(bonusCommonSk).append(';')
.append(bonusCraftSk).append(';')
.append(bonusNonCraftSk).append(';')
.append(bonusLanguages).append(';')
.append(bonusCharStatPt).append(';')
.append(bonusCharLimit).append(';')
.append(bonusCharOnlineLimit).append(';')
.append("</ACCSTATS>");
return rest.toString();
}
@Override
public void setXML(String str)
{
final XMLLibrary xmlLib = CMLib.xml();
final List<XMLLibrary.XMLTag> xml = xmlLib.parseAllXML(str);
final String[] codes=getStatCodes();
for (final String code : codes)
{
String val=xmlLib.getValFromPieces(xml,code.toUpperCase());
if(val==null)
val="";
setStat(code.toUpperCase(),xmlLib.restoreAngleBrackets(val));
}
final String[] nextPeriods=xmlLib.getValFromPieces(xml, "NEXTPRIDEPERIODS").split(",");
final String[] prideStats=xmlLib.getValFromPieces(xml, "PRIDESTATS").split(";");
final Pair<Long,int[]>[] finalPrideStats = CMLib.players().parsePrideStats(nextPeriods, prideStats);
for(final TimeClock.TimePeriod period : TimeClock.TimePeriod.values())
{
if(period.ordinal()<finalPrideStats.length)
{
this.prideExpireTime[period.ordinal()]=finalPrideStats[period.ordinal()].first.longValue();
this.prideStats[period.ordinal()]=finalPrideStats[period.ordinal()].second;
}
}
final XMLTag achievePiece = xmlLib.getPieceFromPieces(xml, "ACHIEVEMENTS");
achievementers.clear();
for(Enumeration<Achievement> a=CMLib.achievements().achievements(Agent.ACCOUNT);a.hasMoreElements();)
{
final Achievement A=a.nextElement();
if((achievePiece != null) && achievePiece.parms().containsKey(A.getTattoo()))
achievementers.put(A.getTattoo(), A.getTracker(CMath.s_int(achievePiece.parms().get(A.getTattoo()).trim())));
else
achievementers.put(A.getTattoo(), A.getTracker(0));
}
final String[] allTattoos=xmlLib.getValFromPieces(xml, "TATTOOS").split(",");
this.tattoos.clear();
for(String tattoo : allTattoos)
this.addTattoo(tattoo);
final String[] allAccStats=xmlLib.getValFromPieces(xml, "ACCSTATS").split(";");
if(allAccStats.length>=7)
{
bonusCommonSk=CMath.s_int(allAccStats[0]);
bonusCraftSk=CMath.s_int(allAccStats[1]);
bonusNonCraftSk=CMath.s_int(allAccStats[2]);
bonusLanguages=CMath.s_int(allAccStats[3]);
bonusCharStatPt=CMath.s_int(allAccStats[4]);
bonusCharLimit=CMath.s_int(allAccStats[5]);
bonusCharOnlineLimit=CMath.s_int(allAccStats[6]);
}
}
// Acct Expire Code
@Override
public long getAccountExpiration()
{
return accountExpiration;
}
@Override
public void setAccountExpiration(long newVal)
{
accountExpiration=newVal;
}
@Override
public String getAccountName()
{
return accountName;
}
@Override
public void setAccountName(String name)
{
accountName = name;
}
@Override
public void addNewPlayer(MOB mob)
{
if(players.contains(mob.Name()))
return;
if(mob==fakePlayerM)
return;
try
{
for(final String name : players)
if(name.equalsIgnoreCase(mob.Name()))
return;
}
catch(final Exception e) {}
players.add(mob.Name());
thinPlayers.clear();
}
@Override
public String findPlayer(String name)
{
if(name==null)
return null;
for(final String pName : players)
if(pName.equalsIgnoreCase(name))
return pName;
return null;
}
@Override
public void delPlayer(String name)
{
players.remove(name);
try
{
for(final String name1 : players)
if(name1.equalsIgnoreCase(name))
players.remove(name1);
}
catch(final Exception e) {}
thinPlayers.clear();
}
@Override
public void delPlayer(MOB mob)
{
if(mob==fakePlayerM)
return;
players.remove(mob.Name());
try
{
for(final String name : players)
if(name.equalsIgnoreCase(mob.Name()))
players.remove(name);
}
catch(final Exception e) {}
thinPlayers.clear();
}
@Override
public Enumeration<MOB> getLoadPlayers()
{
final Vector<MOB> mobs = new Vector<MOB>(players.size());
for(final Enumeration<String> e=getPlayers();e.hasMoreElements();)
{
final MOB M=CMLib.players().getLoadPlayer(e.nextElement());
if(M!=null)
mobs.addElement(M);
}
return mobs.elements();
}
@Override
public Enumeration<PlayerLibrary.ThinPlayer> getThinPlayers()
{
synchronized(thinPlayers)
{
if(thinPlayers.size() != players.size())
{
for(Enumeration<String> e=getPlayers();e.hasMoreElements();)
{
final String name = e.nextElement();
PlayerLibrary.ThinPlayer tP = CMLib.database().getThinUser(name);
if (tP == null)
{
tP = new PlayerLibrary.ThinPlayer()
{
@Override
public String name()
{
return name;
}
@Override
public String charClass()
{
return "";
}
@Override
public String race()
{
return "";
}
@Override
public int level()
{
return 0;
}
@Override
public int age()
{
return 0;
}
@Override
public long last()
{
return 0;
}
@Override
public String email()
{
return null;
}
@Override
public String ip()
{
return "";
}
@Override
public int exp()
{
return 0;
}
@Override
public int expLvl()
{
return 0;
}
};
}
thinPlayers.add(tP);
}
}
}
return thinPlayers.elements();
}
@Override
public Enumeration<String> getPlayers()
{
return players.elements();
}
@Override
public void setPlayerNames(Vector<String> names)
{
if(names != null)
{
players = new SVector<String>(names);
for(final String name : players)
{
final MOB M=CMLib.players().getPlayer(name);
if((M!=null)&&(M.playerStats()!=null)&&(M.playerStats().getAccount()==null))
M.playerStats().setAccount(this);
}
}
}
@Override
public int numPlayers()
{
return players.size();
}
@Override
public boolean isSet(AccountFlag flag)
{
return acctFlags.contains(flag);
}
@Override
public void setFlag(AccountFlag flag, boolean setOrUnset)
{
if(setOrUnset)
acctFlags.add(flag);
else
acctFlags.remove(flag);
}
@Override
public void killAchievementTracker(final Achievement A, final MOB mob)
{
if(achievementers.containsKey(A.getTattoo()))
{
achievementers.remove(A.getTattoo());
if(mob != null)
{
mob.delTattoo(A.getTattoo());
}
}
}
@Override
public Tracker getAchievementTracker(final Achievement A, final MOB mob)
{
final Tracker T;
if(achievementers.containsKey(A.getTattoo()))
{
T=achievementers.get(A.getTattoo());
}
else
{
T=A.getTracker(0);
achievementers.put(A.getTattoo(), T);
}
return T;
}
@Override
public void rebuildAchievementTracker(final MOB mob, String achievementTattoo)
{
Achievement A=CMLib.achievements().getAchievement(achievementTattoo);
if(A!=null)
{
if(achievementers.containsKey(A.getTattoo()))
achievementers.put(A.getTattoo(), A.getTracker(achievementers.get(A.getTattoo()).getCount(mob)));
else
achievementers.put(A.getTattoo(), A.getTracker(0));
}
else
achievementers.remove(achievementTattoo);
}
/** Manipulation of the tatoo list */
@Override
public void addTattoo(String of)
{
final Tattoo T=(Tattoo)CMClass.getCommon("DefaultTattoo");
addTattoo(T.set(of));
}
@Override
public void addTattoo(String of, int tickDown)
{
final Tattoo T=(Tattoo)CMClass.getCommon("DefaultTattoo");
addTattoo(T.set(of,tickDown));
}
@Override
public void delTattoo(String of)
{
final Tattoo T=findTattoo(of);
if(T!=null)
tattoos.remove(T);
}
@Override
public void addTattoo(Tattoo of)
{
if ((of == null) || (of.getTattooName() == null) || (of.getTattooName().length() == 0) || findTattoo(of.getTattooName()) != null)
return;
tattoos.addElement(of);
}
@Override
public void delTattoo(Tattoo of)
{
if ((of == null) || (of.getTattooName() == null) || (of.getTattooName().length() == 0))
return;
final Tattoo tat = findTattoo(of.getTattooName());
if (tat == null)
return;
tattoos.remove(tat);
}
@Override
public Enumeration<Tattoo> tattoos()
{
return tattoos.elements();
}
@Override
public Tattoo findTattoo(String of)
{
if ((of == null) || (of.length() == 0))
return null;
return tattoos.find(of.trim());
}
@Override
public int getBonusCharStatPoints()
{
return this.bonusCharStatPt;
}
@Override
public void setBonusCharStatPoints(int bonus)
{
this.bonusCharStatPt = bonus;
}
@Override
public int getBonusCommonSkillLimits()
{
return this.bonusCommonSk;
}
@Override
public void setBonusCommonSkillLimits(int bonus)
{
this.bonusCommonSk = bonus;
}
@Override
public int getBonusCraftingSkillLimits()
{
return this.bonusCraftSk;
}
@Override
public void setBonusCraftingSkillLimits(int bonus)
{
this.bonusCraftSk = bonus;
}
@Override
public int getBonusNonCraftingSkillLimits()
{
return this.bonusNonCraftSk;
}
@Override
public void setBonusNonCraftingSkillLimits(int bonus)
{
this.bonusNonCraftSk = bonus;
}
@Override
public int getBonusLanguageLimits()
{
return this.bonusLanguages;
}
@Override
public void setBonusLanguageLimits(int bonus)
{
this.bonusLanguages = bonus;
}
@Override
public int getBonusCharsOnlineLimit()
{
return bonusCharOnlineLimit;
}
@Override
public void setBonusCharsOnlineLimit(int bonus)
{
bonusCharOnlineLimit = bonus;
}
@Override
public int getBonusCharsLimit()
{
return bonusCharLimit;
}
@Override
public void setBonusCharsLimit(int bonus)
{
bonusCharLimit = bonus;
}
protected static String[] CODES={"CLASS","FRIENDS","IGNORE","LASTIP","LASTDATETIME",
"NOTES","ACCTEXPIRATION","FLAGS","EMAIL",
"BONUSCOMMON", "BONUSCRAFT","BONUSNONCRAFT","BONUSLANGS",
"BONUSCHARSTATS", "BONUSCHARLIMIT", "BONUSCHARONLINE"};
@Override
public String getStat(String code)
{
switch(getCodeNum(code))
{
case 0:
return ID();
case 1:
return getPrivateList(getFriends());
case 2:
return getPrivateList(getIgnored());
case 3:
return lastIP;
case 4:
return "" + lastDateTime;
case 5:
return notes;
case 6:
return "" + accountExpiration;
case 7:
return CMParms.toListString(acctFlags);
case 8:
return email;
case 9:
return "" + bonusCommonSk;
case 10:
return "" + bonusCraftSk;
case 11:
return "" + bonusNonCraftSk;
case 12:
return "" + bonusLanguages;
case 13:
return "" + bonusCharStatPt;
case 14:
return "" + bonusCharLimit;
case 15:
return "" + bonusCharOnlineLimit;
default:
return CMProps.getStatCodeExtensionValue(getStatCodes(), xtraValues, code);
}
}
@Override
public void setStat(String code, String val)
{
switch(getCodeNum(code))
{
case 0: break;
case 1:
{
friends.clear();
friends.addAll(getHashFrom(val));
break;
}
case 2:
{
ignored.clear();
ignored.addAll(getHashFrom(val));
break;
}
case 3:
lastIP = val;
break;
case 4:
lastDateTime = CMath.s_long(val);
break;
case 5:
notes = val;
break;
case 6:
accountExpiration = CMath.s_long(val);
break;
case 7:
{
acctFlags = new SHashSet<AccountFlag>();
for(String s : CMParms.parseCommas(val.toUpperCase(),true))
{
final AccountFlag flag = (AccountFlag)CMath.s_valueOf(AccountFlag.class, s);
if(flag != null)
acctFlags.add(flag);
}
break;
}
case 8:
email = val;
break;
case 9:
bonusCommonSk = CMath.s_parseIntExpression(val);
break;
case 10:
bonusCraftSk = CMath.s_parseIntExpression(val);
break;
case 11:
bonusNonCraftSk = CMath.s_parseIntExpression(val);
break;
case 12:
bonusLanguages = CMath.s_parseIntExpression(val);
break;
case 13:
bonusCharStatPt = CMath.s_parseIntExpression(val);
break;
case 14:
bonusCharLimit = CMath.s_parseIntExpression(val);
break;
case 15:
bonusCharOnlineLimit = CMath.s_parseIntExpression(val);
break;
default:
CMProps.setStatCodeExtensionValue(getStatCodes(), xtraValues, code, val);
break;
}
}
@Override
public int getSaveStatIndex()
{
return (xtraValues == null) ? getStatCodes().length : getStatCodes().length - xtraValues.length;
}
private static String[] codes = null;
@Override
public String[] getStatCodes()
{
if (codes == null)
codes = CMProps.getStatCodesList(CODES, this);
return codes;
}
@Override
public boolean isStat(String code)
{
return CMParms.indexOf(getStatCodes(), code.toUpperCase().trim()) >= 0;
}
protected int getCodeNum(String code)
{
for (int i = 0; i < CODES.length; i++)
{
if (code.equalsIgnoreCase(CODES[i]))
return i;
}
return -1;
}
public boolean sameAs(PlayerAccount E)
{
if (!(E instanceof DefaultPlayerAccount))
return false;
for (int i = 0; i < getStatCodes().length; i++)
{
if (!E.getStat(getStatCodes()[i]).equals(getStat(getStatCodes()[i])))
return false;
}
return true;
}
@Override
public int compareTo(CMObject o)
{
return CMClass.classID(this).compareToIgnoreCase(CMClass.classID(o));
}
}