feat(plugin-api): add get biome
This commit is contained in:
parent
e2ff17d6f0
commit
95893b7463
37
pumpkin-codegen/src/wit/biome.rs
Normal file
37
pumpkin-codegen/src/wit/biome.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use semver::Version;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs;
|
||||
use wit_encoder::{Enum, Interface, Package, PackageName, TypeDef, TypeDefKind};
|
||||
|
||||
pub fn build() -> String {
|
||||
let json: BTreeMap<String, serde_json::Value> =
|
||||
serde_json::from_str(&fs::read_to_string("../assets/biome.json").unwrap())
|
||||
.expect("Failed to parse biome.json");
|
||||
|
||||
let mut package = Package::new(PackageName::new(
|
||||
"pumpkin",
|
||||
"plugin",
|
||||
Some(Version::new(0, 1, 0)),
|
||||
));
|
||||
let mut interface = Interface::new("biomes");
|
||||
|
||||
let mut biome_enum = Enum::empty();
|
||||
let mut biome_vec = json.keys().collect::<Vec<_>>();
|
||||
biome_vec.sort();
|
||||
|
||||
for raw_name in biome_vec {
|
||||
let name = raw_name
|
||||
.strip_prefix("minecraft:")
|
||||
.unwrap_or(raw_name)
|
||||
.replace('_', "-");
|
||||
biome_enum.case(name);
|
||||
}
|
||||
|
||||
interface.type_def(TypeDef::new(
|
||||
"biome",
|
||||
TypeDefKind::Enum(biome_enum),
|
||||
));
|
||||
package.interface(interface);
|
||||
|
||||
package.to_string()
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
pub mod bedrock_packet;
|
||||
pub mod biome;
|
||||
pub mod data_component;
|
||||
pub mod enchantment;
|
||||
pub mod entity_type;
|
||||
@ -30,6 +31,7 @@ pub fn main() {
|
||||
(bedrock_packet::build, "bedrock-packets.wit"),
|
||||
(data_component::build, "data-components.wit"),
|
||||
(enchantment::build, "enchantments.wit"),
|
||||
(biome::build, "biomes.wit"),
|
||||
];
|
||||
|
||||
for (build_fn, file) in build_functions {
|
||||
|
||||
71
pumpkin-plugin-wit/v0.1/biomes.wit
Normal file
71
pumpkin-plugin-wit/v0.1/biomes.wit
Normal file
@ -0,0 +1,71 @@
|
||||
package pumpkin:plugin@0.1.0;
|
||||
|
||||
interface biomes {
|
||||
enum biome {
|
||||
badlands,
|
||||
bamboo-jungle,
|
||||
basalt-deltas,
|
||||
beach,
|
||||
birch-forest,
|
||||
cherry-grove,
|
||||
cold-ocean,
|
||||
crimson-forest,
|
||||
dark-forest,
|
||||
deep-cold-ocean,
|
||||
deep-dark,
|
||||
deep-frozen-ocean,
|
||||
deep-lukewarm-ocean,
|
||||
deep-ocean,
|
||||
desert,
|
||||
dripstone-caves,
|
||||
end-barrens,
|
||||
end-highlands,
|
||||
end-midlands,
|
||||
eroded-badlands,
|
||||
flower-forest,
|
||||
forest,
|
||||
frozen-ocean,
|
||||
frozen-peaks,
|
||||
frozen-river,
|
||||
grove,
|
||||
ice-spikes,
|
||||
jagged-peaks,
|
||||
jungle,
|
||||
lukewarm-ocean,
|
||||
lush-caves,
|
||||
mangrove-swamp,
|
||||
meadow,
|
||||
mushroom-fields,
|
||||
nether-wastes,
|
||||
ocean,
|
||||
old-growth-birch-forest,
|
||||
old-growth-pine-taiga,
|
||||
old-growth-spruce-taiga,
|
||||
pale-garden,
|
||||
plains,
|
||||
river,
|
||||
savanna,
|
||||
savanna-plateau,
|
||||
small-end-islands,
|
||||
snowy-beach,
|
||||
snowy-plains,
|
||||
snowy-slopes,
|
||||
snowy-taiga,
|
||||
soul-sand-valley,
|
||||
sparse-jungle,
|
||||
stony-peaks,
|
||||
stony-shore,
|
||||
sunflower-plains,
|
||||
swamp,
|
||||
taiga,
|
||||
the-end,
|
||||
the-void,
|
||||
warm-ocean,
|
||||
warped-forest,
|
||||
windswept-forest,
|
||||
windswept-gravelly-hills,
|
||||
windswept-hills,
|
||||
windswept-savanna,
|
||||
wooded-badlands,
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ interface %world {
|
||||
use particles.{particle};
|
||||
use sounds.{sound};
|
||||
use entity-types.{entity-type};
|
||||
use biomes.{biome};
|
||||
use uuid.{uuid};
|
||||
|
||||
/// Defines how a block reacts when pushed by a piston.
|
||||
@ -258,6 +259,12 @@ interface %world {
|
||||
/// Sets the block light level at the specified position.
|
||||
set-block-light: func(pos: block-pos, level: u8);
|
||||
|
||||
/// Returns the biome at the specified position.
|
||||
get-biome: func(pos: block-pos) -> biome;
|
||||
|
||||
/// Spawns an entity of the specified type at the given position.
|
||||
spawn-entity: func(entity-type: entity-type, pos: position) -> entity;
|
||||
|
||||
/// Returns a list of all entities in this world.
|
||||
get-entities: func() -> list<entity>;
|
||||
}
|
||||
|
||||
@ -72,32 +72,23 @@ impl HostEntity for PluginHostState {
|
||||
entity: Resource<Entity>,
|
||||
) -> wasmtime::Result<entity_types::EntityType> {
|
||||
let entity = entity_from_resource(self, &entity)?;
|
||||
let name = entity.get_entity().entity_type.resource_name.to_string();
|
||||
// Standard WIT enum mapping: kebab-case
|
||||
let _wit_name = name.replace('_', "-");
|
||||
// We need to find the variant in the generated enum.
|
||||
// Since we don't have a direct mapping function yet, we use debug format or similar if available,
|
||||
// but for now let's just use the fact that it's an enum.
|
||||
// Actually, the easiest way is to use the generated `from_name` or similar if we added it,
|
||||
// but here we are returning it TO the guest.
|
||||
let original_name = entity.get_entity().entity_type.resource_name;
|
||||
|
||||
// Wait, I need to CONSTRUCT the EntityType enum.
|
||||
// I can't easily do it by string unless I have a mapping.
|
||||
// But wit-bindgen generates the enum.
|
||||
let mut names: Vec<String> = serde_json::from_str::<
|
||||
std::collections::BTreeMap<String, serde_json::Value>,
|
||||
>(&std::fs::read_to_string("assets/entities.json")?)?
|
||||
.keys()
|
||||
.cloned()
|
||||
.collect();
|
||||
names.sort();
|
||||
|
||||
// Let's assume there is a way to construct it.
|
||||
// Actually, I can use the fact that it's a simple enum.
|
||||
// I'll use a hack for now if I don't have a better way, but wait!
|
||||
// I can just use `serde_json` to parse the string into the enum if it implements Deserialize!
|
||||
// Or just a match.
|
||||
let index = names
|
||||
.iter()
|
||||
.position(|n| n == original_name)
|
||||
.ok_or_else(|| wasmtime::Error::msg(format!("Unknown entity type: {original_name}")))?;
|
||||
|
||||
// Better: let's see if pumpkin_data has a way.
|
||||
// For now, I'll just return a placeholder or implement a basic match for the most common ones
|
||||
// OR better: use the generated code.
|
||||
|
||||
Err(wasmtime::Error::msg(
|
||||
"get_type implementation pending full enum mapping",
|
||||
))
|
||||
// Safety: The WIT enum is generated from the sorted keys of assets/entities.json.
|
||||
Ok(unsafe { std::mem::transmute::<u8, entity_types::EntityType>(index as u8) })
|
||||
}
|
||||
|
||||
async fn get_position(&mut self, entity: Resource<Entity>) -> wasmtime::Result<Position> {
|
||||
|
||||
@ -41,6 +41,7 @@ impl pumpkin::plugin::java_packets::Host for PluginHostState {}
|
||||
impl pumpkin::plugin::bedrock_packets::Host for PluginHostState {}
|
||||
impl pumpkin::plugin::data_components::Host for PluginHostState {}
|
||||
impl pumpkin::plugin::enchantments::Host for PluginHostState {}
|
||||
impl pumpkin::plugin::biomes::Host for PluginHostState {}
|
||||
|
||||
pub fn add_to_linker(linker: &mut Linker<PluginHostState>) -> wasmtime::Result<()> {
|
||||
Plugin::add_to_linker::<_, HasSelf<_>>(linker, |state: &mut PluginHostState| state)?;
|
||||
|
||||
@ -403,6 +403,69 @@ impl pumpkin::plugin::world::HostWorld for PluginHostState {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_biome(
|
||||
&mut self,
|
||||
world: Resource<World>,
|
||||
pos: WitBlockPos,
|
||||
) -> wasmtime::Result<pumpkin::plugin::biomes::Biome> {
|
||||
let world_ref = self.get_world_res(&world)?;
|
||||
let internal_pos = BlockPos::new(pos.x, pos.y, pos.z);
|
||||
let biome = world_ref.provider.get_biome(&internal_pos);
|
||||
|
||||
let mut names: Vec<String> = serde_json::from_str::<
|
||||
std::collections::BTreeMap<String, serde_json::Value>,
|
||||
>(&std::fs::read_to_string("assets/biome.json")?)?
|
||||
.keys()
|
||||
.cloned()
|
||||
.collect();
|
||||
names.sort();
|
||||
|
||||
let index = names
|
||||
.iter()
|
||||
.position(|n| n.strip_prefix("minecraft:").unwrap_or(n) == biome.registry_id)
|
||||
.ok_or_else(|| wasmtime::Error::msg(format!("Unknown biome: {}", biome.registry_id)))?;
|
||||
|
||||
// Safety: The WIT enum is generated from the sorted keys of assets/biome.json.
|
||||
Ok(unsafe { std::mem::transmute::<u8, pumpkin::plugin::biomes::Biome>(index as u8) })
|
||||
}
|
||||
|
||||
async fn spawn_entity(
|
||||
&mut self,
|
||||
world: Resource<World>,
|
||||
entity_type: pumpkin::plugin::entity_types::EntityType,
|
||||
pos: pumpkin::plugin::common::Position,
|
||||
) -> wasmtime::Result<Resource<pumpkin::plugin::world::Entity>> {
|
||||
let world_ref = self.get_world_res(&world)?;
|
||||
let world_provider = world_ref.provider.clone();
|
||||
|
||||
let mut names: Vec<String> = serde_json::from_str::<
|
||||
std::collections::BTreeMap<String, serde_json::Value>,
|
||||
>(&std::fs::read_to_string("assets/entities.json")?)?
|
||||
.keys()
|
||||
.cloned()
|
||||
.collect();
|
||||
names.sort();
|
||||
|
||||
let type_name = names.get(entity_type as usize).ok_or_else(|| {
|
||||
wasmtime::Error::msg(format!("Invalid entity type index: {}", entity_type as u8))
|
||||
})?;
|
||||
|
||||
let internal_type = pumpkin_data::entity::EntityType::from_name(type_name)
|
||||
.ok_or_else(|| wasmtime::Error::msg(format!("Invalid entity type: {type_name}")))?;
|
||||
|
||||
let internal_pos = pumpkin_util::math::vector3::Vector3::new(pos.0, pos.1, pos.2);
|
||||
let entity = crate::entity::r#type::from_type(
|
||||
internal_type,
|
||||
internal_pos,
|
||||
&world_provider,
|
||||
uuid::Uuid::new_v4(),
|
||||
);
|
||||
|
||||
world_provider.spawn_entity(entity.clone()).await;
|
||||
|
||||
self.add_entity(entity)
|
||||
}
|
||||
|
||||
async fn get_entities(
|
||||
&mut self,
|
||||
world: Resource<World>,
|
||||
|
||||
@ -3444,6 +3444,23 @@ impl World {
|
||||
.set_sky_light_level(&self.level, position, light_level);
|
||||
}
|
||||
|
||||
pub fn get_biome(&self, position: &BlockPos) -> &'static Biome {
|
||||
let chunk_pos = position.chunk_position();
|
||||
if let Some(chunk) = self.level.loaded_chunks.get(&chunk_pos) {
|
||||
let id = chunk
|
||||
.section
|
||||
.get_rough_biome_absolute_y(
|
||||
(position.0.x & 15) as usize,
|
||||
position.0.y,
|
||||
(position.0.z & 15) as usize,
|
||||
)
|
||||
.unwrap_or(0);
|
||||
Biome::from_id(id).unwrap_or(&Biome::PLAINS)
|
||||
} else {
|
||||
&Biome::PLAINS
|
||||
}
|
||||
}
|
||||
|
||||
pub fn schedule_block_tick(
|
||||
&self,
|
||||
block: &Block,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user