Addition of paperdoll cache.

Contributed by Sahar.
This commit is contained in:
MobiusDevelopment 2020-07-04 00:26:44 +00:00
parent 37d338c51d
commit 1a1241957f
90 changed files with 2340 additions and 510 deletions

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -123,6 +124,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1203,6 +1205,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1233,6 +1237,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1248,6 +1254,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2120,19 +2127,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2196,6 +2191,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2216,6 +2216,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2232,4 +2237,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -40,6 +40,8 @@ public enum BaseStat
CHA(Stat.STAT_CHA), CHA(Stat.STAT_CHA),
LUC(Stat.STAT_LUC); LUC(Stat.STAT_LUC);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -92,7 +94,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -255,6 +255,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -123,6 +124,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1209,6 +1211,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1239,6 +1243,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1254,6 +1260,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2126,19 +2133,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2202,6 +2197,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2222,6 +2222,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2238,4 +2243,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -40,6 +40,8 @@ public enum BaseStat
CHA(Stat.STAT_CHA), CHA(Stat.STAT_CHA),
LUC(Stat.STAT_LUC); LUC(Stat.STAT_LUC);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -92,7 +94,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -255,6 +255,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -123,6 +124,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1209,6 +1211,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1239,6 +1243,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1254,6 +1260,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2126,19 +2133,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2202,6 +2197,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2222,6 +2222,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2238,4 +2243,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -40,6 +40,8 @@ public enum BaseStat
CHA(Stat.STAT_CHA), CHA(Stat.STAT_CHA),
LUC(Stat.STAT_LUC); LUC(Stat.STAT_LUC);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -92,7 +94,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -255,6 +255,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -123,6 +124,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1209,6 +1211,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1239,6 +1243,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1254,6 +1260,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2126,19 +2133,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2202,6 +2197,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2222,6 +2222,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2238,4 +2243,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -40,6 +40,8 @@ public enum BaseStat
CHA(Stat.STAT_CHA), CHA(Stat.STAT_CHA),
LUC(Stat.STAT_LUC); LUC(Stat.STAT_LUC);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -92,7 +94,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -255,6 +255,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -128,6 +129,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1238,6 +1240,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1268,6 +1272,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1283,6 +1289,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2139,19 +2146,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2215,6 +2210,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2235,6 +2235,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2251,4 +2256,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -40,6 +40,8 @@ public enum BaseStat
CHA(Stat.STAT_CHA), CHA(Stat.STAT_CHA),
LUC(Stat.STAT_LUC); LUC(Stat.STAT_LUC);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -92,7 +94,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -255,6 +255,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -151,6 +152,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1314,6 +1316,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1344,6 +1348,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1359,6 +1365,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2436,19 +2443,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2512,6 +2507,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2532,6 +2532,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2548,4 +2553,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -40,6 +40,8 @@ public enum BaseStat
CHA(Stat.STAT_CHA), CHA(Stat.STAT_CHA),
LUC(Stat.STAT_LUC); LUC(Stat.STAT_LUC);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -92,7 +94,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -255,6 +255,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -151,6 +152,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1314,6 +1316,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1344,6 +1348,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1359,6 +1365,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2436,19 +2443,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2512,6 +2507,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2532,6 +2532,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2548,4 +2553,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -40,6 +40,8 @@ public enum BaseStat
CHA(Stat.STAT_CHA), CHA(Stat.STAT_CHA),
LUC(Stat.STAT_LUC); LUC(Stat.STAT_LUC);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -92,7 +94,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -257,6 +257,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -151,6 +152,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1307,6 +1309,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1337,6 +1341,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1352,6 +1358,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2420,19 +2427,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2496,6 +2491,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2516,6 +2516,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2532,4 +2537,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -40,6 +40,8 @@ public enum BaseStat
CHA(Stat.STAT_CHA), CHA(Stat.STAT_CHA),
LUC(Stat.STAT_LUC); LUC(Stat.STAT_LUC);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -92,7 +94,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -257,6 +257,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -123,6 +124,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1209,6 +1211,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1239,6 +1243,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1254,6 +1260,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2126,19 +2133,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2202,6 +2197,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2222,6 +2222,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2238,4 +2243,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -38,6 +38,8 @@ public enum BaseStat
CON(Stat.STAT_CON), CON(Stat.STAT_CON),
MEN(Stat.STAT_MEN); MEN(Stat.STAT_MEN);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -90,7 +92,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -255,6 +255,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -123,6 +124,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1209,6 +1211,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1239,6 +1243,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1254,6 +1260,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2126,19 +2133,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2202,6 +2197,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2222,6 +2222,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2238,4 +2243,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -38,6 +38,8 @@ public enum BaseStat
CON(Stat.STAT_CON), CON(Stat.STAT_CON),
MEN(Stat.STAT_MEN); MEN(Stat.STAT_MEN);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -90,7 +92,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -255,6 +255,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -128,6 +129,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1238,6 +1240,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1268,6 +1272,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1283,6 +1289,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2145,19 +2152,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2221,6 +2216,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2241,6 +2241,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2257,4 +2262,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -38,6 +38,8 @@ public enum BaseStat
CON(Stat.STAT_CON), CON(Stat.STAT_CON),
MEN(Stat.STAT_MEN); MEN(Stat.STAT_MEN);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -90,7 +92,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -255,6 +255,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -151,6 +152,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1314,6 +1316,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1344,6 +1348,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1359,6 +1365,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2436,19 +2443,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2512,6 +2507,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2532,6 +2532,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2548,4 +2553,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -38,6 +38,8 @@ public enum BaseStat
CON(Stat.STAT_CON), CON(Stat.STAT_CON),
MEN(Stat.STAT_MEN); MEN(Stat.STAT_MEN);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -90,7 +92,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -255,6 +255,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -151,6 +152,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1314,6 +1316,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1344,6 +1348,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1359,6 +1365,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2436,19 +2443,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2512,6 +2507,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2532,6 +2532,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2548,4 +2553,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -38,6 +38,8 @@ public enum BaseStat
CON(Stat.STAT_CON), CON(Stat.STAT_CON),
MEN(Stat.STAT_MEN); MEN(Stat.STAT_MEN);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -90,7 +92,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -257,6 +257,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -151,6 +152,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1307,6 +1309,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1337,6 +1341,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1352,6 +1358,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2420,19 +2427,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2496,6 +2491,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2516,6 +2516,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2532,4 +2537,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -38,6 +38,8 @@ public enum BaseStat
CON(Stat.STAT_CON), CON(Stat.STAT_CON),
MEN(Stat.STAT_MEN); MEN(Stat.STAT_MEN);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -90,7 +92,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -257,6 +257,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;

