Skip to content

Conversation

Outspending
Copy link
Collaborator

@Outspending Outspending commented Jun 22, 2025

Introduces PersistentDataContainer system to support per-entity, per-block, and other persistent data storage mechanisms within Ferrumc. This system is designed to allow developers to safely store and retrieve custom data across various server objects using a type-erased, flexible, and serializable structure.

Key Features

  • PersistentDataContainer Structure:
    • Stores key-value pairs where keys are strings (Identifiers) and values (serde_json::Value) types, supporting flexible, type-safe serialization.
    • Includes a type_map for optional runtime type tracking (useful for debugging and ensuring type consistency).
  • PersistentDataHolder Trait:
    • Provides read-only access to the persistent data via get_persistent_data.
    • Provides controlled, in-place mutation via edit_persistent_data using a closure to ensure thread-safe and idiomatic data editing.
  • Serialization Support
    • PersistentDataContainer supports serde serialization/deserialization to allow saving and loading persistent data easily work world files or other storage backends.
  • Runtime Type Awareness
    • Includes a HashMap<String, TypeId> to track the expected type of each key at runtime if needed, improving safety and debugging visibility.

Benefits

  • Allows entities, players, blocks, and other server components to store custom persistent data.
  • Enables plugin developers to easily attach additional state to objects without modifying core structures.
  • Supports safe, type-aware data access patterns to minimize runtime errors.
  • Flexible serialization with serde_json for potential storage in NBT, JSON, or database formats.

Example Usages

player.edit_persistent_data(|data| {
    data.set("score", 1500);
});

let score = player.get_persistent_data().get::<i32>("score").unwrap_or(0);
use crate::{PersistentDataHolder, PersistentKey, container::PersistentDataContainer};

#[derive(Default)]
struct PlayerTesting {
    data: PersistentDataContainer,
}

impl PersistentDataHolder for PlayerTesting {
    fn get_persistent_data(&self) -> &PersistentDataContainer {
        &self.data
    }

    fn edit_persistent_data<F: FnOnce(&mut PersistentDataContainer)>(&mut self, func: F) {
        func(&mut self.data);
    }
}

#[test]
fn something() {
    let mut testing = PlayerTesting::default();
    let testing_key = PersistentKey::<i32>::new("minecraft", "testing");

    testing.edit_persistent_data(|data| {
        data.set(&testing_key, 100);
    });

    let persistent_data = testing.get_persistent_data();
    if let Ok(grabbed_value) = persistent_data.get(&testing_key) {
        println!("Testing: {}", grabbed_value);
    }
}

Future Improvements

  • Implement custom serializers to support direct NBT encoding.
  • Add a utility API for type-checked retrieval (get_as<T>) and automatic casting.
  • Provide integration hooks for saving persistent data with world and entity files.

Notes

  • This system is intentionally designed to closely align with Minecraft’s PaperMC PersistentDataContainer while leveraging Rust’s type system and memory safety guarantees.
  • The API is flexible and can be extended to support advanced use cases like versioning, migration, and custom serialization formats.

@Outspending Outspending self-assigned this Jun 22, 2025
@Outspending Outspending marked this pull request as draft June 22, 2025 18:26
@Outspending Outspending added the enhancement New feature or request label Jun 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant