From cbc71d062ac44d1d23e97fed75b9b17545e8bd9f Mon Sep 17 00:00:00 2001 From: Light_Quanta Date: Tue, 1 Jul 2025 03:37:45 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=86=99=E6=95=B0=E6=8D=AE=E5=8C=85?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/atsuishio/superbwarfare/Mod.java | 3 + .../superbwarfare/data/CustomData.java | 19 +++ .../superbwarfare/data/DataLoader.java | 161 ++++++++++++++++++ .../superbwarfare/data/IDBasedData.java | 5 + .../data/gun/DefaultGunData.java | 8 +- .../data/gun/ProjectileInfo.java | 8 +- .../data/launchable/LaunchableEntityTool.java | 45 +---- .../data/vehicle/DefaultVehicleData.java | 8 +- .../data/vehicle/VehicleDataTool.java | 44 +---- .../superbwarfare/item/gun/GunItem.java | 2 +- .../superbwarfare/tools/GunsTool.java | 49 +----- 11 files changed, 218 insertions(+), 134 deletions(-) create mode 100644 src/main/java/com/atsuishio/superbwarfare/data/CustomData.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/data/DataLoader.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/data/IDBasedData.java diff --git a/src/main/java/com/atsuishio/superbwarfare/Mod.java b/src/main/java/com/atsuishio/superbwarfare/Mod.java index 3a7a4a41d..7e129a3f6 100644 --- a/src/main/java/com/atsuishio/superbwarfare/Mod.java +++ b/src/main/java/com/atsuishio/superbwarfare/Mod.java @@ -12,6 +12,7 @@ import com.atsuishio.superbwarfare.component.ModDataComponents; import com.atsuishio.superbwarfare.config.ClientConfig; import com.atsuishio.superbwarfare.config.CommonConfig; import com.atsuishio.superbwarfare.config.ServerConfig; +import com.atsuishio.superbwarfare.data.CustomData; import com.atsuishio.superbwarfare.init.*; import com.atsuishio.superbwarfare.network.NetworkRegistry; import net.minecraft.resources.ResourceLocation; @@ -86,6 +87,8 @@ public class Mod { } NeoForge.EVENT_BUS.register(this); + + CustomData.load(); } public static ResourceLocation loc(String path) { diff --git a/src/main/java/com/atsuishio/superbwarfare/data/CustomData.java b/src/main/java/com/atsuishio/superbwarfare/data/CustomData.java new file mode 100644 index 000000000..aba7b1f60 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/data/CustomData.java @@ -0,0 +1,19 @@ +package com.atsuishio.superbwarfare.data; + +import com.atsuishio.superbwarfare.data.gun.DefaultGunData; +import com.atsuishio.superbwarfare.data.gun.GunData; +import com.atsuishio.superbwarfare.data.gun.ProjectileInfo; +import com.atsuishio.superbwarfare.data.vehicle.DefaultVehicleData; +import com.atsuishio.superbwarfare.data.vehicle.VehicleData; + +import java.util.HashMap; + +public class CustomData { + public static final HashMap LAUNCHABLE_ENTITY = DataLoader.createData("launchable", ProjectileInfo.class); + public static final HashMap VEHICLE = DataLoader.createData("vehicles", DefaultVehicleData.class, map -> VehicleData.dataCache.invalidateAll()); + public static final HashMap GUN = DataLoader.createData("guns", DefaultGunData.class, map -> GunData.dataCache.invalidateAll()); + + // 务必在Mod加载时调用该方法,确保上面的静态数据加载成功 + public static void load() { + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/data/DataLoader.java b/src/main/java/com/atsuishio/superbwarfare/data/DataLoader.java new file mode 100644 index 000000000..6965b59c1 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/data/DataLoader.java @@ -0,0 +1,161 @@ +package com.atsuishio.superbwarfare.data; + +import com.atsuishio.superbwarfare.Mod; +import com.google.gson.Gson; +import net.minecraft.server.packs.resources.ResourceManager; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.OnDatapackSyncEvent; +import net.neoforged.neoforge.event.server.ServerStartedEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +@EventBusSubscriber(modid = Mod.MODID) +public class DataLoader { + + private static final HashMap> loadedData = new HashMap<>(); + + private record GeneralData( + Class type, DataMap proxyMap, + HashMap data, + @Nullable Consumer> onReload + ) { + } + + public static HashMap createData(String name, Class clazz) { + return createData(name, clazz, null); + } + + @SuppressWarnings("unchecked") + public static DataMap createData(String name, Class clazz, @Nullable Consumer> onReload) { + if (loadedData.containsKey(name)) { + return (DataMap) loadedData.get(name).proxyMap; + } else { + var proxyMap = new DataMap(name); + loadedData.put(name, new GeneralData<>(clazz, proxyMap, new HashMap<>(), onReload)); + return proxyMap; + } + } + + private static void reloadAllData(ResourceManager manager) { + loadedData.forEach((name, value) -> { + var map = value.data; + map.clear(); + + for (var entry : manager.listResources(name, file -> file.getPath().endsWith(".json")).entrySet()) { + var attribute = entry.getValue(); + try { + Gson gson = new Gson(); + var data = (IDBasedData) gson.fromJson(new InputStreamReader(attribute.open()), value.type); + + String id; + if (!data.getId().isEmpty()) { + id = data.getId(); + } else { + var path = entry.getKey().getPath(); + id = Mod.MODID + ":" + path.substring(name.length() + 1, path.length() - name.length() - 1); + Mod.LOGGER.warn("{} ID for {} is empty, try using {} as id", name, id, path); + } + + map.put(id, data); + } catch (Exception e) { + Mod.LOGGER.error(e.getMessage()); + } + } + + if (value.onReload != null) { + value.onReload.accept(map); + } + }); + } + + @SubscribeEvent(priority = EventPriority.HIGH) + public static void serverStarted(ServerStartedEvent event) { + reloadAllData(event.getServer().getResourceManager()); + } + + @SubscribeEvent(priority = EventPriority.HIGH) + public static void onDataPackSync(OnDatapackSyncEvent event) { + reloadAllData(event.getPlayerList().getServer().getResourceManager()); + } + + // read-only custom data map + + public static class DataMap extends HashMap { + private final String name; + + private DataMap(String name) { + this.name = name; + } + + @Override + public int size() { + if (!loadedData.containsKey(name)) return 0; + return loadedData.get(name).data.size(); + } + + @Override + public boolean isEmpty() { + if (!loadedData.containsKey(name)) return true; + return loadedData.get(name).data.isEmpty(); + } + + @Override + @SuppressWarnings("unchecked") + public T get(Object key) { + if (!loadedData.containsKey(name)) return null; + return (T) loadedData.get(name).data.get(key); + } + + @Override + public T getOrDefault(Object key, T defaultValue) { + var value = get(key); + return value == null ? defaultValue : value; + } + + @Override + public boolean containsKey(Object key) { + if (!loadedData.containsKey(name)) return false; + return loadedData.get(name).data.containsKey(key); + } + + @Override + public T put(String key, T value) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(Map m) { + throw new UnsupportedOperationException(); + } + + @Override + public T remove(Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsValue(Object value) { + if (!loadedData.containsKey(name)) return false; + return loadedData.get(name).data.containsValue(value); + } + + @Override + public @NotNull Set keySet() { + if (!loadedData.containsKey(name)) return Set.of(); + return loadedData.get(name).data.keySet(); + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/data/IDBasedData.java b/src/main/java/com/atsuishio/superbwarfare/data/IDBasedData.java new file mode 100644 index 000000000..c7ff86c2c --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/data/IDBasedData.java @@ -0,0 +1,5 @@ +package com.atsuishio.superbwarfare.data; + +public interface IDBasedData { + String getId(); +} diff --git a/src/main/java/com/atsuishio/superbwarfare/data/gun/DefaultGunData.java b/src/main/java/com/atsuishio/superbwarfare/data/gun/DefaultGunData.java index f976ede9c..cfdab747f 100644 --- a/src/main/java/com/atsuishio/superbwarfare/data/gun/DefaultGunData.java +++ b/src/main/java/com/atsuishio/superbwarfare/data/gun/DefaultGunData.java @@ -1,15 +1,21 @@ package com.atsuishio.superbwarfare.data.gun; import com.atsuishio.superbwarfare.annotation.ServerOnly; +import com.atsuishio.superbwarfare.data.IDBasedData; import com.google.gson.annotations.SerializedName; import java.util.List; import java.util.Set; -public class DefaultGunData { +public class DefaultGunData implements IDBasedData { @SerializedName("ID") public String id = ""; + @Override + public String getId() { + return this.id; + } + @SerializedName("RecoilX") public double recoilX; @SerializedName("RecoilY") diff --git a/src/main/java/com/atsuishio/superbwarfare/data/gun/ProjectileInfo.java b/src/main/java/com/atsuishio/superbwarfare/data/gun/ProjectileInfo.java index 3ac80a7ff..3faf077b3 100644 --- a/src/main/java/com/atsuishio/superbwarfare/data/gun/ProjectileInfo.java +++ b/src/main/java/com/atsuishio/superbwarfare/data/gun/ProjectileInfo.java @@ -1,13 +1,19 @@ package com.atsuishio.superbwarfare.data.gun; +import com.atsuishio.superbwarfare.data.IDBasedData; import com.google.gson.JsonObject; import com.google.gson.annotations.SerializedName; -public class ProjectileInfo { +public class ProjectileInfo implements IDBasedData { @SerializedName("Type") public String type = "superbwarfare:projectile"; @SerializedName("Data") public JsonObject data; + + @Override + public String getId() { + return type; + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/data/launchable/LaunchableEntityTool.java b/src/main/java/com/atsuishio/superbwarfare/data/launchable/LaunchableEntityTool.java index 295fadd8a..a4fd89b99 100644 --- a/src/main/java/com/atsuishio/superbwarfare/data/launchable/LaunchableEntityTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/data/launchable/LaunchableEntityTool.java @@ -1,51 +1,24 @@ package com.atsuishio.superbwarfare.data.launchable; -import com.atsuishio.superbwarfare.Mod; +import com.atsuishio.superbwarfare.data.CustomData; import com.atsuishio.superbwarfare.data.gun.ProjectileInfo; -import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.nbt.*; -import net.minecraft.server.packs.resources.ResourceManager; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.neoforge.event.OnDatapackSyncEvent; -import net.neoforged.neoforge.event.server.ServerStartedEvent; import org.jetbrains.annotations.Nullable; -import java.io.InputStreamReader; -import java.util.HashMap; import java.util.Locale; +import java.util.Map; -@EventBusSubscriber(modid = Mod.MODID) public class LaunchableEntityTool { - public static HashMap launchableEntitiesData = new HashMap<>(); - - /** - * 初始化数据,从data中读取数据json文件 - */ - public static void initJsonData(ResourceManager manager) { - launchableEntitiesData.clear(); - - for (var entry : manager.listResources("launchable", file -> file.getPath().endsWith(".json")).entrySet()) { - var attribute = entry.getValue(); - try { - Gson gson = new Gson(); - var data = gson.fromJson(new InputStreamReader(attribute.open()), JsonObject.class); - - launchableEntitiesData.put(data.get("Type").getAsString(), data.get("Data").getAsJsonObject()); - } catch (Exception e) { - Mod.LOGGER.error(e.getMessage()); - } - } - } + public static Map launchableEntitiesData = CustomData.LAUNCHABLE_ENTITY; public static @Nullable CompoundTag getModifiedTag(ProjectileInfo projectileInfo, ShootData data) { JsonObject launchableData; if (projectileInfo.data != null) { launchableData = projectileInfo.data; } else if (launchableEntitiesData.containsKey(projectileInfo.type)) { - launchableData = launchableEntitiesData.get(projectileInfo.type); + launchableData = launchableEntitiesData.get(projectileInfo.type).data; } else { return null; } @@ -104,14 +77,4 @@ public class LaunchableEntityTool { default -> StringTag.valueOf(value); }; } - - @SubscribeEvent - public static void serverStarted(ServerStartedEvent event) { - initJsonData(event.getServer().getResourceManager()); - } - - @SubscribeEvent - public static void onDataPackSync(OnDatapackSyncEvent event) { - initJsonData(event.getPlayerList().getServer().getResourceManager()); - } } diff --git a/src/main/java/com/atsuishio/superbwarfare/data/vehicle/DefaultVehicleData.java b/src/main/java/com/atsuishio/superbwarfare/data/vehicle/DefaultVehicleData.java index 16e5b4ffc..21b13f021 100644 --- a/src/main/java/com/atsuishio/superbwarfare/data/vehicle/DefaultVehicleData.java +++ b/src/main/java/com/atsuishio/superbwarfare/data/vehicle/DefaultVehicleData.java @@ -2,15 +2,21 @@ package com.atsuishio.superbwarfare.data.vehicle; import com.atsuishio.superbwarfare.annotation.ServerOnly; import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.data.IDBasedData; import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModify; import com.google.gson.annotations.SerializedName; import java.util.List; -public class DefaultVehicleData { +public class DefaultVehicleData implements IDBasedData { @SerializedName("ID") public String id = ""; + @Override + public String getId() { + return this.id; + } + @SerializedName("MaxHealth") public float maxHealth = 50; diff --git a/src/main/java/com/atsuishio/superbwarfare/data/vehicle/VehicleDataTool.java b/src/main/java/com/atsuishio/superbwarfare/data/vehicle/VehicleDataTool.java index 0bc13b9de..8084d2cda 100644 --- a/src/main/java/com/atsuishio/superbwarfare/data/vehicle/VehicleDataTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/data/vehicle/VehicleDataTool.java @@ -1,55 +1,21 @@ package com.atsuishio.superbwarfare.data.vehicle; import com.atsuishio.superbwarfare.Mod; +import com.atsuishio.superbwarfare.data.CustomData; import com.atsuishio.superbwarfare.network.message.receive.VehiclesDataMessage; -import com.google.gson.Gson; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.packs.resources.ResourceManager; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.event.OnDatapackSyncEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; -import net.neoforged.neoforge.event.server.ServerStartedEvent; import net.neoforged.neoforge.network.PacketDistributor; -import java.io.InputStreamReader; import java.util.HashMap; @EventBusSubscriber(modid = Mod.MODID) public class VehicleDataTool { - public static HashMap vehicleData = new HashMap<>(); - public static final String VEHICLE_DATA_FOLDER = "vehicles"; - - public static void initJsonData(ResourceManager manager) { - vehicleData.clear(); - VehicleData.dataCache.invalidateAll(); - - for (var entry : manager.listResources(VEHICLE_DATA_FOLDER, file -> file.getPath().endsWith(".json")).entrySet()) { - var attribute = entry.getValue(); - - try { - Gson gson = new Gson(); - var data = gson.fromJson(new InputStreamReader(attribute.open()), DefaultVehicleData.class); - - String id; - if (!data.id.isEmpty()) { - id = data.id; - } else { - var path = entry.getKey().getPath(); - id = Mod.MODID + ":" + path.substring(VEHICLE_DATA_FOLDER.length() + 1, path.length() - VEHICLE_DATA_FOLDER.length() - 1); - Mod.LOGGER.warn("Vehicle ID for {} is empty, try using {} as id", id, path); - data.id = id; - } - - if (!vehicleData.containsKey(id)) { - vehicleData.put(id, data); - } - } catch (Exception e) { - Mod.LOGGER.error(e.getMessage()); - } - } - } + public static HashMap vehicleData = CustomData.VEHICLE; @SubscribeEvent public static void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { @@ -63,15 +29,9 @@ public class VehicleDataTool { } } - @SubscribeEvent - public static void serverStarted(ServerStartedEvent event) { - initJsonData(event.getServer().getResourceManager()); - } - @SubscribeEvent public static void onDataPackSync(OnDatapackSyncEvent event) { var server = event.getPlayerList().getServer(); - initJsonData(server.getResourceManager()); var message = VehiclesDataMessage.create(); for (var player : event.getRelevantPlayers().toList()) { diff --git a/src/main/java/com/atsuishio/superbwarfare/item/gun/GunItem.java b/src/main/java/com/atsuishio/superbwarfare/item/gun/GunItem.java index 6a139f28c..02aef54cf 100644 --- a/src/main/java/com/atsuishio/superbwarfare/item/gun/GunItem.java +++ b/src/main/java/com/atsuishio/superbwarfare/item/gun/GunItem.java @@ -654,7 +654,7 @@ public abstract class GunItem extends Item implements CustomRendererItem, GeoIte } else if (LaunchableEntityTool.launchableEntitiesData.containsKey(projectileType)) { var newInfo = new ProjectileInfo(); - newInfo.data = LaunchableEntityTool.launchableEntitiesData.get(projectileType); + newInfo.data = LaunchableEntityTool.launchableEntitiesData.get(projectileType).data; newInfo.type = projectileType; var tag = LaunchableEntityTool.getModifiedTag( diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java index 7d072d512..aadeec7ea 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java @@ -1,64 +1,25 @@ package com.atsuishio.superbwarfare.tools; import com.atsuishio.superbwarfare.Mod; +import com.atsuishio.superbwarfare.data.CustomData; import com.atsuishio.superbwarfare.data.gun.DefaultGunData; -import com.atsuishio.superbwarfare.data.gun.GunData; import com.atsuishio.superbwarfare.network.message.receive.GunsDataMessage; -import com.google.gson.Gson; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.packs.resources.ResourceManager; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.event.OnDatapackSyncEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; -import net.neoforged.neoforge.event.server.ServerStartedEvent; import net.neoforged.neoforge.network.PacketDistributor; import javax.annotation.Nullable; -import java.io.InputStreamReader; import java.util.HashMap; import java.util.UUID; @EventBusSubscriber(modid = Mod.MODID) public class GunsTool { - public static HashMap gunsData = new HashMap<>(); - - public static final String GUN_DATA_FOLDER = "guns"; - - /** - * 初始化数据,从data中读取数据json文件 - */ - public static void initJsonData(ResourceManager manager) { - gunsData.clear(); - GunData.dataCache.invalidateAll(); - - for (var entry : manager.listResources(GUN_DATA_FOLDER, file -> file.getPath().endsWith(".json")).entrySet()) { - var attribute = entry.getValue(); - - try { - Gson gson = new Gson(); - var data = gson.fromJson(new InputStreamReader(attribute.open()), DefaultGunData.class); - - String id; - if (!data.id.trim().isEmpty()) { - id = data.id; - } else { - var path = entry.getKey().getPath(); - id = Mod.MODID + ":" + path.substring(GUN_DATA_FOLDER.length() + 1, path.length() - GUN_DATA_FOLDER.length() - 1); - Mod.LOGGER.warn("Gun ID for {} is empty, try using {} as id", path, id); - data.id = id; - } - - if (!gunsData.containsKey(id)) { - gunsData.put(id, data); - } - } catch (Exception e) { - Mod.LOGGER.error(e.getMessage()); - } - } - } + public static HashMap gunsData = CustomData.GUN; @SubscribeEvent public static void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { @@ -72,15 +33,9 @@ public class GunsTool { } } - @SubscribeEvent - public static void serverStarted(ServerStartedEvent event) { - initJsonData(event.getServer().getResourceManager()); - } - @SubscribeEvent public static void onDataPackSync(OnDatapackSyncEvent event) { var server = event.getPlayerList().getServer(); - initJsonData(server.getResourceManager()); var message = GunsDataMessage.create(); for (var player : event.getRelevantPlayers().toList()) {