From 2cf59ced8bc2e1ce89118dceea86a4198137cda4 Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 18 Mar 2016 01:18:35 +0000 Subject: [PATCH] new pvp timer management, fixed build house task, fixed incognito --- .../src/mineplex/core/MiniClientPlugin.java | 3 +- .../core/account/CoreClientManager.java | 2 +- .../core/incognito/IncognitoManager.java | 6 -- .../repository/IncognitoRepository.java | 14 ++- .../src/mineplex/game/clans/Clans.java | 2 +- .../game/clans/clans/ClansAlphaManager.java | 75 ---------------- .../game/clans/clans/ClansManager.java | 8 +- .../game/clans/clans/pvptimer/PvpTimer.java | 90 ++++++++++++++----- .../clans/clans/pvptimer/PvpTimerClient.java | 7 +- .../siege/repository/OutpostRepository.java | 3 +- .../repository/SiegeWeaponRepository.java | 3 +- .../game/clans/items/rares/RunedPickaxe.java | 2 +- 12 files changed, 99 insertions(+), 116 deletions(-) delete mode 100644 Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAlphaManager.java diff --git a/Plugins/Mineplex.Core/src/mineplex/core/MiniClientPlugin.java b/Plugins/Mineplex.Core/src/mineplex/core/MiniClientPlugin.java index 397e6d0c5..391e86a54 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/MiniClientPlugin.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/MiniClientPlugin.java @@ -15,7 +15,6 @@ public abstract class MiniClientPlugin extends MiniPlug private NautHashMap _clientData = new NautHashMap(); - public MiniClientPlugin(String moduleName, JavaPlugin plugin) { super(moduleName, plugin); @@ -41,7 +40,7 @@ public abstract class MiniClientPlugin extends MiniPlug return _clientData.get(name); } } - + public void saveData(String name, int accountId) {} public DataType Get(Player player) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java index 1f2dc672d..9ca9c6c37 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java @@ -185,7 +185,7 @@ public class CoreClientManager extends MiniPlugin if (!LoadClient(Add(event.getName()), event.getUniqueId(), event.getAddress().getHostAddress())) event.disallow(Result.KICK_OTHER, "There was a problem logging you in."); } - catch(Exception exception) + catch (Exception exception) { event.disallow(Result.KICK_OTHER, "Error retrieving information from web, please retry in a minute."); exception.printStackTrace(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/incognito/IncognitoManager.java b/Plugins/Mineplex.Core/src/mineplex/core/incognito/IncognitoManager.java index b8e917752..664415263 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/incognito/IncognitoManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/incognito/IncognitoManager.java @@ -64,12 +64,6 @@ public class IncognitoManager extends MiniClientPlugin { other.showPlayer(caller); } - - UtilServer.broadcast(F.sys("Join", caller.getName())); - } - else - { - UtilServer.broadcast(F.sys("Quit", caller.getName())); } runAsync(() -> _repository.SetStatus(_clientManager.getAccountId(caller), enabled)); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/incognito/repository/IncognitoRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/incognito/repository/IncognitoRepository.java index a843aeae7..1032eb809 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/incognito/repository/IncognitoRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/incognito/repository/IncognitoRepository.java @@ -10,9 +10,10 @@ import mineplex.serverdata.database.column.ColumnInt; public class IncognitoRepository extends MinecraftRepository { - private static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS incognitoStaff (accountId INT NOT NULL, status TINYINT(1) DEFAULT '0');"; + private static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS incognitoStaff (accountId INT NOT NULL, status TINYINT(1) DEFAULT '0', PRIMARY KEY (accountId));"; private static final String GET_STATUS = "SELECT * FROM incognitoStaff WHERE accountId = ?;"; - private static final String SET_STATUS = "INSERT INTO incognitoStaff (accountId, status) VALUES (?, ?);"; + private static final String INSERT_STATUS = "INSERT INTO incognitoStaff (accountId, status) VALUES (?, ?);"; + private static final String UPDATE_STATUS = "UPDATE incognitoStaff SET status=? WHERE accountId=?;"; private IncognitoManager _incognitoManager; @@ -29,8 +30,13 @@ public class IncognitoRepository extends MinecraftRepository public void SetStatus(int accountId, boolean status) { - System.out.println("[INCOGNITO] Updated status for " + accountId + " to " + status); - executeUpdate(SET_STATUS, new ColumnInt("accountId", accountId), new ColumnInt("status", status ? 1 : 0)); + // Prevent duplicate entries for individuals + executeQuery(GET_STATUS, result -> { + if (result.next()) + executeUpdate(UPDATE_STATUS, new ColumnInt("status", status ? 1 : 0), new ColumnInt("accountId", accountId)); + else + executeUpdate(INSERT_STATUS, new ColumnInt("accountId", accountId), new ColumnInt("status", status ? 1 : 0)); + }, new ColumnInt("accountId", accountId)); } public boolean GetStatus(int accountId) diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java index 8e0222cd0..e698387d9 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java @@ -55,7 +55,7 @@ import net.minecraft.server.v1_8_R3.MinecraftServer; public class Clans extends JavaPlugin { - public static final String VERSION = "Beta 1.0_01"; + public static final String VERSION = "Beta 1.0"; private String WEB_CONFIG = "webServer"; // Modules diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAlphaManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAlphaManager.java deleted file mode 100644 index df206e60e..000000000 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAlphaManager.java +++ /dev/null @@ -1,75 +0,0 @@ -package mineplex.game.clans.clans; - -import java.util.Arrays; -import java.util.LinkedList; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.player.PlayerJoinEvent; - -import mineplex.core.MiniPlugin; -import mineplex.core.common.util.C; -import mineplex.core.common.util.Callback; -import mineplex.core.common.util.UtilMath; -import mineplex.core.common.util.UtilPlayer; -import mineplex.core.common.util.UtilServer; -import mineplex.core.task.TaskManager; -import mineplex.core.updater.UpdateType; -import mineplex.core.updater.event.UpdateEvent; - -public class ClansAlphaManager extends MiniPlugin -{ - private static final LinkedList> ANNOUNCEMENTS = new LinkedList<>(Arrays.asList(new LinkedList<>(Arrays.asList(C.cDAquaB + "Welcome to Clans Alpha", C.cAqua + "Clans is in early Alpha stages so expect there to be bugs/issues. Please report any bugs to staff, we hope you enjoy this early test!")))); - - private static final boolean RANDOM_ANNOUNCEMENT = true; - - /** - * This is useful if the above boolean (RANDOM_ANNOUNCEMENT) is set to - * false, then the announcement at index SET_ANNOUNCEMENT will be used every - * time. - */ - private static final int SET_ANNOUNCEMENT = 0; - - private static final LinkedList FIRST_JOIN_MESSAGES = new LinkedList<>(ANNOUNCEMENTS.getFirst()); - private static final UpdateType ANNOUNCEMENT_DELAY = UpdateType.MIN_16; - - private TaskManager _taskManager; - - public ClansAlphaManager(ClansManager manager, TaskManager taskManager) - { - super("Announcements", manager.getPlugin()); - - _taskManager = taskManager; - } - - @EventHandler - public void onPlayerJoin(final PlayerJoinEvent event) - { - if (!_taskManager.hasCompletedTask(event.getPlayer(), "ClansAlphaJoinMessage")) - { - _taskManager.completedTask(new Callback() - { - public void run(Boolean data) - { - UtilPlayer.message(event.getPlayer(), FIRST_JOIN_MESSAGES); - } - }, event.getPlayer(), "ClansAlphaJoinMessage"); - } - } - - @EventHandler - public void onUpdate(UpdateEvent event) - { - if (event.getType().equals(ANNOUNCEMENT_DELAY)) - { - if (RANDOM_ANNOUNCEMENT) - { - UtilServer.broadcast(UtilMath.randomElement(ANNOUNCEMENTS)); - } - else - { - UtilServer.broadcast(ANNOUNCEMENTS.get(SET_ANNOUNCEMENT)); - } - } - } - -} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java index bfe579e0b..cc2d28acd 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java @@ -290,7 +290,7 @@ public class ClansManager extends MiniClientPluginimplements IRelati new ClanEnergyTracker(plugin, this); // new StuckManager(this); -// new ClansAlphaManager(this, taskManager); + new ClansBetaManager(this, taskManager); new PotatoManager(plugin, this); @@ -324,7 +324,7 @@ public class ClansManager extends MiniClientPluginimplements IRelati new ClanEnergyManager(plugin, this, clientManager, donationManager); _playTracker = new Playtime(this, statsManager); - _pvpTimer = new PvpTimer(this, _playTracker, statsManager); + _pvpTimer = new PvpTimer(this, statsManager); _tutorialManager = new mineplex.game.clans.legacytutorial.TutorialManager(plugin, _playTracker, _goldManager, taskManager, donationManager, preferencesManager, this, packetHandler); TutorialManager tutorial = new TutorialManager(plugin, clientManager, donationManager, chat); @@ -567,6 +567,10 @@ public class ClansManager extends MiniClientPluginimplements IRelati { UtilServer.broadcast(F.sys("Quit", event.getPlayer().getName())); } + else + { + UtilServer.broadcast(F.sys("Join", event.getPlayer().getName())); + } } @EventHandler diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/pvptimer/PvpTimer.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/pvptimer/PvpTimer.java index 541f3e9e1..af7a06ba3 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/pvptimer/PvpTimer.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/pvptimer/PvpTimer.java @@ -9,30 +9,31 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityShootBowEvent; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; import mineplex.core.MiniClientPlugin; -import mineplex.core.common.jsonchat.ClickEvent; -import mineplex.core.common.jsonchat.JsonMessage; +import mineplex.core.account.CoreClientManager; import mineplex.core.common.util.C; -import mineplex.core.common.util.Callback; import mineplex.core.common.util.F; import mineplex.core.common.util.UtilAction; import mineplex.core.common.util.UtilAlg; import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilTextMiddle; import mineplex.core.common.util.UtilTime; import mineplex.core.stats.StatsManager; -import mineplex.core.task.TaskManager; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; import mineplex.game.clans.clans.ClanTips.TipType; import mineplex.game.clans.clans.ClansManager; import mineplex.game.clans.clans.event.ClanTipEvent; import mineplex.game.clans.clans.event.PlayerEnterTerritoryEvent; -import mineplex.game.clans.clans.playtime.Playtime; import mineplex.game.clans.clans.playtime.command.cemde; import mineplex.game.clans.clans.pvptimer.command.PvPTimerCommand; +import mineplex.game.clans.clans.pvptimer.repository.PvpTimerRepository; +import mineplex.game.clans.clans.pvptimer.repository.TimerClientToken; import mineplex.game.clans.core.repository.ClanTerritory; import mineplex.game.clans.spawn.Spawn; import mineplex.minecraft.game.classcombat.Skill.event.SkillTriggerEvent; @@ -41,20 +42,33 @@ import mineplex.minecraft.game.core.damage.CustomDamageEvent; public class PvpTimer extends MiniClientPlugin { - public static final String SKIPPED_TASK = "PvpTimer.Skipped"; - private final int[] DISPLAY_TIMES = { 5, 10, 30, 1 * 60, 2 * 60, 5 * 60, 10 * 60, 20 * 60 }; + private final int[] DISPLAY_TIMES = { + 5, + 10, + 30, + 1 * 60, + 2 * 60, + 5 * 60, + 10 * 60, + 20 * 60 + }; + + private PvpTimerRepository _repository; + private CoreClientManager _clientManager; private ClansManager _clansManager; - private Playtime _tracker; private static long TIMER_LENGTH = 30 * 60; - public PvpTimer(ClansManager clans, Playtime playtime, StatsManager statsManager) + public PvpTimer(ClansManager clans, StatsManager statsManager) { super("PvP Timer", clans.getPlugin()); - _tracker = playtime; _clansManager = clans; + _clientManager = clans.getClientManager(); + + _repository = new PvpTimerRepository(this, clans.getClientManager()); + addCommand(new cemde(statsManager, this)); } @@ -69,7 +83,7 @@ public class PvpTimer extends MiniClientPlugin Get(caller).Skipped = true; caller.playSound(caller.getLocation(), Sound.ENDERDRAGON_GROWL, 1f, 0.75f); - TaskManager.Instance.completedTask(null, caller, "PvpTimer.Skipped"); + _repository.Save(_clientManager.getAccountId(caller), Get(caller).Skipped, Get(caller).Elapsed); } @EventHandler @@ -89,9 +103,26 @@ public class PvpTimer extends MiniClientPlugin } } + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) + { + runAsync(() -> _repository.Save(_clientManager.getAccountId(event.getPlayer()), Get(event.getPlayer()).Skipped, Get(event.getPlayer()).Elapsed + (int) (elapsed(event.getPlayer()) / 1000))); + } + @EventHandler public void outYouGo(UpdateEvent event) { + if (event.getType() == UpdateType.SLOWER) + { + UtilServer.getPlayersCollection().forEach(player -> { + PvpTimerClient client = Get(player); + + client.StartTime = System.currentTimeMillis(); + + runAsync(() -> _repository.Save(_clientManager.getAccountId(player), client.Skipped, client.Elapsed += (int) (elapsed(player)))); + }); + } + if (event.getType() == UpdateType.SEC) { for (Player player : Bukkit.getOnlinePlayers()) @@ -149,9 +180,9 @@ public class PvpTimer extends MiniClientPlugin } }, 10); - UtilPlayer.message(player, F.main("Clans", "You are currently safe from PvP because you are a new player. This safety will end in " + F.time(UtilTime.MakeStr(getPvPTimerLeft(player) * 1000)))); - UtilPlayer.message(player, F.main("Clans", "Until it ends, you are immune to, and unable to deal PvP damage.")); - UtilPlayer.message(player, F.main("Clans", "If you would like to disable the PvP safety permanently, then type " + F.elem("/pvp") + ".")); + UtilPlayer.message(player, C.cAqua + "You are currently safe from PvP because you are a new player. This safety will end in " + F.time(UtilTime.MakeStr(getPvPTimerLeft(player) * 1000))); + UtilPlayer.message(player, C.cAqua + "Until it ends, you are immune to, and are unable to deal PvP damage."); + UtilPlayer.message(player, C.cAqua + "If you would like to disable the PvP safety permanently, then type " + F.elem("/pvp") + "."); } } @@ -171,17 +202,17 @@ public class PvpTimer extends MiniClientPlugin { UtilPlayer.message(player, F.main("Clans", "PvP Safety has ended!")); UtilPlayer.message(player, F.main("Clans", "You are now completely open to attacks, and you can also attack others.")); - player.playSound(player.getLocation(), Sound.ENDERDRAGON_GROWL, 1f, 0.75f); + player.playSound(player.getLocation(), Sound.ENDERDRAGON_GROWL, 0.2f, 0.75f); continue; } for (int unit : DISPLAY_TIMES) { - if (time <= unit && !client.InformedTimes.contains(unit)) + if (time <= unit && !client.InformedTimes.contains(Integer.valueOf(unit))) { UtilPlayer.message(player, F.main("Clans", "PvP Safety will end in " + F.time(UtilTime.MakeStr(unit * 1000)))); UtilTextMiddle.display(C.cGreen + "Pvp Safety", C.cGray + "ending in " + UtilTime.MakeStr(unit * 1000), 20, 80, 20, player); - client.InformedTimes.add(unit); + client.InformedTimes.add(Integer.valueOf(unit)); } } } @@ -255,7 +286,10 @@ public class PvpTimer extends MiniClientPlugin { if (victimTimer) { - if (!bothMsg) UtilPlayer.message(damager, F.main("Clans", "You and " + F.name(victim.getName()) + " are still under PvP Safety. Type " + F.elem("/pvp") + " to disable.")); + if (!bothMsg) + { + UtilPlayer.message(damager, F.main("Clans", "You and " + F.name(victim.getName()) + " are still under PvP Safety. Type " + F.elem("/pvp") + " to disable.")); + } } else if (damager != null) { @@ -267,13 +301,29 @@ public class PvpTimer extends MiniClientPlugin } + @EventHandler(priority = EventPriority.LOWEST) + public void ClientLoad(AsyncPlayerPreLoginEvent event) + { + _clientManager.getRepository().getAccountId(event.getUniqueId(), accountId -> { + TimerClientToken token = _repository.Get(accountId.intValue()); + + Get(event.getName()).Skipped = token.Skipped; + Get(event.getName()).Elapsed = token.Elapsed; + }); + } + public long getPvPTimerLeft(Player player) { - long time = (_tracker.getPlaytime(player) + _tracker.getUnsavedPlaytime(player)); + long time = Get(player).Elapsed + (elapsed(player) / 1000); return (TIMER_LENGTH <= time ? 0 : TIMER_LENGTH - time); } + public long elapsed(Player player) + { + return System.currentTimeMillis() - Get(player).StartTime; + } + public boolean hasTimer(Player victim) { return victim != null && getPvPTimerLeft(victim) > 0 && !Get(victim).Skipped; @@ -282,6 +332,6 @@ public class PvpTimer extends MiniClientPlugin @Override protected PvpTimerClient AddPlayer(String player) { - return new PvpTimerClient(Bukkit.getPlayer(player)); + return new PvpTimerClient(); } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/pvptimer/PvpTimerClient.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/pvptimer/PvpTimerClient.java index 82df2bd55..6d8563e56 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/pvptimer/PvpTimerClient.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/pvptimer/PvpTimerClient.java @@ -6,15 +6,18 @@ import java.util.List; import org.bukkit.entity.Player; import mineplex.core.task.TaskManager; +import mineplex.game.clans.clans.ClansPlayerTasks; public class PvpTimerClient { public boolean Skipped; public List InformedTimes; + public long StartTime; + public int Elapsed; - public PvpTimerClient(Player player) + public PvpTimerClient() { - Skipped = TaskManager.Instance.hasCompletedTask(player, PvpTimer.SKIPPED_TASK); + StartTime = System.currentTimeMillis(); InformedTimes = new ArrayList<>(); } } diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/OutpostRepository.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/OutpostRepository.java index b3546a110..3bb41f700 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/OutpostRepository.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/OutpostRepository.java @@ -34,7 +34,8 @@ public class OutpostRepository extends MinecraftRepository + "outpostType TINYINT NOT NULL," + "ownerClan INT NOT NULL," + "timeSpawned LONG," - + "outpostState TINYINT NOT NULL);"; + + "outpostState TINYINT NOT NULL," + + "PRIMARY KEY (uniqueId));"; private static final String GET_OUTPOST_BY_ID = "SELECT * FROM clansOutposts WHERE uniqueId=?;"; private static final String GET_OUTPOST_BY_CLAN = "SELECT * FROM clansOutposts WHERE ownerClan=?;"; diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/SiegeWeaponRepository.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/SiegeWeaponRepository.java index f6ff02483..5fc7caca3 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/SiegeWeaponRepository.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/SiegeWeaponRepository.java @@ -32,7 +32,8 @@ public class SiegeWeaponRepository extends MinecraftRepository + "health INT NOT NULL," + "yaw INT NOT NULL," + "lastFired LONG," - + "entities VARCHAR(200));"; + + "entities VARCHAR(200)," + + "PRIMARY KEY (uniqueId));"; private static final String GET_WEAPON_BY_ID = "SELECT * FROM clansSiegeWeapons WHERE uniqueId=?;"; private static final String GET_WEAPONS_BY_CLAN = "SELECT * FROM clansSiegeWeapons WHERE ownerClan=?;"; diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/rares/RunedPickaxe.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/rares/RunedPickaxe.java index 4540a43e2..d8fa5b4bd 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/rares/RunedPickaxe.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/items/rares/RunedPickaxe.java @@ -94,7 +94,7 @@ public class RunedPickaxe extends RareItem { event.getBlock().breakNaturally(); - event.getBlock().getWorld().playEffect(event.getBlock().getLocation(), Effect.TILE_BREAK, event.getBlock().getType(), 10); + event.getBlock().getWorld().playEffect(event.getBlock().getLocation(), Effect.TILE_BREAK, event.getBlock().getTypeId(), 10); event.getPlayer().playSound(event.getBlock().getLocation(), Sound.LAVA_POP, 1.f, 1.f); }