Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ parchment_mappings_version=2024.11.17
mod_id=pmweatherapi
mod_name=PMWeatherAPI
mod_license=GNU GPL 3.0
mod_version=0.15.3.2
mod_version=0.15.3.3-rc1
mod_group_id=net.nullved
mod_authors=NullVed
mod_authors=nullved
mod_description=An API for interfacing with ProtoManly's Weather Mod

# Dependencies
Expand Down
33 changes: 29 additions & 4 deletions src/main/java/net/nullved/pmweatherapi/PMWeatherAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,28 @@
import net.neoforged.neoforge.client.gui.ConfigurationScreen;
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
import net.nullved.pmweatherapi.client.data.PMWClientStorages;
import net.nullved.pmweatherapi.client.metar.MetarClientStorage;
import net.nullved.pmweatherapi.client.radar.RadarClientStorage;
import net.nullved.pmweatherapi.client.radar.WSRClientStorage;
import net.nullved.pmweatherapi.client.render.IDOverlay;
import net.nullved.pmweatherapi.client.render.RadarOverlays;
import net.nullved.pmweatherapi.config.PMWClientConfig;
import net.nullved.pmweatherapi.data.PMWStorages;
import net.nullved.pmweatherapi.example.ExampleOverlay;
import net.nullved.pmweatherapi.metar.MetarServerStorage;
import net.nullved.pmweatherapi.metar.MetarStorage;
import net.nullved.pmweatherapi.metar.MetarStorageData;
import net.nullved.pmweatherapi.network.PMWNetworking;
import net.nullved.pmweatherapi.radar.RadarMode;
import net.nullved.pmweatherapi.radar.storage.*;
import net.nullved.pmweatherapi.storage.data.BlockPosData;
import net.nullved.pmweatherapi.storage.data.StorageDataManager;
import org.checkerframework.checker.units.qual.C;
import org.slf4j.Logger;

import java.awt.*;

