mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-26 19:18:12 +01:00
Update + added benchmark tool
This commit is contained in:
parent
126d778221
commit
c2580789b9
@ -13,6 +13,8 @@ import fr.themode.minestom.item.Material;
|
||||
import fr.themode.minestom.net.packet.server.play.DeclareRecipesPacket;
|
||||
import fr.themode.minestom.recipe.RecipeManager;
|
||||
import fr.themode.minestom.recipe.ShapelessRecipe;
|
||||
import fr.themode.minestom.utils.time.TimeUnit;
|
||||
import fr.themode.minestom.utils.time.UpdateOption;
|
||||
|
||||
|
||||
public class Main {
|
||||
@ -38,6 +40,7 @@ public class Main {
|
||||
shapelessRecipe.addIngredient(ingredient);
|
||||
recipeManager.addRecipe(shapelessRecipe);
|
||||
|
||||
MinecraftServer.getBenchmarkManager().enable(new UpdateOption(2500, TimeUnit.MILLISECOND));
|
||||
|
||||
PlayerInit.init();
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
package fr.themode.demo;
|
||||
|
||||
import fr.themode.demo.entity.ChickenCreature;
|
||||
import fr.themode.demo.generator.ChunkGeneratorDemo;
|
||||
import fr.themode.minestom.MinecraftServer;
|
||||
import fr.themode.minestom.benchmark.BenchmarkManager;
|
||||
import fr.themode.minestom.benchmark.ThreadResult;
|
||||
import fr.themode.minestom.entity.Entity;
|
||||
import fr.themode.minestom.entity.EntityCreature;
|
||||
import fr.themode.minestom.entity.GameMode;
|
||||
@ -12,8 +15,14 @@ import fr.themode.minestom.inventory.Inventory;
|
||||
import fr.themode.minestom.inventory.InventoryType;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.net.ConnectionManager;
|
||||
import fr.themode.minestom.timer.TaskRunnable;
|
||||
import fr.themode.minestom.utils.MathUtils;
|
||||
import fr.themode.minestom.utils.Position;
|
||||
import fr.themode.minestom.utils.Vector;
|
||||
import fr.themode.minestom.utils.time.TimeUnit;
|
||||
import fr.themode.minestom.utils.time.UpdateOption;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PlayerInit {
|
||||
|
||||
@ -37,6 +46,33 @@ public class PlayerInit {
|
||||
|
||||
public static void init() {
|
||||
ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
|
||||
BenchmarkManager benchmarkManager = MinecraftServer.getBenchmarkManager();
|
||||
|
||||
MinecraftServer.getSchedulerManager().addRepeatingTask(new TaskRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
long ramUsage = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
|
||||
ramUsage /= 1e6; // To MB
|
||||
|
||||
String benchmarkMessage = "";
|
||||
for (Map.Entry<String, ThreadResult> resultEntry : benchmarkManager.getResultMap().entrySet()) {
|
||||
String name = resultEntry.getKey();
|
||||
ThreadResult result = resultEntry.getValue();
|
||||
benchmarkMessage += name;
|
||||
benchmarkMessage += ": ";
|
||||
benchmarkMessage += MathUtils.round(result.getCpuPercentage(), 2) + "% CPU ";
|
||||
benchmarkMessage += MathUtils.round(result.getUserPercentage(), 2) + "% USER ";
|
||||
benchmarkMessage += MathUtils.round(result.getBlockedPercentage(), 2) + "% BLOCKED ";
|
||||
benchmarkMessage += "\n";
|
||||
}
|
||||
if (benchmarkMessage.length() > 0)
|
||||
System.out.println(benchmarkMessage);
|
||||
|
||||
for (Player player : connectionManager.getOnlinePlayers()) {
|
||||
player.sendHeaderFooter("RAM USAGE: " + ramUsage + " MB", "", '&');
|
||||
}
|
||||
}
|
||||
}, new UpdateOption(5, TimeUnit.TICK));
|
||||
|
||||
connectionManager.setResponseDataConsumer(responseData -> {
|
||||
responseData.setName("1.15.2");
|
||||
@ -78,8 +114,8 @@ public class PlayerInit {
|
||||
p.teleport(player.getPosition());
|
||||
}
|
||||
|
||||
//ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
|
||||
//chickenCreature.setInstance(player.getInstance());
|
||||
ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
|
||||
chickenCreature.setInstance(player.getInstance());
|
||||
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package fr.themode.minestom;
|
||||
|
||||
import com.github.simplenet.Server;
|
||||
import fr.themode.minestom.benchmark.BenchmarkManager;
|
||||
import fr.themode.minestom.command.CommandManager;
|
||||
import fr.themode.minestom.data.DataManager;
|
||||
import fr.themode.minestom.entity.EntityManager;
|
||||
@ -23,15 +24,33 @@ import fr.themode.minestom.utils.Utils;
|
||||
|
||||
public class MinecraftServer {
|
||||
|
||||
// Thread pools
|
||||
// Threads
|
||||
public static final String THREAD_NAME_BENCHMARK = "Ms-Benchmark";
|
||||
|
||||
public static final String THREAD_NAME_PACKET_WRITER = "Ms-PacketWriterPool";
|
||||
public static final int THREAD_COUNT_PACKET_WRITER = 2;
|
||||
|
||||
public static final String THREAD_NAME_IO = "Ms-IOPool";
|
||||
public static final int THREAD_COUNT_IO = 2;
|
||||
|
||||
public static final String THREAD_NAME_BLOCK_BATCH = "Ms-BlockBatchPool";
|
||||
public static final int THREAD_COUNT_BLOCK_BATCH = 2;
|
||||
|
||||
public static final String THREAD_NAME_BLOCK_UPDATE = "Ms-BlockUpdatePool";
|
||||
public static final int THREAD_COUNT_BLOCK_UPDATE = 2;
|
||||
|
||||
public static final String THREAD_NAME_ENTITIES = "Ms-EntitiesPool";
|
||||
public static final int THREAD_COUNT_ENTITIES = 2;
|
||||
|
||||
public static final String THREAD_NAME_ENTITIES_PATHFINDING = "Ms-EntitiesPathFinding";
|
||||
public static final int THREAD_COUNT_ENTITIES_PATHFINDING = 2;
|
||||
|
||||
public static final String THREAD_NAME_PLAYERS_ENTITIES = "Ms-PlayersPool";
|
||||
public static final int THREAD_COUNT_PLAYERS_ENTITIES = 2;
|
||||
public static final int THREAD_COUNT_SCHEDULER = 2;
|
||||
|
||||
public static final String THREAD_NAME_SCHEDULER = "Ms-SchedulerPool";
|
||||
public static final int THREAD_COUNT_SCHEDULER = 1;
|
||||
|
||||
// Config
|
||||
public static final int CHUNK_VIEW_DISTANCE = 5;
|
||||
public static final int ENTITY_VIEW_DISTANCE = 2;
|
||||
@ -55,6 +74,7 @@ public class MinecraftServer {
|
||||
private static DataManager dataManager;
|
||||
private static TeamManager teamManager;
|
||||
private static SchedulerManager schedulerManager;
|
||||
private static BenchmarkManager benchmarkManager;
|
||||
|
||||
private static MinecraftServer minecraftServer;
|
||||
|
||||
@ -71,6 +91,7 @@ public class MinecraftServer {
|
||||
dataManager = new DataManager();
|
||||
teamManager = new TeamManager();
|
||||
schedulerManager = new SchedulerManager();
|
||||
benchmarkManager = new BenchmarkManager();
|
||||
|
||||
server = new Server();
|
||||
|
||||
@ -125,6 +146,10 @@ public class MinecraftServer {
|
||||
return schedulerManager;
|
||||
}
|
||||
|
||||
public static BenchmarkManager getBenchmarkManager() {
|
||||
return benchmarkManager;
|
||||
}
|
||||
|
||||
public static ConnectionManager getConnectionManager() {
|
||||
return connectionManager;
|
||||
}
|
||||
|
@ -0,0 +1,122 @@
|
||||
package fr.themode.minestom.benchmark;
|
||||
|
||||
import fr.themode.minestom.MinecraftServer;
|
||||
import fr.themode.minestom.utils.time.UpdateOption;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.ThreadInfo;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.util.*;
|
||||
|
||||
import static fr.themode.minestom.MinecraftServer.*;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class BenchmarkManager {
|
||||
|
||||
public static ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
|
||||
private static List<String> threads = Arrays.asList(THREAD_NAME_PACKET_WRITER, THREAD_NAME_IO,
|
||||
THREAD_NAME_BLOCK_BATCH, THREAD_NAME_BLOCK_UPDATE, THREAD_NAME_ENTITIES, THREAD_NAME_ENTITIES_PATHFINDING,
|
||||
THREAD_NAME_PLAYERS_ENTITIES, THREAD_NAME_SCHEDULER);
|
||||
|
||||
static {
|
||||
assertTrue(threadMXBean.isThreadCpuTimeSupported());
|
||||
assertTrue(threadMXBean.isCurrentThreadCpuTimeSupported());
|
||||
|
||||
threadMXBean.setThreadContentionMonitoringEnabled(true);
|
||||
threadMXBean.setThreadCpuTimeEnabled(true);
|
||||
assertTrue(threadMXBean.isThreadCpuTimeEnabled());
|
||||
}
|
||||
|
||||
private Map<Long, Long> lastCpuTimeMap = new HashMap<>();
|
||||
private Map<Long, Long> lastUserTimeMap = new HashMap<>();
|
||||
private Map<Long, Long> lastBlockedMap = new HashMap<>();
|
||||
|
||||
private Map<String, ThreadResult> resultMap = new HashMap<>();
|
||||
|
||||
private boolean enabled = false;
|
||||
private volatile boolean stop = false;
|
||||
|
||||
private UpdateOption updateOption;
|
||||
private Thread thread;
|
||||
|
||||
private long time;
|
||||
|
||||
public void enable(UpdateOption updateOption) {
|
||||
if (enabled)
|
||||
throw new IllegalStateException("A benchmark is already running, please disable it first.");
|
||||
|
||||
this.updateOption = updateOption;
|
||||
time = updateOption.getTimeUnit().toMilliseconds(updateOption.getValue());
|
||||
|
||||
this.thread = new Thread(null, () -> {
|
||||
|
||||
while (!stop) {
|
||||
refreshData();
|
||||
|
||||
try {
|
||||
Thread.sleep(time);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
stop = false;
|
||||
|
||||
}, MinecraftServer.THREAD_NAME_BENCHMARK, 0L);
|
||||
|
||||
this.thread.start();
|
||||
|
||||
this.enabled = true;
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
this.stop = true;
|
||||
this.enabled = false;
|
||||
}
|
||||
|
||||
public Map<String, ThreadResult> getResultMap() {
|
||||
return Collections.unmodifiableMap(resultMap);
|
||||
}
|
||||
|
||||
private void refreshData() {
|
||||
ThreadInfo[] threadInfo = threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds());
|
||||
for (ThreadInfo threadInfo2 : threadInfo) {
|
||||
String name = threadInfo2.getThreadName();
|
||||
boolean shouldBenchmark = false;
|
||||
for (String thread : threads) {
|
||||
if (name.startsWith(thread)) {
|
||||
shouldBenchmark = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!shouldBenchmark)
|
||||
continue;
|
||||
|
||||
long id = threadInfo2.getThreadId();
|
||||
|
||||
long lastCpuTime = lastCpuTimeMap.getOrDefault(id, 0L);
|
||||
long lastUserTime = lastUserTimeMap.getOrDefault(id, 0L);
|
||||
long lastBlockedTime = lastBlockedMap.getOrDefault(id, 0L);
|
||||
|
||||
long blockedTime = threadInfo2.getBlockedTime();
|
||||
//long waitedTime = threadInfo2.getWaitedTime();
|
||||
long cpuTime = threadMXBean.getThreadCpuTime(id);
|
||||
long userTime = threadMXBean.getThreadUserTime(id);
|
||||
|
||||
lastCpuTimeMap.put(id, cpuTime);
|
||||
lastUserTimeMap.put(id, userTime);
|
||||
lastBlockedMap.put(id, blockedTime);
|
||||
|
||||
double totalCpuTime = (double) (cpuTime - lastCpuTime) / 1000000D;
|
||||
double totalUserTime = (double) (userTime - lastUserTime) / 1000000D;
|
||||
long totalBlocked = blockedTime - lastBlockedTime;
|
||||
|
||||
double cpuPercentage = totalCpuTime / (double) time * 100L;
|
||||
double userPercentage = totalUserTime / (double) time * 100L;
|
||||
double blockedPercentage = totalBlocked / (double) time * 100L;
|
||||
|
||||
ThreadResult threadResult = new ThreadResult(cpuPercentage, userPercentage, blockedPercentage);
|
||||
resultMap.put(name, threadResult);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package fr.themode.minestom.benchmark;
|
||||
|
||||
public class ThreadResult {
|
||||
|
||||
private double cpuPercentage, userPercentage, blockedPercentage;
|
||||
|
||||
protected ThreadResult(double cpuPercentage, double userPercentage, double blockedPercentage) {
|
||||
this.cpuPercentage = cpuPercentage;
|
||||
this.userPercentage = userPercentage;
|
||||
this.blockedPercentage = blockedPercentage;
|
||||
}
|
||||
|
||||
public double getCpuPercentage() {
|
||||
return cpuPercentage;
|
||||
}
|
||||
|
||||
public double getUserPercentage() {
|
||||
return userPercentage;
|
||||
}
|
||||
|
||||
public double getBlockedPercentage() {
|
||||
return blockedPercentage;
|
||||
}
|
||||
}
|
@ -18,8 +18,8 @@ public class EntityManager {
|
||||
private UpdateType updateType = UpdateType.PER_INSTANCE;
|
||||
private Set<Instance> instances = instanceManager.getInstances();
|
||||
|
||||
private ExecutorService entitiesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_ENTITIES, "Ms-EntitiesPool");
|
||||
private ExecutorService playersPool = new MinestomThread(MinecraftServer.THREAD_COUNT_PLAYERS_ENTITIES, "Ms-PlayersPool");
|
||||
private ExecutorService entitiesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_ENTITIES, MinecraftServer.THREAD_NAME_ENTITIES);
|
||||
private ExecutorService playersPool = new MinestomThread(MinecraftServer.THREAD_COUNT_PLAYERS_ENTITIES, MinecraftServer.THREAD_NAME_PLAYERS_ENTITIES);
|
||||
|
||||
private ConcurrentLinkedQueue<Player> waitingPlayers = new ConcurrentLinkedQueue<>();
|
||||
|
||||
@ -187,6 +187,6 @@ public class EntityManager {
|
||||
PER_CHUNK,
|
||||
PER_ENTITY_TYPE,
|
||||
PER_INSTANCE,
|
||||
SINGLE_THREADED;
|
||||
SINGLE_THREADED
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import java.util.function.Consumer;
|
||||
|
||||
public class EntityPathFinder {
|
||||
|
||||
private ExecutorService pathfindingPool = new MinestomThread(MinecraftServer.THREAD_COUNT_ENTITIES_PATHFINDING, "Ms-EntitiesPathFinding");
|
||||
private ExecutorService pathfindingPool = new MinestomThread(MinecraftServer.THREAD_COUNT_ENTITIES_PATHFINDING, MinecraftServer.THREAD_NAME_ENTITIES_PATHFINDING);
|
||||
|
||||
|
||||
private Entity entity;
|
||||
|
@ -59,9 +59,8 @@ public class InstanceContainer extends Instance {
|
||||
|
||||
chunk.UNSAFE_setBlock(index, blockId, data);
|
||||
|
||||
executeNeighboursBlockPlacementRule(blockId, blockPosition);
|
||||
executeNeighboursBlockPlacementRule(blockPosition);
|
||||
|
||||
// TODO instead of sending a block change packet each time, cache changed blocks and flush them every tick with a MultiBlockChangePacket
|
||||
sendBlockChange(chunk, x, y, z, blockId);
|
||||
}
|
||||
}
|
||||
@ -83,11 +82,10 @@ public class InstanceContainer extends Instance {
|
||||
|
||||
chunk.UNSAFE_setCustomBlock(index, blockId, data);
|
||||
|
||||
executeNeighboursBlockPlacementRule(blockId, blockPosition);
|
||||
executeNeighboursBlockPlacementRule(blockPosition);
|
||||
|
||||
callBlockPlace(chunk, index, x, y, z);
|
||||
|
||||
// TODO instead of sending a block change packet each time, cache changed blocks and flush them every tick with a MultiBlockChangePacket
|
||||
short id = BLOCK_MANAGER.getBlock(blockId).getType();
|
||||
sendBlockChange(chunk, x, y, z, id);
|
||||
}
|
||||
@ -132,7 +130,7 @@ public class InstanceContainer extends Instance {
|
||||
return blockId;
|
||||
}
|
||||
|
||||
private void executeNeighboursBlockPlacementRule(short blockId, BlockPosition blockPosition) {
|
||||
private void executeNeighboursBlockPlacementRule(BlockPosition blockPosition) {
|
||||
for (int offsetX = -1; offsetX < 2; offsetX++) {
|
||||
for (int offsetY = -1; offsetY < 2; offsetY++) {
|
||||
for (int offsetZ = -1; offsetZ < 2; offsetZ++) {
|
||||
|
@ -12,7 +12,7 @@ import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class InstanceManager {
|
||||
|
||||
private ExecutorService blocksPool = new MinestomThread(MinecraftServer.THREAD_COUNT_BLOCK_UPDATE, "Ms-BlockUpdatePool");
|
||||
private ExecutorService blocksPool = new MinestomThread(MinecraftServer.THREAD_COUNT_BLOCK_UPDATE, MinecraftServer.THREAD_NAME_BLOCK_UPDATE);
|
||||
|
||||
private Set<Instance> instances = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
|
@ -8,6 +8,6 @@ import java.util.concurrent.ExecutorService;
|
||||
|
||||
public interface InstanceBatch extends BlockModifier {
|
||||
|
||||
ExecutorService batchesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_BLOCK_BATCH, "Ms-BlockBatchPool");
|
||||
ExecutorService batchesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_BLOCK_BATCH, MinecraftServer.THREAD_NAME_BLOCK_BATCH);
|
||||
|
||||
}
|
||||
|
@ -56,6 +56,8 @@ public class RedstonePlacementRule extends BlockPlacementRule {
|
||||
north = "side";
|
||||
}
|
||||
|
||||
// TODO power
|
||||
|
||||
|
||||
return Block.REDSTONE_WIRE.withProperties(east, north, power, south, west);
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
|
||||
|
||||
public void update() {
|
||||
WindowItemsPacket windowItemsPacket = getWindowItemsPacket();
|
||||
getViewers().forEach(p -> p.getPlayerConnection().sendPacket(windowItemsPacket));
|
||||
sendPacketToViewers(windowItemsPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -129,7 +129,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
|
||||
setSlotPacket.windowId = 1;
|
||||
setSlotPacket.slot = (short) slot;
|
||||
setSlotPacket.itemStack = itemStack;
|
||||
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(setSlotPacket));
|
||||
sendPacketToViewers(setSlotPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class IOManager {
|
||||
|
||||
private static final ExecutorService IO_POOL = new MinestomThread(MinecraftServer.THREAD_COUNT_IO, "Ms-IOPool");
|
||||
private static final ExecutorService IO_POOL = new MinestomThread(MinecraftServer.THREAD_COUNT_IO, MinecraftServer.THREAD_NAME_IO);
|
||||
|
||||
public static void submit(Runnable runnable) {
|
||||
IO_POOL.execute(runnable);
|
||||
|
@ -14,7 +14,7 @@ import java.util.function.Consumer;
|
||||
|
||||
public class PacketWriterUtils {
|
||||
|
||||
private static ExecutorService batchesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_PACKET_WRITER, "Ms-PacketWriterPool");
|
||||
private static ExecutorService batchesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_PACKET_WRITER, MinecraftServer.THREAD_NAME_PACKET_WRITER);
|
||||
|
||||
public static void writeCallbackPacket(ServerPacket serverPacket, Consumer<Packet> consumer) {
|
||||
batchesPool.execute(() -> {
|
||||
|
@ -5,7 +5,6 @@ import fr.themode.minestom.utils.thread.MinestomThread;
|
||||
import fr.themode.minestom.utils.time.CooldownUtils;
|
||||
import fr.themode.minestom.utils.time.UpdateOption;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@ -14,7 +13,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
public class SchedulerManager {
|
||||
|
||||
private static final AtomicInteger COUNTER = new AtomicInteger();
|
||||
private static ExecutorService batchesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_SCHEDULER, "Ms-SchedulerPool");
|
||||
private static ExecutorService batchesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_SCHEDULER, MinecraftServer.THREAD_NAME_SCHEDULER);
|
||||
private List<Task> tasks = new CopyOnWriteArrayList<>();
|
||||
|
||||
public int addTask(TaskRunnable runnable, UpdateOption updateOption, int maxCallCount) {
|
||||
@ -36,36 +35,28 @@ public class SchedulerManager {
|
||||
}
|
||||
|
||||
public void removeTask(int taskId) {
|
||||
synchronized (tasks) {
|
||||
this.tasks.removeIf(task -> task.getId() == taskId);
|
||||
}
|
||||
this.tasks.removeIf(task -> task.getId() == taskId);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
long time = System.currentTimeMillis();
|
||||
batchesPool.execute(() -> {
|
||||
for (Task task : tasks) {
|
||||
UpdateOption updateOption = task.getUpdateOption();
|
||||
long lastUpdate = task.getLastUpdateTime();
|
||||
boolean hasCooldown = CooldownUtils.hasCooldown(time, lastUpdate, updateOption.getTimeUnit(), updateOption.getValue());
|
||||
if (!hasCooldown) {
|
||||
TaskRunnable runnable = task.getRunnable();
|
||||
int maxCallCount = task.getMaxCallCount();
|
||||
int callCount = runnable.getCallCount() + 1;
|
||||
runnable.setCallCount(callCount);
|
||||
|
||||
synchronized (tasks) {
|
||||
Iterator<Task> iterator = tasks.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Task task = iterator.next();
|
||||
runnable.run();
|
||||
|
||||
UpdateOption updateOption = task.getUpdateOption();
|
||||
long lastUpdate = task.getLastUpdateTime();
|
||||
boolean hasCooldown = CooldownUtils.hasCooldown(time, lastUpdate, updateOption.getTimeUnit(), updateOption.getValue());
|
||||
if (!hasCooldown) {
|
||||
TaskRunnable runnable = task.getRunnable();
|
||||
int maxCallCount = task.getMaxCallCount();
|
||||
int callCount = runnable.getCallCount() + 1;
|
||||
runnable.setCallCount(callCount);
|
||||
task.refreshLastUpdateTime(time);
|
||||
|
||||
runnable.run();
|
||||
|
||||
task.refreshLastUpdateTime(time);
|
||||
|
||||
if (callCount == maxCallCount) {
|
||||
iterator.remove();
|
||||
}
|
||||
if (callCount == maxCallCount) {
|
||||
tasks.remove(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,4 +10,22 @@ public class MathUtils {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
public static double round(double value, int places) {
|
||||
if (places < 0) throw new IllegalArgumentException();
|
||||
|
||||
long factor = (long) Math.pow(10, places);
|
||||
value = value * factor;
|
||||
long tmp = Math.round(value);
|
||||
return (double) tmp / factor;
|
||||
}
|
||||
|
||||
public static float round(float value, int places) {
|
||||
if (places < 0) throw new IllegalArgumentException();
|
||||
|
||||
long factor = (long) Math.pow(10, places);
|
||||
value = value * factor;
|
||||
long tmp = Math.round(value);
|
||||
return (float) tmp / factor;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user