From 1ba173388e6c9c35b3cf046b330a7c88fb1e1d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chirose=E2=80=9D?= Date: Mon, 20 Apr 2026 12:45:08 +0900 Subject: [PATCH 1/4] Add PlayerCount entity to track online player count via fiware --- .../java/city/makeour/fiwarecraft/App.java | 23 +++++++- .../fiwarecraft/client/FcMocClient.java | 18 ++++++ .../fiwarecraft/model/PlayerCount.java | 57 +++++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 src/main/java/city/makeour/fiwarecraft/model/PlayerCount.java diff --git a/src/main/java/city/makeour/fiwarecraft/App.java b/src/main/java/city/makeour/fiwarecraft/App.java index 7e9c7c0..e6867aa 100644 --- a/src/main/java/city/makeour/fiwarecraft/App.java +++ b/src/main/java/city/makeour/fiwarecraft/App.java @@ -3,6 +3,10 @@ import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.java.JavaPlugin; import city.makeour.fiwarecraft.client.FcMocClient; @@ -11,9 +15,10 @@ /** * Fiwarecraft plugin main class */ -public class App extends JavaPlugin { +public class App extends JavaPlugin implements Listener { protected FcMocClient mocClient; + private static final String PLAYER_COUNT_ENTITY_ID = "urn:ngsi-ld:PlayerCount:server-001"; /** * デフォルトのコンストラクタ @@ -41,10 +46,26 @@ public void onEnable() { return; } this.mocClient.sendPing("urn:ngsi-ld:ping:test-serer-001", true); + getServer().getPluginManager().registerEvents(this, this); getLogger().info("Send ping"); } + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + int count = getServer().getOnlinePlayers().size(); + getLogger().info("Player joined: " + event.getPlayer().getName() + " (online: " + count + ")"); + this.mocClient.sendPlayerCount(PLAYER_COUNT_ENTITY_ID, count); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + // Quit時点ではまだプレイヤーが含まれているので -1 + int count = getServer().getOnlinePlayers().size() - 1; + getLogger().info("Player quit: " + event.getPlayer().getName() + " (online: " + count + ")"); + this.mocClient.sendPlayerCount(PLAYER_COUNT_ENTITY_ID, count); + } + @Override public void onDisable() { getLogger().info("Fiwarecraft plugin has been disabled!"); diff --git a/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java b/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java index 8293b87..46ea039 100644 --- a/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java +++ b/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java @@ -2,6 +2,7 @@ import city.makeour.moc.MocClient; import city.makeour.fiwarecraft.model.Ping; +import city.makeour.fiwarecraft.model.PlayerCount; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -107,6 +108,23 @@ public void sendPing(String entityId, boolean status) { } + public void sendPlayerCount(String entityId, int count) { + PlayerCount entity = new PlayerCount(); + entity.setId(entityId); + entity.setType("PlayerCount"); + entity.setCount(count); + entity.setUpdatedAt(LocalDateTime.now()); + + if (this.fiwareService != null && !this.fiwareService.isEmpty()) { + mocClient.setFiwareService(this.fiwareService); + } + + var resp = mocClient.updateEntity(entityId, "PlayerCount", entity); + if (resp != null) { + System.out.println("PlayerCount Upserted: " + count); + } + } + public void setFiwareService(String fiwareService) { this.fiwareService = fiwareService; } diff --git a/src/main/java/city/makeour/fiwarecraft/model/PlayerCount.java b/src/main/java/city/makeour/fiwarecraft/model/PlayerCount.java new file mode 100644 index 0000000..584a7ae --- /dev/null +++ b/src/main/java/city/makeour/fiwarecraft/model/PlayerCount.java @@ -0,0 +1,57 @@ +package city.makeour.fiwarecraft.model; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.annotation.Nonnull; +import java.time.LocalDateTime; + +public class PlayerCount extends NgsiV2Entity { + + public static final String JSON_PROPERTY_COUNT = "count"; + private int count; + + public static final String JSON_PROPERTY_UPDATED_AT = "updatedAt"; + private LocalDateTime updatedAt; + + public PlayerCount() { + this.count = 0; + } + + public PlayerCount count(int count) { + this.count = count; + return this; + } + + public PlayerCount updatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + return this; + } + + @Nonnull + @JsonProperty(JSON_PROPERTY_COUNT) + @JsonInclude(JsonInclude.Include.ALWAYS) + public int getCount() { + return this.count; + } + + @JsonProperty(JSON_PROPERTY_COUNT) + @JsonInclude(JsonInclude.Include.ALWAYS) + public void setCount(int count) { + this.count = count; + } + + @JsonProperty(JSON_PROPERTY_UPDATED_AT) + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + public LocalDateTime getUpdatedAt() { + return this.updatedAt; + } + + @JsonProperty(JSON_PROPERTY_UPDATED_AT) + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } +} From 4d076d8d58e8beaf63a31298eb061e2f1665031b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chirose=E2=80=9D?= Date: Wed, 3 Jun 2026 13:05:10 +0900 Subject: [PATCH 2/4] Consolidate heatmap into Server entity --- .../java/city/makeour/fiwarecraft/App.java | 37 ++++++++++++++++--- .../fiwarecraft/client/FcMocClient.java | 25 +++++++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/main/java/city/makeour/fiwarecraft/App.java b/src/main/java/city/makeour/fiwarecraft/App.java index e6867aa..0fb7496 100644 --- a/src/main/java/city/makeour/fiwarecraft/App.java +++ b/src/main/java/city/makeour/fiwarecraft/App.java @@ -2,7 +2,10 @@ import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; @@ -18,7 +21,8 @@ public class App extends JavaPlugin implements Listener { protected FcMocClient mocClient; - private static final String PLAYER_COUNT_ENTITY_ID = "urn:ngsi-ld:PlayerCount:server-001"; + private static final String BASE_ENTITY_ID = "test-server-001"; + private static final int GRID_SIZE = 64; // グリッドサイズ(ブロック単位) /** * デフォルトのコンストラクタ @@ -45,9 +49,13 @@ public void onEnable() { getLogger().severe("Authentication failed. Please check your environment variables for Cognito credentials."); return; } - this.mocClient.sendPing("urn:ngsi-ld:ping:test-serer-001", true); + this.mocClient.sendPing(BASE_ENTITY_ID, true); getServer().getPluginManager().registerEvents(this, this); + // ヒートマップ更新を5秒ごとに実行 + getServer().getScheduler().scheduleSyncRepeatingTask(this, + () -> updatePlayerHeatmap(), 0L, 100L); + getLogger().info("Send ping"); } @@ -55,7 +63,7 @@ public void onEnable() { public void onPlayerJoin(PlayerJoinEvent event) { int count = getServer().getOnlinePlayers().size(); getLogger().info("Player joined: " + event.getPlayer().getName() + " (online: " + count + ")"); - this.mocClient.sendPlayerCount(PLAYER_COUNT_ENTITY_ID, count); + this.mocClient.sendPlayerCount(BASE_ENTITY_ID, count); } @EventHandler @@ -63,15 +71,32 @@ public void onPlayerQuit(PlayerQuitEvent event) { // Quit時点ではまだプレイヤーが含まれているので -1 int count = getServer().getOnlinePlayers().size() - 1; getLogger().info("Player quit: " + event.getPlayer().getName() + " (online: " + count + ")"); - this.mocClient.sendPlayerCount(PLAYER_COUNT_ENTITY_ID, count); + this.mocClient.sendPlayerCount(BASE_ENTITY_ID, count); + } + + private void updatePlayerHeatmap() { + Map gridCounts = new HashMap<>(); + + for (Player player : getServer().getOnlinePlayers()) { + String gridId = getGridId(player); + gridCounts.put(gridId, gridCounts.getOrDefault(gridId, 0) + 1); + } + + this.mocClient.sendServerData(BASE_ENTITY_ID, gridCounts); + } + + private String getGridId(Player player) { + int gridX = (int) player.getLocation().getX() / GRID_SIZE; + int gridZ = (int) player.getLocation().getZ() / GRID_SIZE; + int gridY = (int) player.getLocation().getY() / GRID_SIZE; + return String.format("urn:ngsi-ld:Heatmap:grid-%d-%d-%d", gridX, gridY, gridZ); } @Override public void onDisable() { getLogger().info("Fiwarecraft plugin has been disabled!"); if (this.mocClient != null) { - // onEnableと同じ Entity ID を指定して、ステータスを false にして送信 - this.mocClient.sendPing("urn:ngsi-ld:ping:test-serer-001", false); + this.mocClient.sendPing(BASE_ENTITY_ID, false); getLogger().info("Send ping (offline)"); } } diff --git a/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java b/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java index 46ea039..02653bb 100644 --- a/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java +++ b/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java @@ -125,6 +125,31 @@ public void sendPlayerCount(String entityId, int count) { } } + public void sendServerData(String entityId, Map gridCounts) { + Map heatmapGrids = new HashMap<>(); + for (String gridId : gridCounts.keySet()) { + Map gridData = new HashMap<>(); + gridData.put("gridId", gridId); + gridData.put("count", gridCounts.get(gridId)); + heatmapGrids.put(gridId, gridData); + } + + Map serverData = new HashMap<>(); + serverData.put("id", entityId); + serverData.put("type", "Server"); + serverData.put("heatmapGrids", heatmapGrids); + serverData.put("recordedAt", LocalDateTime.now()); + + if (this.fiwareService != null && !this.fiwareService.isEmpty()) { + mocClient.setFiwareService(this.fiwareService); + } + + var resp = mocClient.updateEntity(entityId, "Server", serverData); + if (resp != null) { + System.out.println("Server Data Sent: " + gridCounts.size() + " grids updated"); + } + } + public void setFiwareService(String fiwareService) { this.fiwareService = fiwareService; } From f483006cd67ae0f658f1805992c242be50fe088b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chirose=E2=80=9D?= Date: Tue, 16 Jun 2026 16:02:19 +0900 Subject: [PATCH 3/4] Optimize heatmap updates --- .../java/city/makeour/fiwarecraft/App.java | 34 +++++++------------ 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/src/main/java/city/makeour/fiwarecraft/App.java b/src/main/java/city/makeour/fiwarecraft/App.java index 0fb7496..c2d5af2 100644 --- a/src/main/java/city/makeour/fiwarecraft/App.java +++ b/src/main/java/city/makeour/fiwarecraft/App.java @@ -1,15 +1,11 @@ package city.makeour.fiwarecraft; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.java.JavaPlugin; import city.makeour.fiwarecraft.client.FcMocClient; @@ -23,6 +19,7 @@ public class App extends JavaPlugin implements Listener { protected FcMocClient mocClient; private static final String BASE_ENTITY_ID = "test-server-001"; private static final int GRID_SIZE = 64; // グリッドサイズ(ブロック単位) + private Map lastGridCounts = new HashMap<>(); /** * デフォルトのコンストラクタ @@ -52,37 +49,30 @@ public void onEnable() { this.mocClient.sendPing(BASE_ENTITY_ID, true); getServer().getPluginManager().registerEvents(this, this); - // ヒートマップ更新を5秒ごとに実行 + // ヒートマップ更新を60秒ごとに実行(CPU削減) getServer().getScheduler().scheduleSyncRepeatingTask(this, - () -> updatePlayerHeatmap(), 0L, 100L); + () -> updatePlayerHeatmap(), 0L, 1200L); getLogger().info("Send ping"); } - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - int count = getServer().getOnlinePlayers().size(); - getLogger().info("Player joined: " + event.getPlayer().getName() + " (online: " + count + ")"); - this.mocClient.sendPlayerCount(BASE_ENTITY_ID, count); - } - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - // Quit時点ではまだプレイヤーが含まれているので -1 - int count = getServer().getOnlinePlayers().size() - 1; - getLogger().info("Player quit: " + event.getPlayer().getName() + " (online: " + count + ")"); - this.mocClient.sendPlayerCount(BASE_ENTITY_ID, count); - } private void updatePlayerHeatmap() { Map gridCounts = new HashMap<>(); + int totalPlayers = 0; for (Player player : getServer().getOnlinePlayers()) { + totalPlayers++; String gridId = getGridId(player); gridCounts.put(gridId, gridCounts.getOrDefault(gridId, 0) + 1); } - this.mocClient.sendServerData(BASE_ENTITY_ID, gridCounts); + if (!Objects.equals(lastGridCounts, gridCounts)) { + this.mocClient.sendServerData(BASE_ENTITY_ID, gridCounts); + this.mocClient.sendPlayerCount(BASE_ENTITY_ID, totalPlayers); + lastGridCounts = new HashMap<>(gridCounts); + getLogger().info("Updated heatmap and player count: " + totalPlayers + " players"); + } } private String getGridId(Player player) { From 3c9fe577f48d63ba32ba2fc4d87dc1ddd496207e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chirose=E2=80=9D?= Date: Tue, 16 Jun 2026 16:06:02 +0900 Subject: [PATCH 4/4] Created Server entity --- .../java/city/makeour/fiwarecraft/App.java | 21 +++- .../fiwarecraft/client/FcMocClient.java | 25 +++++ .../makeour/fiwarecraft/model/Server.java | 103 ++++++++++++++++++ 3 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 src/main/java/city/makeour/fiwarecraft/model/Server.java diff --git a/src/main/java/city/makeour/fiwarecraft/App.java b/src/main/java/city/makeour/fiwarecraft/App.java index c2d5af2..79e65e8 100644 --- a/src/main/java/city/makeour/fiwarecraft/App.java +++ b/src/main/java/city/makeour/fiwarecraft/App.java @@ -1,5 +1,6 @@ package city.makeour.fiwarecraft; +import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -9,6 +10,7 @@ import org.bukkit.plugin.java.JavaPlugin; import city.makeour.fiwarecraft.client.FcMocClient; +import city.makeour.fiwarecraft.model.Server; import city.makeour.moc.MocClient; /** @@ -68,10 +70,15 @@ private void updatePlayerHeatmap() { } if (!Objects.equals(lastGridCounts, gridCounts)) { - this.mocClient.sendServerData(BASE_ENTITY_ID, gridCounts); - this.mocClient.sendPlayerCount(BASE_ENTITY_ID, totalPlayers); + Server server = new Server() + .playerCount(totalPlayers) + .heatmap(gridCounts) + .status("ONLINE") + .updatedAt(LocalDateTime.now()); + + this.mocClient.sendServer(BASE_ENTITY_ID, server); lastGridCounts = new HashMap<>(gridCounts); - getLogger().info("Updated heatmap and player count: " + totalPlayers + " players"); + getLogger().info("Updated server: " + totalPlayers + " players, " + gridCounts.size() + " grids"); } } @@ -87,7 +94,13 @@ public void onDisable() { getLogger().info("Fiwarecraft plugin has been disabled!"); if (this.mocClient != null) { this.mocClient.sendPing(BASE_ENTITY_ID, false); - getLogger().info("Send ping (offline)"); + Server server = new Server() + .playerCount(0) + .heatmap(new HashMap<>()) + .status("OFFLINE") + .updatedAt(LocalDateTime.now()); + this.mocClient.sendServer(BASE_ENTITY_ID, server); + getLogger().info("Send ping and server status (offline)"); } } } \ No newline at end of file diff --git a/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java b/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java index 02653bb..45f7f15 100644 --- a/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java +++ b/src/main/java/city/makeour/fiwarecraft/client/FcMocClient.java @@ -3,6 +3,7 @@ import city.makeour.moc.MocClient; import city.makeour.fiwarecraft.model.Ping; import city.makeour.fiwarecraft.model.PlayerCount; +import city.makeour.fiwarecraft.model.Server; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -125,6 +126,30 @@ public void sendPlayerCount(String entityId, int count) { } } + public void sendServer(String entityId, Server server) { + if (server.getType() == null) { + server.setType("Server"); + } + + if (server.getId() == null) { + server.setId(entityId); + } + + if (server.getUpdatedAt() == null) { + server.setUpdatedAt(LocalDateTime.now()); + } + + if (this.fiwareService != null && !this.fiwareService.isEmpty()) { + mocClient.setFiwareService(this.fiwareService); + } + + var resp = mocClient.updateEntity(entityId, "Server", server); + if (resp != null) { + System.out.println("Server Upserted: " + server.getPlayerCount() + " players, " + + server.getHeatmap().size() + " grids, status=" + server.getStatus()); + } + } + public void sendServerData(String entityId, Map gridCounts) { Map heatmapGrids = new HashMap<>(); for (String gridId : gridCounts.keySet()) { diff --git a/src/main/java/city/makeour/fiwarecraft/model/Server.java b/src/main/java/city/makeour/fiwarecraft/model/Server.java new file mode 100644 index 0000000..ae3089e --- /dev/null +++ b/src/main/java/city/makeour/fiwarecraft/model/Server.java @@ -0,0 +1,103 @@ +package city.makeour.fiwarecraft.model; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.annotation.Nonnull; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +public class Server extends NgsiV2Entity { + + public static final String JSON_PROPERTY_PLAYER_COUNT = "playerCount"; + private int playerCount; + + public static final String JSON_PROPERTY_HEATMAP = "heatmap"; + private Map heatmap; + + public static final String JSON_PROPERTY_STATUS = "status"; + private String status; + + public static final String JSON_PROPERTY_UPDATED_AT = "updatedAt"; + private LocalDateTime updatedAt; + + public Server() { + this.playerCount = 0; + this.heatmap = new HashMap<>(); + this.status = "OFFLINE"; + } + + public Server playerCount(int playerCount) { + this.playerCount = playerCount; + return this; + } + + public Server heatmap(Map heatmap) { + this.heatmap = heatmap; + return this; + } + + public Server status(String status) { + this.status = status; + return this; + } + + public Server updatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + return this; + } + + @Nonnull + @JsonProperty(JSON_PROPERTY_PLAYER_COUNT) + @JsonInclude(JsonInclude.Include.ALWAYS) + public int getPlayerCount() { + return this.playerCount; + } + + @JsonProperty(JSON_PROPERTY_PLAYER_COUNT) + @JsonInclude(JsonInclude.Include.ALWAYS) + public void setPlayerCount(int playerCount) { + this.playerCount = playerCount; + } + + @Nonnull + @JsonProperty(JSON_PROPERTY_HEATMAP) + @JsonInclude(JsonInclude.Include.ALWAYS) + public Map getHeatmap() { + return this.heatmap; + } + + @JsonProperty(JSON_PROPERTY_HEATMAP) + @JsonInclude(JsonInclude.Include.ALWAYS) + public void setHeatmap(Map heatmap) { + this.heatmap = heatmap; + } + + @Nonnull + @JsonProperty(JSON_PROPERTY_STATUS) + @JsonInclude(JsonInclude.Include.ALWAYS) + public String getStatus() { + return this.status; + } + + @JsonProperty(JSON_PROPERTY_STATUS) + @JsonInclude(JsonInclude.Include.ALWAYS) + public void setStatus(String status) { + this.status = status; + } + + @JsonProperty(JSON_PROPERTY_UPDATED_AT) + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + public LocalDateTime getUpdatedAt() { + return this.updatedAt; + } + + @JsonProperty(JSON_PROPERTY_UPDATED_AT) + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } +}