aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-04-07 11:47:00 +0200
committermetamuffin <metamuffin@disroot.org>2025-04-07 11:47:00 +0200
commit0df5ea3ee241159ed5083a29e7a6373faa08990b (patch)
tree2afdfbd99c0e9c7854ec6f52c60d06a37f7ae5d3
parentf08eedf7fd7a40c5681316a332b1d6386f2f14c7 (diff)
downloadweareearth-0df5ea3ee241159ed5083a29e7a6373faa08990b.tar
weareearth-0df5ea3ee241159ed5083a29e7a6373faa08990b.tar.bz2
weareearth-0df5ea3ee241159ed5083a29e7a6373faa08990b.tar.zst
works
-rw-r--r--src/earth.proto2
-rw-r--r--src/main.rs93
-rw-r--r--src/mesh.rs43
3 files changed, 77 insertions, 61 deletions
diff --git a/src/earth.proto b/src/earth.proto
index 0f0b3d0..90288d1 100644
--- a/src/earth.proto
+++ b/src/earth.proto
@@ -1,3 +1,5 @@
+// Adapted from https://github.com/retroplasma/earth-reverse-engineering
+
syntax = "proto2";
package earth.proto;
diff --git a/src/main.rs b/src/main.rs
index 733dbcc..988a5ec 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,10 @@
#![feature(array_chunks)]
+pub mod mesh;
+
use anyhow::{Result, bail};
-use glam::Vec3;
+use glam::{DAffine3, DMat4, Vec3};
use log::{debug, error};
+use mesh::convert_mesh;
use prost::{Message, bytes::Bytes};
use proto::{BulkMetadata, NodeData, NodeMetadata, PlanetoidMetadata};
use reqwest::{
@@ -10,15 +13,14 @@ use reqwest::{
};
use std::path::PathBuf;
use tokio::{
- fs::{File, create_dir, create_dir_all},
+ fs::{File, create_dir_all},
io::{AsyncReadExt, AsyncWriteExt},
};
use weareshared::{
- Affine3A, Vec3A,
- resources::{MeshPart, Prefab, RespackEntry},
+ Affine3A,
+ resources::{Prefab, RespackEntry},
respack::save_full_respack,
store::ResourceStore,
- vec3a,
};
#[tokio::main]
@@ -28,77 +30,44 @@ async fn main() -> Result<()> {
let c = GeClient::new().await?;
let entry = c.planetoid_metdata().await?;
- eprintln!("{:#?}", entry);
-
- let mut bulk = c
+ let bulk = c
.bulk_metadata("", entry.root_node_metadata.unwrap().bulk_metadata_epoch())
.await?;
- eprintln!("{:#?}", bulk);
-
let store = ResourceStore::new_memory();
- let mut meshes = Vec::new();
-
+ let mut prefabs = Vec::new();
for node_meta in &bulk.node_metadata {
- let Ok(mut node_data) = c.node_data(&bulk, &node_meta).await else {
+ if unpack_path_and_id(node_meta.path_and_flags()).0.len() != 4 {
+ // toplevel octs are not found
+ // also i want most subdivided
continue;
- };
-
- for m in node_data.meshes {
- let mut index_strip = Vec::new();
+ }
- let strip_len = m.indices[0];
- let mut zeros = 0;
- for i in 0..strip_len {
- let val = m.indices[i as usize + 1];
- index_strip.push((zeros - val) as u32);
- if val == 0 {
- zeros += 1;
- }
- }
- let mut index = Vec::new();
- for i in 0..index_strip.len() - 2 {
- if i & 1 == 0 {
- index.push([index_strip[i + 0], index_strip[i + 1], index_strip[i + 2]]);
- } else {
- index.push([index_strip[i + 0], index_strip[i + 2], index_strip[i + 1]]);
- }
- }
+ let Ok(node_data) = c.node_data(&bulk, &node_meta).await else {
+ continue;
+ };
- let mut positions = Vec::new();
- let vert = m.vertices();
- let vertex_count = vert.len() / 3;
- let (mut x, mut y, mut z) = (0u8, 0u8, 0u8);
- for i in 0..vertex_count {
- x = x.wrapping_add(vert[vertex_count * 0 + i]);
- y = y.wrapping_add(vert[vertex_count * 1 + i]);
- z = z.wrapping_add(vert[vertex_count * 2 + i]);
- positions.push(vec3a(x as f32, y as f32, z as f32));
- }
- // eprintln!("{index:?}");
- // eprintln!("{positions:?}");
+ let transform = DMat4::from_cols_slice(&node_data.matrix_globe_from_mesh);
+ let mut meshes = Vec::new();
+ for m in node_data.meshes {
+ let mesh = convert_mesh(m, &store)?;
meshes.push((
- Affine3A::from_scale(Vec3::splat(0.01)),
- store.set(&MeshPart {
- index: Some(store.set(&index)?),
- va_position: Some(store.set(&positions)?),
- g_double_sided: Some(()),
- ..Default::default()
- })?,
+ Affine3A::from_mat4((transform / 3_000_000.).as_mat4()),
+ mesh,
))
}
- }
- eprintln!("{}", meshes.len());
- let prefab = store.set(&Prefab {
- mesh: meshes,
- ..Default::default()
- })?;
+ prefabs.push(store.set(&Prefab {
+ transform: Some(DAffine3::from_mat4(transform)),
+ mesh: meshes,
+ ..Default::default()
+ })?);
+ }
let entry = store.set(&RespackEntry {
- c_prefab: vec![prefab],
+ c_prefab: prefabs,
..Default::default()
})?;
@@ -167,7 +136,9 @@ impl GeClient {
let texture_format = bulk.default_available_texture_formats();
let imagery_epoch = node.imagery_epoch.unwrap_or(bulk.default_imagery_epoch());
- let node_epoch = bulk.head_node_key.as_ref().unwrap().epoch.unwrap(); // ?
+ let node_epoch = node
+ .epoch
+ .unwrap_or(bulk.head_node_key.as_ref().unwrap().epoch.unwrap()); // ?
let image_epoch_part = if flags & 16 != 0 {
format!("!3u{imagery_epoch}")
diff --git a/src/mesh.rs b/src/mesh.rs
new file mode 100644
index 0000000..d491a97
--- /dev/null
+++ b/src/mesh.rs
@@ -0,0 +1,43 @@
+use crate::proto::Mesh;
+use anyhow::Result;
+use glam::vec3a;
+use weareshared::{packets::Resource, resources::MeshPart, store::ResourceStore};
+
+pub fn convert_mesh(m: Mesh, store: &ResourceStore) -> Result<Resource<MeshPart>> {
+ let mut index_strip = Vec::new();
+ let strip_len = m.indices[0];
+ let mut zeros = 0;
+ for i in 0..strip_len {
+ let val = m.indices[i as usize + 1];
+ index_strip.push((zeros - val) as u32);
+ if val == 0 {
+ zeros += 1;
+ }
+ }
+ let mut index = Vec::new();
+ for i in 0..index_strip.len() - 2 {
+ if i & 1 == 0 {
+ index.push([index_strip[i + 0], index_strip[i + 1], index_strip[i + 2]]);
+ } else {
+ index.push([index_strip[i + 0], index_strip[i + 2], index_strip[i + 1]]);
+ }
+ }
+
+ let mut positions = Vec::new();
+ let vert = m.vertices();
+ let vertex_count = vert.len() / 3;
+ let (mut x, mut y, mut z) = (0u8, 0u8, 0u8);
+ for i in 0..vertex_count {
+ x = x.wrapping_add(vert[vertex_count * 0 + i]);
+ y = y.wrapping_add(vert[vertex_count * 1 + i]);
+ z = z.wrapping_add(vert[vertex_count * 2 + i]);
+ positions.push(vec3a(x as f32, y as f32, z as f32));
+ }
+
+ Ok(store.set(&MeshPart {
+ index: Some(store.set(&index)?),
+ va_position: Some(store.set(&positions)?),
+ g_double_sided: Some(()),
+ ..Default::default()
+ })?)
+}