View File

@ -0,0 +1,127 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.cache;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.Stat;
/**
* @author Sahar
*/
public final class PaperdollCache
{
private final Set<ItemInstance> _paperdollItems = ConcurrentHashMap.newKeySet();
private final Map<BaseStat, Double> _baseStatValues = new ConcurrentHashMap<>();
private final Map<Stat, Double> _statValues = new ConcurrentHashMap<>();
private int _maxSetEnchant = -1;
public Set<ItemInstance> getPaperdollItems()
{
return _paperdollItems;
}
public void clearCachedStats()
{
_baseStatValues.clear();
_statValues.clear();
clearMaxSetEnchant();
}
public void clearMaxSetEnchant()
{
_maxSetEnchant = -1;
}
public double getBaseStatValue(PlayerInstance player, final BaseStat stat)
{
final Double baseStatValue = _baseStatValues.get(stat);
if (baseStatValue != null)
{
return baseStatValue;
}
final Set<ArmorSet> appliedSets = new HashSet<>(2);
double value = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
value += set.getStatsBonus(stat);
}
}
}
_baseStatValues.put(stat, value);
return value;
}
public int getMaxSetEnchant(PlayerInstance player)
{
int maxSetEnchant = _maxSetEnchant;
if (maxSetEnchant >= 0)
{
return maxSetEnchant;
}
maxSetEnchant = 0;
for (ItemInstance item : _paperdollItems)
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
_maxSetEnchant = maxSetEnchant;
return maxSetEnchant;
}
public double getStats(Stat stat)
{
final Double statValue = _statValues.get(stat);
if (statValue != null)
{
return statValue;
}
double value = 0;
for (ItemInstance item : _paperdollItems)
{
value += item.getItem().getStats(stat, 0);
}
_statValues.put(stat, value);
return value;
}
}

View File

@ -33,6 +33,7 @@ import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.commons.util.CommonUtil;
import org.l2jmobius.gameserver.cache.PaperdollCache;
import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData; import org.l2jmobius.gameserver.data.xml.impl.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData; import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.datatables.ItemTable; import org.l2jmobius.gameserver.datatables.ItemTable;
@ -123,6 +124,7 @@ public abstract class Inventory extends ItemContainer
private final ItemInstance[] _paperdoll; private final ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners; private final List<PaperdollListener> _paperdollListeners;
private final PaperdollCache _paperdollCache = new PaperdollCache();
// protected to be accessed from child classes only // protected to be accessed from child classes only
protected int _totalWeight; protected int _totalWeight;
@ -1209,6 +1211,8 @@ public abstract class Inventory extends ItemContainer
if (old != null) if (old != null)
{ {
_paperdoll[slot] = null; _paperdoll[slot] = null;
_paperdollCache.getPaperdollItems().remove(old);
// Put old item from paperdoll slot to base location // Put old item from paperdoll slot to base location
old.setItemLocation(getBaseLocation()); old.setItemLocation(getBaseLocation());
old.setLastChange(ItemInstance.MODIFIED); old.setLastChange(ItemInstance.MODIFIED);
@ -1239,6 +1243,8 @@ public abstract class Inventory extends ItemContainer
if (item != null) if (item != null)
{ {
_paperdoll[slot] = item; _paperdoll[slot] = item;
_paperdollCache.getPaperdollItems().add(item);
item.setItemLocation(getEquipLocation(), slot); item.setItemLocation(getEquipLocation(), slot);
item.setLastChange(ItemInstance.MODIFIED); item.setLastChange(ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask(); _wearedMask |= item.getItem().getItemMask();
@ -1254,6 +1260,7 @@ public abstract class Inventory extends ItemContainer
item.updateDatabase(); item.updateDatabase();
} }
_paperdollCache.clearCachedStats();
getOwner().getStat().recalculateStats(!getOwner().isPlayer()); getOwner().getStat().recalculateStats(!getOwner().isPlayer());
if (getOwner().isPlayer()) if (getOwner().isPlayer())
@ -2126,19 +2133,7 @@ public abstract class Inventory extends ItemContainer
} }
final PlayerInstance player = getOwner().getActingPlayer(); final PlayerInstance player = getOwner().getActingPlayer();
int maxSetEnchant = 0; return _paperdollCache.getMaxSetEnchant(player);
for (ItemInstance item : getPaperdollItems())
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
final int enchantEffect = set.getLowestSetEnchant(player);
if (enchantEffect > maxSetEnchant)
{
maxSetEnchant = enchantEffect;
}
}
}
return maxSetEnchant;
} }
public int getWeaponEnchant() public int getWeaponEnchant()
@ -2202,6 +2197,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters) public final Collection<ItemInstance> getPaperdollItems(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2222,6 +2222,11 @@ public abstract class Inventory extends ItemContainer
@SafeVarargs @SafeVarargs
public final int getPaperdollItemCount(Predicate<ItemInstance>... filters) public final int getPaperdollItemCount(Predicate<ItemInstance>... filters)
{ {
if (filters.length == 0)
{
return _paperdollCache.getPaperdollItems().size();
}
Predicate<ItemInstance> filter = Objects::nonNull; Predicate<ItemInstance> filter = Objects::nonNull;
for (Predicate<ItemInstance> additionalFilter : filters) for (Predicate<ItemInstance> additionalFilter : filters)
{ {
@ -2238,4 +2243,9 @@ public abstract class Inventory extends ItemContainer
} }
return count; return count;
} }
public PaperdollCache getPaperdollCache()
{
return _paperdollCache;
}
} }

