Add sponsorship. Ignore Entity CommandSenders, support ignoring player invenoties on clone.

This commit is contained in:
Olof Larsson 2016-04-15 15:32:03 +02:00
parent 712a1ab0f4
commit 9dddbe01dc
No known key found for this signature in database
GPG Key ID: BBEF14F97DA52474
14 changed files with 548 additions and 16 deletions

View File

@ -13,7 +13,6 @@ permissions:
massivecore.basecommand: {description: use the MassiveCore base command, default: false}
massivecore.test: {description: run developer test, default: false}
massivecore.id: {description: see the server id, default: false}
massivecore.version: {description: diplay plugin version, default: false}
massivecore.hearsound: {description: hear a sound, default: false}
massivecore.store: {description: use the mstore command, default: false}
massivecore.store.stats: {description: show mstore statistics, default: false}
@ -41,8 +40,10 @@ permissions:
massivecore.buffer.add: {description: add to buffer, default: false}
massivecore.buffer.whitespace: {description: add whitespace to buffer, default: false}
massivecore.cmdurl: {description: run all lines of url content, default: false}
massivecore.click: {description: click, default: false}
massivecore.config: {description: edit config, default: false}
massivecore.sponsor: {description: toggle sponsor message, default: false}
massivecore.click: {description: click, default: false}
massivecore.version: {description: diplay plugin version, default: false}
# misc
massivecore.notpdelay: {description: teleport without delay, default: false}
massivecore.variable.book: {description: replace ***book*** with content of book in your hand, default: false}
@ -56,7 +57,6 @@ permissions:
massivecore.basecommand: true
massivecore.test: true
massivecore.id: true
massivecore.version: true
massivecore.hearsound: true
massivecore.store: true
massivecore.store.stats: true
@ -84,8 +84,10 @@ permissions:
massivecore.buffer.add: true
massivecore.buffer.whitespace: true
massivecore.cmdurl: true
massivecore.click: true
massivecore.config: true
massivecore.sponsor: true
massivecore.click: true
massivecore.version: true
massivecore.notpdelay: true
massivecore.variable.book: true
massivecore.variable.buffer: true

View File

