/* * This file is part of NeptuneVanilla, licensed under the MIT License (MIT). * * Copyright (c) 2015-2017, Jamie Mansfield <https://github.com/jamierocks> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.neptunepowered.vanilla.mixin.minecraft.entity.player; import static net.canarymod.Canary.log; import co.aikar.timings.NeptuneTimings; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.mojang.authlib.GameProfile; import net.canarymod.Canary; import net.canarymod.ToolBox; import net.canarymod.api.GameMode; import net.canarymod.api.NetServerHandler; import net.canarymod.api.PlayerListAction; import net.canarymod.api.PlayerListData; import net.canarymod.api.chat.ChatComponent; import net.canarymod.api.entity.EntityType; import net.canarymod.api.entity.living.humanoid.Player; import net.canarymod.api.inventory.Inventory; import net.canarymod.api.inventory.Item; import net.canarymod.api.packet.Packet; import net.canarymod.api.statistics.Achievement; import net.canarymod.api.statistics.Achievements; import net.canarymod.api.statistics.Stat; import net.canarymod.api.statistics.Statistics; import net.canarymod.api.world.blocks.Sign; import net.canarymod.api.world.position.Direction; import net.canarymod.api.world.position.Location; import net.canarymod.chat.ChatFormat; import net.canarymod.config.Configuration; import net.canarymod.hook.command.PlayerCommandHook; import net.canarymod.hook.player.ChatHook; import net.canarymod.hook.player.PlayerDeathHook; import net.canarymod.hook.player.ReturnFromIdleHook; import net.canarymod.hook.player.TeleportHook; import net.canarymod.hook.system.PermissionCheckHook; import net.canarymod.permissionsystem.PermissionProvider; import net.canarymod.user.Group; import net.canarymod.user.UserAndGroupsProvider; import net.canarymod.warp.Warp; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.PlayerCapabilities; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.NetHandlerPlayServer; import net.minecraft.network.play.server.S02PacketChat; import net.minecraft.network.play.server.S38PacketPlayerListItem; import net.minecraft.network.play.server.S39PacketPlayerAbilities; import net.minecraft.network.play.server.S45PacketTitle; import net.minecraft.scoreboard.IScoreObjectiveCriteria; import net.minecraft.scoreboard.Score; import net.minecraft.scoreboard.ScoreObjective; import net.minecraft.scoreboard.Team; import net.minecraft.server.MinecraftServer; import net.minecraft.server.management.ItemInWorldManager; import net.minecraft.stats.StatBase; import net.minecraft.stats.StatList; import net.minecraft.stats.StatisticsFile; import net.minecraft.tileentity.TileEntitySign; import net.minecraft.util.DamageSource; import net.minecraft.util.IChatComponent; import net.minecraft.world.WorldServer; import net.minecraft.world.WorldSettings; import net.visualillusionsent.utils.DateUtils; import net.visualillusionsent.utils.StringUtils; import org.neptunepowered.vanilla.interfaces.minecraft.network.IMixinNetHandlerPlayServer; import org.neptunepowered.vanilla.interfaces.minecraft.util.IMixinFoodStats; import org.neptunepowered.vanilla.util.NbtConstants; import org.neptunepowered.vanilla.util.PermissionConstants; import org.neptunepowered.vanilla.util.converter.GameModeConverter; import org.neptunepowered.vanilla.util.converter.PlayerListActionConverter; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Implements; import org.spongepowered.asm.mixin.Interface; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @Mixin(EntityPlayerMP.class) @Implements(@Interface(iface = Player.class, prefix = "player$")) public abstract class MixinEntityPlayerMP extends MixinEntityPlayer implements Player { private static Pattern BAD_CHAT_PATTERN = Pattern.compile("[\u2302\u00D7\u00AA\u00BA\u00AE\u00AC\u00BD\u00BC\u00A1\u00AB\u00BB]"); private static String CHAT_FORMAT = Configuration.getServerConfig().getChatFormat().replace("&", ChatFormat.MARKER.toString()); @Shadow @Final public MinecraftServer mcServer; @Shadow @Final public ItemInWorldManager theItemInWorldManager; @Shadow @Final private StatisticsFile statsFile; @Shadow private String translator; @Shadow public int ping; @Shadow public NetHandlerPlayServer playerNetServerHandler; @Shadow private long playerLastActiveTime; private List<Group> groups; private PermissionProvider permissions; private boolean muted = false; private HashMap<String, String> defaultChatPattern = Maps.newHashMap(); private long currentSessionStart = ToolBox.getUnixTimestamp(); @Shadow public abstract void openEditSign(TileEntitySign signTile); @Shadow public abstract void closeScreen(); @Shadow public abstract String getPlayerIP(); @Inject(method = "<init>", at = @At("RETURN")) public void onConstruction(MinecraftServer server, WorldServer worldIn, GameProfile profile, ItemInWorldManager interactionManager, CallbackInfo info) { this.initPlayerData(); } @Inject(method = "markPlayerActive", at = @At("INVOKE")) public void onMarkPlayerActive(CallbackInfo info) { final long idleTime = MinecraftServer.getCurrentTimeMillis() - this.playerLastActiveTime; if (idleTime > 10000) { new ReturnFromIdleHook(this, idleTime).call(); } } /** * @author jamierocks - 2nd October 2016 * @reason Overwrite to use Canary's {@link Configuration} rather than the original server.properties * and fire the {@link PlayerDeathHook}. */ @Overwrite public void onDeath(DamageSource cause) { // Neptune - PlayerDeathHook start PlayerDeathHook hook = (PlayerDeathHook) new PlayerDeathHook( this, (net.canarymod.api.DamageSource) cause, (ChatComponent) this.getCombatTracker().getDeathMessage() ).call(); // Neptune - PlayerDeathHook end //if (this.worldObj.getGameRules().getBoolean("showDeathMessages")) { if (Configuration.getServerConfig().isDeathMessageEnabled()) { // Neptune - Use Canary configuration Team team = this.getTeam(); if (team != null && team.getDeathMessageVisibility() != Team.EnumVisible.ALWAYS) { if (team.getDeathMessageVisibility() == Team.EnumVisible.HIDE_FOR_OTHER_TEAMS) { this.mcServer.getConfigurationManager() .sendMessageToAllTeamMembers((EntityPlayerMP) (Object) this, (IChatComponent) hook.getDeathMessage1()); } else if (team.getDeathMessageVisibility() == Team.EnumVisible.HIDE_FOR_OWN_TEAM) { this.mcServer.getConfigurationManager().sendMessageToTeamOrEvryPlayer( (EntityPlayerMP) (Object) this, (IChatComponent) hook.getDeathMessage1()); } } else { this.mcServer.getConfigurationManager().sendChatMsg((IChatComponent) hook.getDeathMessage1()); } } if (!this.worldObj.getGameRules().getBoolean("keepInventory")) { this.inventory.dropAllItems(); } for (ScoreObjective scoreobjective : this.worldObj.getScoreboard().getObjectivesFromCriteria(IScoreObjectiveCriteria.deathCount)) { Score score = this.getWorldScoreboard().getValueFromObjective(this.getName(), scoreobjective); score.func_96648_a(); } EntityLivingBase entitylivingbase = this.getAttackingEntity(); if (entitylivingbase != null) { EntityList.EntityEggInfo entitylist$entityegginfo = EntityList.entityEggs.get(EntityList.getEntityID(entitylivingbase)); if (entitylist$entityegginfo != null) { this.triggerAchievement(entitylist$entityegginfo.field_151513_e); } entitylivingbase.addToPlayerScore((EntityPlayerMP) (Object) this, this.scoreValue); } this.triggerAchievement(StatList.deathsStat); this.func_175145_a(StatList.timeSinceDeathStat); this.getCombatTracker().reset(); } @Override public void initPlayerData() { final UserAndGroupsProvider provider = Canary.usersAndGroups(); final String uuid = this.getUUIDString(); final boolean isNew = !provider.playerExists(uuid); final String[] data = provider.getPlayerData(uuid); final Group[] subs = provider.getModuleGroupsForPlayer(uuid); this.groups = Lists.newLinkedList(); this.groups.add(Canary.usersAndGroups().getGroup(data[1])); for (Group group : subs) { if (group != null) { this.groups.add(group); } } this.permissions = Canary.permissionManager().getPlayerProvider(uuid, this.getWorld().getFqName()); if (data[0] != null && (!data[0].isEmpty() && !data[0].equals(" "))) { this.prefix = ToolBox.stringToNull(data[0]); } if (data[2] != null && !data[2].isEmpty()) { this.muted = Boolean.valueOf(data[2]); } this.defaultChatPattern.put("%prefix", this.getPrefix()); if (isNew || provider.nameChanged(this)) { provider.addOrUpdatePlayerData(this); } } @Override public void chat(final String message) { if (message.length() > 100) { this.kick("Message too long!"); } String out = message.trim(); final Matcher matcher = BAD_CHAT_PATTERN.matcher(out); if (matcher.find() && !this.canIgnoreRestrictions()) { out = out.replaceAll(matcher.group(), ""); } if (out.startsWith("/")) { this.executeCommand(out.split(" ")); } else if (this.isMuted()) { this.notice("You are currently muted!"); } else { final String displayName = this.getDisplayName(); this.defaultChatPattern.put("%name", displayName != null ? displayName : getName()); this.defaultChatPattern.put("%message", out); this.defaultChatPattern.put("%group", this.getGroup().getName()); ChatHook hook = (ChatHook) new ChatHook(this, CHAT_FORMAT, Canary.getServer().getPlayerList(), this.defaultChatPattern).call(); if (hook.isCanceled()) { return; } final String formattedMessage = hook.buildSendMessage(); for (Player player : hook.getReceiverList()) { player.message(formattedMessage); } log.info(ChatFormat.consoleFormat(formattedMessage)); } } @Override public Location getSpawnPosition() { return null; } @Override public void setSpawnPosition(Location spawn) { } @Override public boolean executeCommand(String[] command) { NeptuneTimings.playerCommandTimer.startTiming(); try { PlayerCommandHook commandHook = (PlayerCommandHook) new PlayerCommandHook(this, command).call(); if (commandHook.isCanceled()) { NeptuneTimings.playerCommandTimer.stopTiming(); return true; } String commandName = command[0]; if (commandName.startsWith("/")) { commandName = commandName.substring(1); } if (Canary.commands().parseCommand(this, commandName, command)) { log.info("Command used by " + getName() + ": " + StringUtils.joinString(command, " ", 0)); NeptuneTimings.playerCommandTimer.stopTiming(); return true; } else { log.debug("Vanilla Command Execution..."); NeptuneTimings.playerCommandTimer.stopTiming(); return Canary.getServer().consoleCommand(StringUtils.joinString(command, " ", 0), this); } } catch (Throwable t) { log.error("Exception in command handler!", t); if (this.isAdmin()) { this.message(ChatFormat.RED + "Exception occurred: " + t.getMessage()); } NeptuneTimings.playerCommandTimer.stopTiming(); return false; } } @Override public void sendPacket(Packet packet) { this.getNetServerHandler().sendPacket(packet); } @Override public NetServerHandler getNetServerHandler() { return (NetServerHandler) this.playerNetServerHandler; } @Override public void teleportTo(Location location, TeleportHook.TeleportCause cause) { } @Override public void kick(String reason) { this.playerNetServerHandler.kickPlayerFromServer(reason); } @Override public void kickNoHook(String reason) { ((IMixinNetHandlerPlayServer) this.playerNetServerHandler).kickPlayerFromServerWithoutHook(reason); } @Override public Direction getCardinalDirection() { double degrees = (getRotation() - 180) % 360; if (degrees < 0) { degrees += 360.0; } if (0 <= degrees && degrees < 22.5) { return Direction.NORTH; } else if (22.5 <= degrees && degrees < 67.5) { return Direction.NORTHEAST; } else if (67.5 <= degrees && degrees < 112.5) { return Direction.EAST; } else if (112.5 <= degrees && degrees < 157.5) { return Direction.SOUTHEAST; } else if (157.5 <= degrees && degrees < 202.5) { return Direction.SOUTH; } else if (202.5 <= degrees && degrees < 247.5) { return Direction.SOUTHWEST; } else if (247.5 <= degrees && degrees < 292.5) { return Direction.WEST; } else if (292.5 <= degrees && degrees < 337.5) { return Direction.NORTHWEST; } else if (337.5 <= degrees && degrees < 360.0) { return Direction.NORTH; } else { return Direction.ERROR; } } @Override public int getPing() { return this.ping; } @Override public PlayerListData getPlayerListData(PlayerListAction action) { return new PlayerListData(action, this.getGameProfile(), this.getPing(), this.getMode(), this.getDisplayNameComponent()); } @Override public void sendPlayerListData(PlayerListData data) { final S38PacketPlayerListItem packet = new S38PacketPlayerListItem(PlayerListActionConverter.of(data.getAction())); packet.players.add(packet.new AddPlayerData( data.getProfile(), // gameProfile data.getPing(), // ping GameModeConverter.of(data.getMode()), // gameType (IChatComponent) data.getDisplayName()) // displayName ); this.playerNetServerHandler.sendPacket(packet); } @Override public void refreshCreativeMode() { } @Override public void updateCapabilities() { this.playerNetServerHandler.sendPacket(new S39PacketPlayerAbilities((PlayerCapabilities) this.getCapabilities())); } @Override public void openInventory(Inventory inventory) { } @Override public void createAndOpenWorkbench() { } @Override public void createAndOpenAnvil() { } @Override public void createAndOpenEnchantmentTable(int bookshelves) { } @Override public void openSignEditWindow(Sign sign) { this.openEditSign((TileEntitySign) sign); } @Override public void openBook(Item writtenbook) { } @Override public void closeWindow() { this.closeScreen(); } @Override public void sendChatComponent(ChatComponent chatComponent) { this.playerNetServerHandler.sendPacket(new S02PacketChat((IChatComponent) chatComponent)); } @Override public String getPreviousIP() { if (this.metadata.hasKey("PreviousIP")) { return this.metadata.getString("PreviousIP"); } return "UNKNOWN"; } @Override public void hidePlayer(Player player) { this.getWorld().getEntityTracker().hidePlayer(player, this); } @Override public void hideFrom(Player player) { this.getWorld().getEntityTracker().hidePlayer(this, player); } @Override public void hidePlayerGlobal() { this.getWorld().getEntityTracker().hidePlayerGlobal(this); } @Override public void hideFromAll() { this.getWorld().getEntityTracker().hidePlayerGlobal(this); } @Override public void showPlayer(Player player) { this.getWorld().getEntityTracker().showPlayer(player, this); } @Override public void showTo(Player player) { this.getWorld().getEntityTracker().showPlayer(this, player); } @Override public void showPlayerGlobal() { this.getWorld().getEntityTracker().showPlayerGlobal(this); } @Override public void showToAll() { this.getWorld().getEntityTracker().showPlayerGlobal(this); } @Override public boolean isPlayerHidden(Player player, Player isHidden) { return this.isHiddenFrom(player); } @Override public boolean isHiddenFrom(Player player) { return this.getWorld().getEntityTracker().isPlayerHidden(player, this); } @Override public boolean isHiddenFromAll() { return false; } @Override public void setCompassTarget(int x, int y, int z) { } @Override public GameProfile getGameProfile() { return super.getGameProfile(); } @Override public ChatComponent getDisplayNameComponent() { return null; } @Override public void setDisplayNameComponent(ChatComponent component) { } @Override public Inventory getSecondInventory() { return null; } @Override public void showTitle(ChatComponent title) { this.showTitle(title, null); } @Override public void showTitle(ChatComponent title, ChatComponent subtitle) { if (title != null) { this.playerNetServerHandler.sendPacket(new S45PacketTitle(S45PacketTitle.Type.TITLE, (IChatComponent) title)); if (subtitle != null) { this.playerNetServerHandler.sendPacket(new S45PacketTitle(S45PacketTitle.Type.SUBTITLE, (IChatComponent) subtitle)); } } } @Override public PermissionProvider getPermissionProvider() { return this.permissions; } @Override public Group getGroup() { return this.groups.get(0); } @Override public void setGroup(Group group) { this.groups.set(0, group); Canary.usersAndGroups().addOrUpdatePlayerData(this); this.defaultChatPattern.put("%prefix", this.getPrefix()); // Update Prefix } @Override public String getPrefix() { if (this.prefix != null) { return this.prefix; } else if (this.groups.get(0).getPrefix() != null) { return this.groups.get(0).getPrefix(); } else { return ChatFormat.WHITE.toString(); } } @Override public void setPrefix(String prefix) { super.setPrefix(prefix); Canary.usersAndGroups().addOrUpdatePlayerData(this); this.defaultChatPattern.put("%prefix", this.getPrefix()); } @Override public boolean isOnline() { return Canary.getServer().getPlayer(this.getName()) != null; } @Override public void addGroup(Group group) { if (!this.groups.contains(group)) { this.groups.add(group); Canary.usersAndGroups().addOrUpdatePlayerData(this); } } @Override public boolean removeGroup(Group group) { boolean success = this.groups.remove(group); if (success) { Canary.usersAndGroups().addOrUpdatePlayerData(this); } return success; } @Override public boolean removeGroup(String group) { final Group g = Canary.usersAndGroups().getGroup(group); return g != null && this.removeGroup(g); } @Override public boolean isInGroup(Group group, boolean parents) { for (Group g : this.groups) { if (g.getName().equals(group.getName())) { return true; } if (parents) { for (Group parent : g.parentsToList()) { if (parent.getName().equals(group.getName())) { return true; } } } } return false; } @Override public boolean isInGroup(String group, boolean parents) { for (Group g : this.groups) { if (g.getName().equals(group)) { return true; } if (parents) { for (Group parent : g.parentsToList()) { if (parent.getName().equals(group)) { return true; } } } } return false; } @Override public UUID getUUID() { return EntityPlayer.getUUID(this.getGameProfile()); } @Override public String getUUIDString() { return this.getUUID().toString(); } @Override public boolean isMuted() { return this.muted; } @Override public void setMuted(boolean muted) { this.muted = muted; } @Override public Group[] getPlayerGroups() { return this.groups.toArray(new Group[this.groups.size()]); } @Override public String getFirstJoined() { return this.metadata.getString(NbtConstants.FIRST_JOINED); } @Override public long getTimePlayed() { return this.metadata.getLong(NbtConstants.TIME_PLAYED) + (ToolBox.getUnixTimestamp() - this.currentSessionStart); } @Override public GameMode getMode() { return GameModeConverter.of(this.theItemInWorldManager.getGameType()); } @Override public void setMode(GameMode mode) { this.theItemInWorldManager.setGameType(GameModeConverter.of(mode)); } @Override public int getModeId() { return this.theItemInWorldManager.getGameType().getID(); } @Override public void setModeId(int mode) { this.theItemInWorldManager.setGameType(WorldSettings.GameType.getByID(mode)); } @Override public boolean isOperator() { return Canary.ops().isOpped(this); } @Override public boolean isAdmin() { return this.isOperator() || this.hasPermission(PermissionConstants.Super.ADMINISTRATOR); } @Override public boolean canBuild() { return this.isAdmin() || this.hasPermission(PermissionConstants.World.BUILD); } @Override public void setCanBuild(boolean canModify) { this.permissions.addPermission(PermissionConstants.World.BUILD, canModify); } @Override public boolean canIgnoreRestrictions() { return this.isAdmin() || this.hasPermission(PermissionConstants.Super.IGNORE_RESTRICTIONS); } @Override public void setCanIgnoreRestrictions(boolean canIgnore) { this.permissions.addPermission(PermissionConstants.Super.IGNORE_RESTRICTIONS, canIgnore, -1); } @Override public void addExhaustion(float exhaustion) { ((IMixinFoodStats) this.foodStats).setExhaustionLevel(this.getExhaustionLevel() + exhaustion); } @Override public void setExhaustion(float exhaustion) { ((IMixinFoodStats) this.foodStats).setExhaustionLevel(exhaustion); } @Override public float getExhaustionLevel() { return ((IMixinFoodStats) this.foodStats).getExhaustionLevel(); } @Override public void addSaturation(float saturation) { ((IMixinFoodStats) this.foodStats).setSaturationLevel(this.getSaturationLevel() + saturation); } @Override public void setSaturation(float saturation) { ((IMixinFoodStats) this.foodStats).setSaturationLevel(saturation); } @Override public float getSaturationLevel() { return this.foodStats.getSaturationLevel(); } @Override public int getHunger() { return this.foodStats.getFoodLevel(); } @Override public void setHunger(int hunger) { this.foodStats.setFoodLevel(hunger); } @Override public void addExperience(int experience) { } @Override public void removeExperience(int experience) { } @Override public int getExperience() { return 0; } @Override public void setExperience(int xp) { } @Override public int getLevel() { return 0; } @Override public void setLevel(int level) { } @Override public void addLevel(int level) { } @Override public void removeLevel(int level) { } @Override public Location getHome() { final Warp home = Canary.warps().getHome(this); if (home != null) { return home.getLocation(); } return this.getSpawnPosition(); } @Override public void setHome(Location home) { Canary.warps().setHome(this, home); } @Override public boolean hasHome() { return Canary.warps().getHome(this) != null; } @Override public String[] getAllowedIPs() { return new String[0]; } @Override public String getIP() { return this.getPlayerIP(); } @Override public String getLastJoined() { return this.metadata.getString(NbtConstants.LAST_JOINED); } @Override public void setStat(Stat stat, int value) { this.statsFile.unlockAchievement((EntityPlayerMP) (Object) this, (StatBase) stat, value); } @Override public void setStat(Statistics stat, int value) { this.setStat(stat.getInstance(), value); } @Override public void increaseStat(Stat stat, int value) { if (value < 0) return; this.statsFile.increaseStat((EntityPlayerMP) (Object) this, (StatBase) stat, value); } @Override public void increaseStat(Statistics stat, int value) { this.increaseStat(stat.getInstance(), value); } @Override public void decreaseStat(Stat stat, int value) { if (value < 0) return; this.setStat(stat, this.getStat(stat) - value); } @Override public void decreaseStat(Statistics stat, int value) { this.decreaseStat(stat.getInstance(), value); } @Override public int getStat(Stat stat) { return this.statsFile.readStat((StatBase) stat); } @Override public int getStat(Statistics stat) { return this.getStat(stat.getInstance()); } @Override public boolean hasAchievement(Achievement achievement) { return this.statsFile.hasAchievementUnlocked((net.minecraft.stats.Achievement) achievement); } @Override public boolean hasAchievement(Achievements achievement) { return this.hasAchievement(achievement.getInstance()); } @Override public void removeAchievement(Achievement achievement) { // Ensure all children achievements are removed Arrays.stream(Achievements.values()) .map(Achievements::getInstance).map(Achievement::getParent) .filter(achievement::equals).filter(this::hasAchievement) .forEach(this::removeAchievement); this.statsFile.unlockAchievement((EntityPlayerMP) (Object) this, (StatBase) achievement, 0); } @Override public void removeAchievement(Achievements achievement) { this.removeAchievement(achievement.getInstance()); } @Override public void awardAchievement(Achievement achievement) { // Ensure all parent achievements are awarded if (!this.hasAchievement(achievement.getParent())) { this.awardAchievement(achievement.getParent()); } this.statsFile.unlockAchievement((EntityPlayerMP) (Object) this, (StatBase) achievement, 1); this.statsFile.sendAchievements((EntityPlayerMP) (Object) this); } @Override public void awardAchievement(Achievements achievement) { this.awardAchievement(achievement.getInstance()); } @Override public Inventory getEnderChestInventory() { return (Inventory) this.getEnderChest(); } @Override public boolean hasPermission(String permission) { if (this.isOperator()) { return true; } final PermissionCheckHook hook = new PermissionCheckHook(permission, this, false); // If player has the permission set, use its personal permissions if (this.permissions.pathExists(permission)) { hook.setResult(this.permissions.queryPermission(permission)); Canary.hooks().callHook(hook); return hook.getResult(); } else if (this.groups.size() == 1) { // Only main group is set hook.setResult(this.groups.get(0).hasPermission(permission)); Canary.hooks().callHook(hook); return hook.getResult(); } // Check sub groups for (int i = 1; i < this.groups.size(); i++) { // First group that if (this.groups.get(i).getPermissionProvider().pathExists(permission)) { hook.setResult(this.groups.get(i).hasPermission(permission)); Canary.hooks().callHook(hook); return hook.getResult(); } } // No subgroup has permission defined, use what base group has to say hook.setResult(this.groups.get(0).hasPermission(permission)); Canary.hooks().callHook(hook); return hook.getResult(); } @Override public boolean safeHasPermission(String permission) { if (this.isOperator()) { return true; } // If player has the permission set, use its personal permissions if (this.permissions.pathExists(permission)) { return this.permissions.queryPermission(permission); } else if (this.groups.size() == 1) { // Only main group is set return this.groups.get(0).hasPermission(permission); } // Check sub groups for (int i = 1; i < this.groups.size(); i++) { // First group that if (this.groups.get(i).getPermissionProvider().pathExists(permission)) { return this.groups.get(i).hasPermission(permission); } } // No subgroup has permission defined, use what base group has to say return this.groups.get(0).hasPermission(permission); } @Override public String getLocale() { return this.translator; } @Override public String getFqName() { return "Player"; } @Override public boolean isPlayer() { return true; } @Override public EntityType getEntityType() { return EntityType.PLAYER; } @Override public NBTTagCompound writeCanaryNBT(NBTTagCompound tagCompound) { this.metadata.setLong(NbtConstants.TIME_PLAYED, this.metadata.getLong(NbtConstants.TIME_PLAYED) + (ToolBox.getUnixTimestamp() - this.currentSessionStart)); this.currentSessionStart = ToolBox.getUnixTimestamp(); // Reset time this.metadata.setString(NbtConstants.PREVIOUS_IP, this.getIP()); return super.writeCanaryNBT(tagCompound); } @Override public void initializeMetaData() { if (!this.bukkitData.hasKey(NbtConstants.BUKKIT_FIRST_JOINED)) { this.metadata.setString(NbtConstants.FIRST_JOINED, DateUtils.longToDateTime(System.currentTimeMillis())); } else { this.metadata.setString(NbtConstants.FIRST_JOINED, DateUtils.longToDateTime(this.bukkitData.getLong(NbtConstants.BUKKIT_FIRST_JOINED))); } if (!this.bukkitData.hasKey(NbtConstants.BUKKIT_LAST_JOINED)) { this.metadata.setString(NbtConstants.LAST_JOINED, DateUtils.longToDateTime(System.currentTimeMillis())); } else { this.metadata.setString(NbtConstants.LAST_JOINED, DateUtils.longToDateTime(this.bukkitData.getLong(NbtConstants.BUKKIT_LAST_JOINED))); } this.metadata.setLong(NbtConstants.TIME_PLAYED, 1L); // Initialise to 1 } }