View File

@ -40,6 +40,8 @@ public enum BaseStat
CHA(Stat.STAT_CHA), CHA(Stat.STAT_CHA),
LUC(Stat.STAT_LUC); LUC(Stat.STAT_LUC);
private static final BaseStat[] VALUES = BaseStat.values();
public static final int MAX_STAT_VALUE = 201; public static final int MAX_STAT_VALUE = 201;
private final double[] _bonus = new double[MAX_STAT_VALUE]; private final double[] _bonus = new double[MAX_STAT_VALUE];
@ -92,7 +94,7 @@ public enum BaseStat
public static BaseStat valueOf(Stat stat) public static BaseStat valueOf(Stat stat)
{ {
for (BaseStat baseStat : values()) for (BaseStat baseStat : VALUES)
{ {
if (baseStat.getStat() == stat) if (baseStat.getStat() == stat)
{ {

View File

@ -92,10 +92,7 @@ public interface IStatFunction
final Inventory inv = creature.getInventory(); final Inventory inv = creature.getInventory();
if (inv != null) if (inv != null)
{ {
for (ItemInstance item : inv.getPaperdollItems()) baseValue += inv.getPaperdollCache().getStats(stat);
{
baseValue += item.getItem().getStats(stat, 0);
}
} }
} }

View File

@ -16,15 +16,10 @@
*/ */
package org.l2jmobius.gameserver.model.stats.finalizers; package org.l2jmobius.gameserver.model.stats.finalizers;
import java.util.HashSet;
import java.util.OptionalDouble; import java.util.OptionalDouble;
import java.util.Set;
import org.l2jmobius.gameserver.data.xml.impl.ArmorSetData;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.stats.BaseStat; import org.l2jmobius.gameserver.model.stats.BaseStat;
import org.l2jmobius.gameserver.model.stats.IStatFunction; import org.l2jmobius.gameserver.model.stats.IStatFunction;
import org.l2jmobius.gameserver.model.stats.Stat; import org.l2jmobius.gameserver.model.stats.Stat;
@ -46,19 +41,9 @@ public class BaseStatFinalizer implements IStatFunction
if (creature.isPlayer()) if (creature.isPlayer())
{ {
final PlayerInstance player = creature.getActingPlayer(); final PlayerInstance player = creature.getActingPlayer();
final Set<ArmorSet> appliedSets = new HashSet<>(2);
// Armor sets calculation // Armor sets calculation
for (ItemInstance item : player.getInventory().getPaperdollItems()) baseValue += player.getInventory().getPaperdollCache().getBaseStatValue(player, BaseStat.valueOf(stat));
{
for (ArmorSet set : ArmorSetData.getInstance().getSets(item.getId()))
{
if ((set.getPiecesCountById(player) >= set.getMinimumPieces()) && appliedSets.add(set))
{
baseValue += set.getStatsBonus(BaseStat.valueOf(stat));
}
}
}
// Henna calculation // Henna calculation
baseValue += player.getHennaValue(BaseStat.valueOf(stat)); baseValue += player.getHennaValue(BaseStat.valueOf(stat));

View File

@ -255,6 +255,7 @@ public class RequestEnchantItem implements IClientIncomingPacket
} }
}); });
} }
player.getInventory().getPaperdollCache().clearMaxSetEnchant();
player.broadcastUserInfo(); // update user info player.broadcastUserInfo(); // update user info
} }
break; break;