@ -12,6 +12,7 @@ import com.massivecraft.massivecore.command.MassiveCommand;
import com.massivecraft.massivecore.command.massivecore.CmdMassiveCore;
import com.massivecraft.massivecore.command.requirement.Requirement;
import com.massivecraft.massivecore.command.requirement.RequirementAbstract;
import com.massivecraft.massivecore.command.requirement.RequirementIsPlayer;
import com.massivecraft.massivecore.mson.Mson;
import com.massivecraft.massivecore.mson.MsonEvent;
@ -69,8 +70,8 @@ public class Button
// Requirements to always be validated.
private List<Requirement> requirements = new MassiveList<>();
public List<Requirement> getRequirements() { return this.requirements; }
public Button setRequirements(Collection<Requirement> requirements) { this.requirements = new MassiveList<>(requirements); return this; }
public Button setRequirements(Requirement... requirements) { this.setRequirements(Arrays.asList(requirements)); return this; }
public Button addRequirements(Collection<Requirement> requirements) { this.requirements.addAll(requirements); return this; }
public Button addRequirements(Requirement... requirements) { this.addRequirements(Arrays.asList(requirements)); return this; }
// -------------------------------------------- //
// FIELDS > COMMAND
@ -120,6 +121,8 @@ public class Button
{
// Get Requirements
List<Requirement> requirements = new MassiveList<>();
requirements.add(RequirementIsPlayer.get());
requirements.addAll(this.getRequirements());
if (this.getCommand() != null) requirements.addAll(this.getCommand().getRequirements());
// Check Requirements

View File

@ -0,0 +1,112 @@
package com.massivecraft.massivecore;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.enchantments.Enchantment;
import com.massivecraft.massivecore.collections.MassiveListDef;
import com.massivecraft.massivecore.collections.MassiveMapDef;
public class ItemData
{
// -------------------------------------------- //
// CONSTANTS
// -------------------------------------------- //
// Immutable Defaults
public static final transient int DEFAULT_ID = 0;
public static final transient int DEFAULT_COUNT = 1;
public static final transient int DEFAULT_DAMAGE = 0;
public static final transient boolean DEFAULT_SCALING = false;
// -------------------------------------------- //
// FIELDS > BASIC
// -------------------------------------------- //
private Integer id = null;
public int getId() { return (this.id == null ? DEFAULT_ID : this.id); }
public ItemData setId(int id) { this.id = (id == DEFAULT_ID ? null : id); return this; }
private Integer count = null;
public int getCount() { return (this.count == null ? DEFAULT_COUNT : this.count); }
public ItemData setCount(int count) { this.count = (count == DEFAULT_COUNT ? null : count); return this; }
private Integer damage = null;
public int getDamage() { return (this.damage == null ? DEFAULT_DAMAGE : this.damage); }
public ItemData setDamage(int damage) { this.damage = (damage == DEFAULT_DAMAGE ? null: damage); return this; }
// -------------------------------------------- //
// FIELDS > UNSPECIFIC
// -------------------------------------------- //
private String name = null;
public String getName() { return this.name; }
public ItemData setName(String name) { this.name = name; return this; }
private MassiveListDef<String> lore = new MassiveListDef<>();
public List<String> getLore() { return this.lore; }
public ItemData setLore(Collection<String> lore) { this.lore = new MassiveListDef<>(lore); return this;}
private MassiveMapDef<Enchantment, Integer> enchants = new MassiveMapDef<>();
public Map<Enchantment, Integer> getEnchants() { return this.enchants; }
public ItemData setEnchants(Map<Enchantment, Integer> enchants) { this.enchants = new MassiveMapDef<>(enchants); return this; }
private Integer repaircost = null;
public Integer getRepaircost() { return this.repaircost; }
public ItemData setRepaircost(int repaircost) { this.repaircost = repaircost; return this; }
// -------------------------------------------- //
// FIELDS > BOOK
// -------------------------------------------- //
private String title = null;
public String getTitle() { return this.title; }
public ItemData setTitle(String title) { this.title = title; return this; }
private String author = null;
public String getAuthor() { return this.author; }
public ItemData setAuthor(String author) { this.author = author; return this; }
private MassiveListDef<String> pages = new MassiveListDef<>();
public List<String> getPages() { return this.pages; }
public ItemData setPages(Collection<String> bookPages) { this.pages = new MassiveListDef<>(bookPages); return this; }
// -------------------------------------------- //
// FIELDS > LEATHER ARMOR
// -------------------------------------------- //
private Color color = null;
public Color getColor() { return (this.color == null ? Bukkit.getItemFactory().getDefaultLeatherColor() : this.color); }
public ItemData setColor(Color color) { this.color = (Bukkit.getItemFactory().getDefaultLeatherColor().equals(color) ? null : color); return this; }
// -------------------------------------------- //
// FIELDS > MAP
// -------------------------------------------- //
private Boolean scaling = null;
public boolean isScaling() { return (this.scaling == null ? DEFAULT_SCALING : this.scaling); }
public ItemData setScaling(boolean scaling) { this.scaling = (scaling == DEFAULT_SCALING ? null : scaling); return this; }
// -------------------------------------------- //
// FIELDS > ...
// -------------------------------------------- //
// TODO: Add all the fields
// -------------------------------------------- //
// CONVERT
// -------------------------------------------- //
// TODO: Add in covert methods... they will have to use mixins for transfering!
// -------------------------------------------- //
// HASH CODE & EQUALS
// -------------------------------------------- //
// TODO
}

View File

@ -56,6 +56,7 @@ import com.massivecraft.massivecore.engine.EngineMassiveCorePlayerLeave;
import com.massivecraft.massivecore.engine.EngineMassiveCorePlayerState;
import com.massivecraft.massivecore.engine.EngineMassiveCorePlayerUpdate;
import com.massivecraft.massivecore.engine.EngineMassiveCoreScheduledTeleport;
import com.massivecraft.massivecore.engine.EngineMassiveCoreSponsor;
import com.massivecraft.massivecore.engine.EngineMassiveCoreTeleportMixinCause;
import com.massivecraft.massivecore.engine.EngineMassiveCoreVariable;
import com.massivecraft.massivecore.engine.EngineMassiveCoreWorldNameSet;
@ -207,6 +208,7 @@ public class MassiveCore extends MassivePlugin
MultiverseColl.get(),
AspectColl.get(),
MassiveCoreMConfColl.get(),
MassiveCoreMSponsorInfoColl.get(),
// Engine
EngineMassiveCoreChestGui.get(),
@ -223,6 +225,7 @@ public class MassiveCore extends MassivePlugin
EngineMassiveCoreTeleportMixinCause.get(),
EngineMassiveCoreVariable.get(),
EngineMassiveCoreWorldNameSet.get(),
EngineMassiveCoreSponsor.get(),
// Util
PlayerUtil.get(),

View File

@ -116,4 +116,11 @@ public class MassiveCoreMConf extends Entity<MassiveCoreMConf>
@EditorType(fieldName = "iOn")
public boolean warnOnLocalAlter = false;
// -------------------------------------------- //
// SPONSOR
// -------------------------------------------- //
public boolean sponsorEnabled = true;
public long sponsorUpdateMillis = 0;
}