@Mod(PMWeatherAPI.MODID)
public class PMWeatherAPI {
public static final String MODID = "pmweatherapi";
Expand All @@ -40,20 +55,30 @@ public PMWeatherAPI(IEventBus modEventBus, ModContainer modContainer) {
}

private void commonSetup(FMLCommonSetupEvent event) {
// if (!ModList.get().isLoaded("pmweather")) {
// throw new RuntimeException("ProtoManly's Weather not detected!");
// }
StorageDataManager.register(BlockPosData.ID, BlockPosData::deserializeFromNBT);
StorageDataManager.register(RadarStorageData.ID, RadarStorageData::deserializeFromNBT);
StorageDataManager.register(MetarStorageData.ID, MetarStorageData::deserializeFromNBT);
StorageDataManager.register(WSRStorageData.ID, WSRStorageData::deserializeFromNBT);

PMWStorages.registerStorage(RadarStorage.ID, RadarServerStorage.class, RadarServerStorage::new);
PMWStorages.registerStorage(MetarStorage.ID, MetarServerStorage.class, MetarServerStorage::new);
PMWStorages.registerStorage(WSRStorage.ID, WSRServerStorage.class, WSRServerStorage::new);
}

private void registerPayloads(RegisterPayloadHandlersEvent event) {
PMWNetworking.register(event.registrar("1"));
}

private void clientSetup(FMLClientSetupEvent event) {
//RadarMode.removeBaseRendering(true);

PMWClientStorages.registerStorage(RadarStorage.ID, RadarClientStorage.class, RadarClientStorage::new);
PMWClientStorages.registerStorage(MetarStorage.ID, MetarClientStorage.class, MetarClientStorage::new);
PMWClientStorages.registerStorage(WSRStorage.ID, WSRClientStorage.class, WSRClientStorage::new);

RadarOverlays.registerOverlay(() -> IDOverlay.INSTANCE);
//RadarOverlays.registerOverlay(() -> ExampleOverlay.INSTANCE);
}

public static ResourceLocation rl(String path) {
return ResourceLocation.fromNamespaceAndPath(MODID, path);
}
Expand Down
107 changes: 107 additions & 0 deletions src/main/java/net/nullved/pmweatherapi/client/data/IClientStorage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package net.nullved.pmweatherapi.client.data;

import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.*;
import net.nullved.pmweatherapi.PMWeatherAPI;
import net.nullved.pmweatherapi.client.radar.RadarClientStorage;
import net.nullved.pmweatherapi.network.S2CStoragePacket;
import net.nullved.pmweatherapi.storage.IStorage;
import net.nullved.pmweatherapi.storage.data.IStorageData;
import net.nullved.pmweatherapi.storage.data.StorageData;

import java.util.Objects;
import java.util.stream.Collectors;

/**
* The interface defining the client-side implementation of a Storage such as {@link RadarClientStorage}
* <br><br>
* Every time the client changes dimension, a new {@link IClientStorage} is created for each storage.
* @since 0.15.3.3
*/
public interface IClientStorage<D extends IStorageData> extends IStorage<D> {
ClientLevel getLevel();

/**
* Syncs all data from a {@link S2CStoragePacket} with operation {@code overwrite} into this storage's memory
* @param tag The {@link CompoundTag} of the data
* @since 0.15.3.3
*/
default void syncAll(CompoundTag tag) {
clean();
syncAdd(tag);
}

/**
* Syncs data from a {@link S2CStoragePacket} with operation {@code add} into this storage's memory
* @param tag The {@link CompoundTag} of the data
* @since 0.15.3.3
*/
default void syncAdd(CompoundTag tag) {
int version = tag.getInt("version");
if (tag.contains("list") && tag.getBoolean("list")) {
// list format
ListTag list = tag.getList("data", ListTag.TAG_COMPOUND);
add(list.stream().map((t -> {
try {
return (D) StorageData.deserializeFromNBT((CompoundTag) t, version);
} catch (ClassCastException e) {
PMWeatherAPI.LOGGER.info("Invalid data entry in NBT: {}", e.getMessage());
return null;
}
})).filter(Objects::nonNull).collect(Collectors.toSet()));
} else {
try {
add((D) StorageData.deserializeFromNBT(tag.getCompound("data"), version));
} catch (ClassCastException e) {
PMWeatherAPI.LOGGER.info("Invalid data entry in NBT: {}", e.getMessage());
}
}
}

/**
* Syncs data from a {@link S2CStoragePacket} with operation {@code remove} into this storage's memory
* @param tag The {@link CompoundTag} of the data
* @since 0.15.3.3
*/
default void syncRemove(CompoundTag tag) {
int version = tag.getInt("version");
if (!tag.contains("format")) {
// data
if (tag.contains("list") && tag.getBoolean("list")) {
// list format
ListTag list = tag.getList("data", ListTag.TAG_COMPOUND);
removeByData(list.stream().map((t -> {
try {
return (D) StorageData.deserializeFromNBT((CompoundTag) t, version);
} catch (ClassCastException e) {
PMWeatherAPI.LOGGER.info("Invalid data entry in NBT: {}", e.getMessage());
return null;
}
})).filter(Objects::nonNull).collect(Collectors.toSet()));
} else {
// not list format
try {
remove((D) StorageData.deserializeFromNBT(tag.getCompound("data"), version));
} catch (ClassCastException e) {
PMWeatherAPI.LOGGER.info("Invalid data entry in NBT: {}", e.getMessage());
}
}
} else if (tag.getString("format").equals("blockpos")) {
if (tag.contains("list") && tag.getBoolean("list")) {
// list format
ListTag list = tag.getList("data", ListTag.TAG_INT_ARRAY);
removeByPos(list.stream().map(t -> {
if (t instanceof IntArrayTag iat) {
return new BlockPos(iat.get(0).getAsInt(), iat.get(1).getAsInt(), iat.get(2).getAsInt());
} else return null;
}).collect(Collectors.toSet()));
} else {
// not list format
remove(NbtUtils.readBlockPos(tag, "data").orElseThrow());
}
} else {
PMWeatherAPI.LOGGER.info("Invalid data format for packet: '{}'!", tag.getString("format"));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
package net.nullved.pmweatherapi.client.data;

import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
import net.nullved.pmweatherapi.PMWeatherAPI;
import net.nullved.pmweatherapi.client.metar.MetarClientStorage;
import net.nullved.pmweatherapi.client.radar.RadarClientStorage;
import net.nullved.pmweatherapi.client.radar.WSRClientStorage;
import net.nullved.pmweatherapi.client.storage.ClientStorageInstance;
import net.nullved.pmweatherapi.metar.MetarStorage;
import net.nullved.pmweatherapi.metar.MetarStorageData;
import net.nullved.pmweatherapi.radar.RadarMode;
import net.nullved.pmweatherapi.radar.storage.RadarStorage;
import net.nullved.pmweatherapi.radar.storage.WSRStorage;
import net.nullved.pmweatherapi.radar.storage.WSRStorageData;
import net.nullved.pmweatherapi.storage.data.IStorageData;
import net.nullved.pmweatherapi.storage.data.StorageData;
import net.nullved.pmweatherapi.radar.storage.RadarStorageData;

import java.awt.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

/**
* A class holding the specific storage instances for the client
Expand All @@ -25,44 +40,122 @@ public class PMWClientStorages {
*/
public static Map<BlockPos, Map<RadarMode, Map<Integer, Color>>> RADAR_MODE_COLORS = new HashMap<>();

private static Level lastLevel;
private static RadarClientStorage radar;
public static final Map<ResourceLocation, ClientStorageInstance<?, ?>> STORAGE_INSTANCES = new HashMap<>();

private static ClientLevel lastLevel;

/**
* Resets this client's internal radar storage
* Gets the {@link ClientStorageInstance} of the {@link RadarClientStorage}
* @return The {@link ClientStorageInstance}
* @since 0.14.15.3
*/
public static void resetRadars() {
radar = null;
public static ClientStorageInstance<RadarStorageData, RadarClientStorage> radars() {
return get(RadarStorage.ID, RadarClientStorage.class).orElseThrow();
}

/**
* Gets the radar storage for the dimension this client is currently in
* @return A {@link RadarClientStorage}
* @since 0.14.15.3
* Gets the {@link ClientStorageInstance} of the {@link MetarClientStorage}
* @return The {@link ClientStorageInstance}
* @since 0.15.3.3
*/
public static RadarClientStorage getRadars() {
try {
Level level = Minecraft.getInstance().level;
if (radar == null || level != lastLevel) {
init(level);
}
} catch (Exception e) {
PMWeatherAPI.LOGGER.error(e.getMessage(), e);
}
public static ClientStorageInstance<MetarStorageData, MetarClientStorage> metars() {
return get(MetarStorage.ID, MetarClientStorage.class).orElseThrow();
}

return radar;
/**
* Gets the {@link ClientStorageInstance} of the {@link WSRClientStorage}
* @return The {@link ClientStorageInstance}
* @since 0.15.3.3
*/
public static ClientStorageInstance<WSRStorageData, WSRClientStorage> wsrs() {
return get(WSRStorage.ID, WSRClientStorage.class).orElseThrow();
}

/**
* Initializes this client's storages to be the storages for the given level
* @param level The {@link Level} to initialize storages for
* @since 0.14.15.3
* Get a {@link ClientStorageInstance} for a given {@link ResourceLocation} ID
* @param location The ID of the storage
* @return A {@link ClientStorageInstance}
* @since 0.15.3.3
*/
public static void init(Level level) {
lastLevel = level;
if (level != null) {
radar = new RadarClientStorage(level.dimension());
public static ClientStorageInstance<?, ?> get(ResourceLocation location) {
if (!STORAGE_INSTANCES.containsKey(location)) {
PMWeatherAPI.LOGGER.error("No storage instance found for location {}", location);
}

ClientLevel curLevel = Minecraft.getInstance().level;
if (curLevel != null && curLevel != lastLevel) {
loadDimension(curLevel);
}

ClientStorageInstance<?, ?> csi = STORAGE_INSTANCES.get(location);
if (csi.get() == null) {
csi.load(curLevel);
}

return csi;
}

/**
* Overwrite a {@link ClientStorageInstance}
* @param location The ID {@link ResourceLocation}
* @param instance The new {@link ClientStorageInstance}
* @since 0.15.3.3
*/
public static void set(ResourceLocation location, ClientStorageInstance<?, ?> instance) {
STORAGE_INSTANCES.put(location, instance);
}

/**
* Casts the {@link ClientStorageInstance} to the specified {@link IClientStorage} class after retrieval
* @param location The ID {@link ResourceLocation}
* @param clazz The {@link Class} of an {@link IClientStorage} to cast to
* @return The casted {@link ClientStorageInstance}
* @param <D> The {@link IStorageData} of the {@link IClientStorage}
* @param <T> The {@link IClientStorage}
* @since 0.15.3.3
*/
public static <D extends StorageData, T extends IClientStorage<D>> Optional<ClientStorageInstance<D, T>> get(ResourceLocation location, Class<T> clazz) {
return get(location).cast(clazz);
}

/**
* Gets all {@link ClientStorageInstance}s
* @return A {@link Collection} of all {@link ClientStorageInstance}s
* @since 0.15.3.3
*/
public static Collection<? extends ClientStorageInstance<?, ?>> getAll() {
return STORAGE_INSTANCES.values();
}

/**
* Resets all data for all {@link ClientStorageInstance}s
* @since 0.15.3.3
*/
public static void resetAll() {
getAll().forEach(ClientStorageInstance::clear);
}

/**
* Loads a new {@link ClientLevel} for all {@link ClientStorageInstance}s
* @param clientLevel The new {@link ClientLevel} to load
* @since 0.15.3.3
*/
public static void loadDimension(ClientLevel clientLevel) {
lastLevel = clientLevel;
STORAGE_INSTANCES.forEach((location, instance) -> instance.load(clientLevel));
}

/**
* Register a new {@link IClientStorage}
* @param id The {@link ResourceLocation} to save this {@link IClientStorage} as
* @param clazz The {@link Class} of the {@link IClientStorage}
* @param creator A function creating another {@link IClientStorage} for the given {@link ClientLevel}
* @param <D> The {@link IStorageData} of the {@link IClientStorage}
* @param <C> The {@link IClientStorage}
* @since 0.15.3.3
*/
public static <D extends StorageData, C extends IClientStorage<D>> void registerStorage(ResourceLocation id, Class<C> clazz, Function<ClientLevel, C> creator) {
ClientStorageInstance<D, C> instance = new ClientStorageInstance<>(id, clazz, creator);
STORAGE_INSTANCES.put(id, instance);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package net.nullved.pmweatherapi.client.event;

import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.level.LevelAccessor;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.event.level.LevelEvent;
import net.nullved.pmweatherapi.PMWeatherAPI;
import net.nullved.pmweatherapi.client.data.PMWClientStorages;

@EventBusSubscriber(modid = PMWeatherAPI.MODID, value = Dist.CLIENT)
public class PMWClientEvents {
@SubscribeEvent
public static void onLevelLoadEvent(LevelEvent.Load event) {
LevelAccessor level = event.getLevel();
if (level.isClientSide() && level instanceof ClientLevel clevel) {
PMWeatherAPI.LOGGER.info("Loaded client storages for dimension {}", clevel.dimension().location());
PMWClientStorages.loadDimension(clevel);
}
}

@SubscribeEvent
public static void onLevelUnloadEvent(LevelEvent.Unload event) {
LevelAccessor level = event.getLevel();
if (level.isClientSide() && level instanceof ClientLevel clevel) {
PMWeatherAPI.LOGGER.info("Unloaded client storages for dimension {}", clevel.dimension().location());
}
}
}
Loading
Loading