View File

@ -14,7 +14,7 @@ public class MassiveCoreMConfColl extends Coll<MassiveCoreMConf>
public static MassiveCoreMConfColl get() { return i; }
private MassiveCoreMConfColl()
{
super("massivecore_mconf", MassiveCoreMConf.class, MStore.getDb(ConfServer.dburi), MassiveCore.get());
super("massivecore_mconf", MassiveCoreMConf.class, MStore.getDb(), MassiveCore.get());
}
// -------------------------------------------- //

View File

@ -0,0 +1,166 @@
package com.massivecraft.massivecore;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import org.bukkit.Bukkit;
import com.massivecraft.massivecore.collections.MassiveList;
import com.massivecraft.massivecore.store.Entity;
import com.massivecraft.massivecore.util.TimeUnit;
import com.massivecraft.massivecore.util.Txt;
import com.massivecraft.massivecore.util.WebUtil;
public class MassiveCoreMSponsorInfo extends Entity<MassiveCoreMSponsorInfo>
{
// -------------------------------------------- //
// META
// -------------------------------------------- //
protected static transient MassiveCoreMSponsorInfo i;
public static MassiveCoreMSponsorInfo get() { return i; }
// -------------------------------------------- //
// COMMON
// -------------------------------------------- //
public boolean enabled = true;
public long enabledToMillis = 1473890400000L;
public List<String> indicatorFileNames = new MassiveList<>(
"/home/smpicnic"
);
// -------------------------------------------- //
// CONSOLE
// -------------------------------------------- //
public boolean consoleEnabled = true;
public int consoleDelayTicks = 100;
public List<String> consoleMsgs = new MassiveList<>(
"",
"<pink>____----====[ <aqua>Sponsored by ServerMiner<pink> ]====----____",
"<lime>Get <gold>20% off<lime> a Premium Minecraft Server at ServerMiner:",
"<aqua>https://ServerMiner.com/?p=MassiveCraft",
"",
"<lime>Factions and MassiveCore is sponsored by ServerMiner.com!",
"<lime>They help us fund the development of new plugin features.",
"<lime>Use the promo code <gold>MassiveCraft<lime> to get a <gold>20% discount<lime>.",
"",
"<i>Only server operators get this message, not regular players.",
"<i>Type <c>/mcore sponsor<i> to disable it.",
"" // NOTE: an empty line like this makes sense in console but not for players.
);
// -------------------------------------------- //
// INGAME
// -------------------------------------------- //
public boolean ingameEnabled = true;
public int ingameDelayTicks = 600;
public List<String> ingameMsgs = new MassiveList<>(
"",
"<pink>____----====[ <aqua>Sponsored by ServerMiner<pink> ]====----____",
"<lime>Get <gold>20% off<lime> a Premium Minecraft Server at ServerMiner:",
"<aqua>https://ServerMiner.com/?p=MassiveCraft",
"",
"<lime>Factions and MassiveCore is sponsored by ServerMiner.com!",
"<lime>They help us fund the development of new plugin features.",
"<lime>Use the promo code <gold>MassiveCraft<lime> to get a <gold>20% discount<lime>.",
"",
"<i>Only server operators get this message, not regular players.",
"<i>Type <c>/mcore sponsor<i> to disable it."
);
public List<SoundEffect> ingameSoundEffects = new MassiveList<>(
SoundEffect.valueOf(
"ENTITY_PLAYER_LEVELUP",
1.0F,
0.8F
),
SoundEffect.valueOf(
"ENTITY_EXPERIENCE_ORB_PICKUP",
1.0F,
0.8F
)
);
public String ingameLink = "https://ServerMiner.com/?p=MassiveCraft";
// -------------------------------------------- //
// UPDATE
// -------------------------------------------- //
public static final transient long SPONSOR_INFO_UPDATE_MILLIS = TimeUnit.MILLIS_PER_HOUR;
public static final transient URL SPONSOR_INFO_URL;
static
{
URL url = null;
try
{
url = new URL("http://sponsorinfo.massivecraft.com/1/");
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
SPONSOR_INFO_URL = url;
}
public static void update()
{
// If enough time has passed since last update ...
long now = System.currentTimeMillis();
long last = MassiveCoreMConf.get().sponsorUpdateMillis;
long since = now - last;
if (since < SPONSOR_INFO_UPDATE_MILLIS) return;
// ... then mark update ...
MassiveCoreMConf.get().sponsorUpdateMillis = now;
MassiveCoreMConf.get().changed();
// ... and start the update.
updateInner();
}
public static void updateInner()
{
Bukkit.getScheduler().runTaskAsynchronously(MassiveCore.get(), new Runnable()
{
@Override
public void run()
{
List<String> lines;
try
{
lines = WebUtil.getLines(SPONSOR_INFO_URL);
}
catch (IOException e)
{
e.printStackTrace();
return;
}
final String json = Txt.implode(lines, "\n");
Bukkit.getScheduler().runTask(MassiveCore.get(), new Runnable()
{
@Override
public void run()
{
MassiveCoreMSponsorInfo web = MassiveCore.get().getGson().fromJson(json, MassiveCoreMSponsorInfo.class);
MassiveCoreMSponsorInfo live = MassiveCoreMSponsorInfo.get();
live.load(web);
live.changed();
}
});
}
});
}
}

View File

@ -0,0 +1,43 @@
package com.massivecraft.massivecore;
import com.massivecraft.massivecore.store.Coll;
import com.massivecraft.massivecore.store.MStore;
public class MassiveCoreMSponsorInfoColl extends Coll<MassiveCoreMSponsorInfo>
{
// -------------------------------------------- //
// INSTANCE & CONSTRUCT
// -------------------------------------------- //
private static MassiveCoreMSponsorInfoColl i = new MassiveCoreMSponsorInfoColl();
public static MassiveCoreMSponsorInfoColl get() { return i; }
private MassiveCoreMSponsorInfoColl()
{
super("massivecore_msponsorinfo", MassiveCoreMSponsorInfo.class, MStore.getDb(), MassiveCore.get());
}
// -------------------------------------------- //
// STACK TRACEABILITY
// -------------------------------------------- //
@Override
public void onTick()
{
super.onTick();
}
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public void setActive(boolean active)
{
super.setActive(active);
if ( ! active) return;
MassiveCoreMSponsorInfo.i = this.get(MassiveCore.INSTANCE, true);
}
}

View File

@ -42,10 +42,12 @@ public enum MassiveCorePerm
BUFFER_WHITESPACE,
CMDURL,
CONFIG,
SPONSOR,
CLICK,
NOTPDELAY,
VARIABLE_BOOK,
VARIABLE_BUFFER,
CLICK,
// END OF LIST
;

View File

@ -31,8 +31,9 @@ public class CmdMassiveCore extends MassiveCommand
public CmdMassiveCoreHearsound cmdMassiveCoreHearsound = new CmdMassiveCoreHearsound();
public CmdMassiveCoreBuffer cmdMassiveCoreBuffer = new CmdMassiveCoreBuffer();
public CmdMassiveCoreCmdurl cmdMassiveCoreCmdurl = new CmdMassiveCoreCmdurl();
public CmdMassiveCoreClick cmdMassiveCoreClick = new CmdMassiveCoreClick();
public CommandEditAbstract<MassiveCoreMConf, MassiveCoreMConf> cmdMassiveCoreConfig = new CommandEditSingleton<>(MassiveCoreMConf.get(), MassiveCorePerm.CONFIG.node);
public CmdMassiveCoreSponsor cmdMassiveCoreSponsor = new CmdMassiveCoreSponsor();
public CmdMassiveCoreClick cmdMassiveCoreClick = new CmdMassiveCoreClick();
public MassiveCommandVersion cmdMassiveCoreVersion = new MassiveCommandVersion(MassiveCore.get(), MassiveCorePerm.VERSION.node, "v", "version");
// -------------------------------------------- //
@ -52,8 +53,9 @@ public class CmdMassiveCore extends MassiveCommand
this.addChild(this.cmdMassiveCoreHearsound);
this.addChild(this.cmdMassiveCoreBuffer);
this.addChild(this.cmdMassiveCoreCmdurl);
this.addChild(this.cmdMassiveCoreClick);
this.addChild(this.cmdMassiveCoreConfig);
this.addChild(this.cmdMassiveCoreSponsor);
this.addChild(this.cmdMassiveCoreClick);
this.addChild(this.cmdMassiveCoreVersion);
// Requirements

View File

@ -0,0 +1,47 @@
package com.massivecraft.massivecore.command.massivecore;
import com.massivecraft.massivecore.MassiveCoreMConf;
import com.massivecraft.massivecore.MassiveCorePerm;
import com.massivecraft.massivecore.command.MassiveCommandToggle;
import com.massivecraft.massivecore.command.requirement.RequirementHasPerm;
public class CmdMassiveCoreSponsor extends MassiveCommandToggle
{
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static CmdMassiveCoreSponsor i = new CmdMassiveCoreSponsor();
public static CmdMassiveCoreSponsor get() { return i; }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public CmdMassiveCoreSponsor()
{
// Aliases
this.addAliases("sponsor");
// Requirements
this.addRequirements(RequirementHasPerm.get(MassiveCorePerm.SPONSOR.node));
}
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public boolean getValue()
{
return MassiveCoreMConf.get().sponsorEnabled;
}
@Override
public void setValue(boolean value)
{
MassiveCoreMConf.get().sponsorEnabled = value;
MassiveCoreMConf.get().changed();
}
}

View File

@ -0,0 +1,137 @@
package com.massivecraft.massivecore.engine;
import java.io.File;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerJoinEvent;
import com.massivecraft.massivecore.Engine;
import com.massivecraft.massivecore.MassiveCoreMConf;
import com.massivecraft.massivecore.MassiveCoreMSponsorInfo;
import com.massivecraft.massivecore.SoundEffect;
import com.massivecraft.massivecore.mixin.MixinDisplayName;
import com.massivecraft.massivecore.mixin.MixinMessage;
import com.massivecraft.massivecore.mson.Mson;
import com.massivecraft.massivecore.util.IdUtil;
import com.massivecraft.massivecore.util.Txt;
public class EngineMassiveCoreSponsor extends Engine
{
// -------------------------------------------- //
// INSTANCE & CONSTRUCT
// -------------------------------------------- //
private static EngineMassiveCoreSponsor i = new EngineMassiveCoreSponsor();
public static EngineMassiveCoreSponsor get() { return i; }
public EngineMassiveCoreSponsor()
{
this.setPeriod(1L);
}
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public void setActiveInner(boolean active)
{
if ( ! active) return;
this.inform(IdUtil.getConsole());
}
// -------------------------------------------- //
// UPDATE
// -------------------------------------------- //
@Override
public void run()
{
MassiveCoreMSponsorInfo.update();
}
// -------------------------------------------- //
// INFORM
// -------------------------------------------- //
public void inform(final CommandSender sender)
{
// If enabled by mconf ...
if ( ! MassiveCoreMConf.get().sponsorEnabled) return;
// ... and enabled by info base ...
if ( ! MassiveCoreMSponsorInfo.get().enabled) return;
// ... and enabled by info time ...
long now = System.currentTimeMillis();
long to = MassiveCoreMSponsorInfo.get().enabledToMillis;
long left = to - now;
if (left <= 0) return;
// ... and enabled by sender type ...
boolean isConsole = IdUtil.isConsole(sender);
boolean enabledByType = (isConsole ? MassiveCoreMSponsorInfo.get().consoleEnabled : MassiveCoreMSponsorInfo.get().ingameEnabled);
if ( ! enabledByType) return;
// ... and enabled by sender operator ...
if ( ! sender.isOp()) return;
// ... and enabled by in indicator files ...
for (String indicatorFileName : MassiveCoreMSponsorInfo.get().indicatorFileNames)
{
File indicatorFile = new File(indicatorFileName);
if (indicatorFile.exists()) return;
}
// ... then schedule inner inform.
int delayTicks = (isConsole ? MassiveCoreMSponsorInfo.get().consoleDelayTicks : MassiveCoreMSponsorInfo.get().ingameDelayTicks);
Bukkit.getScheduler().runTaskLater(this.getPlugin(), new Runnable()
{
@Override
public void run()
{
informInner(sender);
}
}, delayTicks);
}
public void informInner(CommandSender sender)
{
// Console?
boolean isConsole = IdUtil.isConsole(sender);
// Messages
List<String> msgs = (isConsole ? MassiveCoreMSponsorInfo.get().consoleMsgs : MassiveCoreMSponsorInfo.get().ingameMsgs);
String senderVisual = MixinDisplayName.get().getDisplayName(sender, sender);
for (String msg : msgs)
{
String message = Txt.parse(msg);
message = message.replace("{p}", senderVisual);
Mson mson = Mson.fromParsedMessage(message).link(MassiveCoreMSponsorInfo.get().ingameLink);
MixinMessage.get().messageOne(sender, mson);
}
// Sound
if (sender instanceof Player)
{
Player player = (Player)sender;
SoundEffect.runAll(MassiveCoreMSponsorInfo.get().ingameSoundEffects, player);
}
}
// -------------------------------------------- //
// LISTENER
// -------------------------------------------- //
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerJoin(PlayerJoinEvent event)
{
this.inform(event.getPlayer());
}
}

View File

@ -16,6 +16,7 @@ import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@ -678,6 +679,12 @@ public class IdUtil implements Listener, Runnable
{
if (sender instanceof Player) return ((Player) sender).getUniqueId().toString();
if (sender instanceof ConsoleCommandSender) return CONSOLE_ID;
// We blacklist all entities other than players.
// This is because all entities are CommandSenders since Minecraft 1.9.
// We do not want Arrows with id "arrow" in the database.
if (sender instanceof Entity) return null;
return sender.getName().toLowerCase();
}

View File

@ -379,7 +379,7 @@ public class InventoryUtil
return ret;
}
public static Inventory cloneInventory(Inventory inventory)
public static Inventory cloneInventory(Inventory inventory, boolean playerSupport)
{
if (inventory == null) return null;
@ -389,7 +389,7 @@ public class InventoryUtil
InventoryHolder holder = inventory.getHolder();
String title = inventory.getTitle();
if (inventory instanceof PlayerInventory)
if (playerSupport && inventory instanceof PlayerInventory)
{
PlayerInventory pret = Mixin.createPlayerInventory();
ret = pret;
@ -412,9 +412,9 @@ public class InventoryUtil
return ret;
}
public static PlayerInventory cloneInventory(PlayerInventory inventory)
public static PlayerInventory cloneInventory(PlayerInventory inventory, boolean playerSupport)
{
return (PlayerInventory)cloneInventory((Inventory)inventory);
return (PlayerInventory)cloneInventory((Inventory)inventory, playerSupport);
}
// -------------------------------------------- //
@ -493,7 +493,8 @@ public class InventoryUtil
// NOTE: This method does not alter the inventory.
public static int roomLeft(Inventory inventory, ItemStack item, int limit)
{
inventory = cloneInventory(inventory);
// NOTE: We can not afford to clone player inventories here.
inventory = cloneInventory(inventory, false);
int ret = 0;
while (limit <= 0 || ret < limit)
{