fix the fact that I barely use any memory (in progress)
This commit is contained in:
parent
48d7ea164d
commit
8adcfdea38
5 changed files with 113 additions and 30 deletions
|
@ -40,3 +40,4 @@ opentelemetry = "0.21.0"
|
|||
tracing-opentelemetry = "0.22"
|
||||
opentelemetry-jaeger = { version = "0.20", features = ["rt-tokio"] }
|
||||
opentelemetry_sdk = { version = "0.21.1", features = ["trace"] }
|
||||
memoize = "0.4.2"
|
||||
|
|
|
@ -1,46 +1,84 @@
|
|||
use std::{sync::Arc, ops::Sub};
|
||||
|
||||
use anyhow::Ok;
|
||||
use nalgebra::Vector3;
|
||||
use rstar::{PointDistance, RTree, RTreeObject, AABB};
|
||||
use rstar::{PointDistance, RTree, RTreeObject, AABB, Envelope};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::{RwLock, OwnedRwLockReadGuard};
|
||||
use memoize::memoize;
|
||||
|
||||
use crate::{turtle::TurtleCommand, paths::{self, TRANSPARENT}};
|
||||
|
||||
pub type WorldReadLock = OwnedRwLockReadGuard<RTree<Block>>;
|
||||
const CHUNK_SIZE: usize = 16;
|
||||
const CHUNK_VOLUME: usize = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
|
||||
const CHUNK_VEC: Vec3 = Vec3::new(CHUNK_SIZE as i32, CHUNK_SIZE as i32, CHUNK_SIZE as i32);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct World {
|
||||
state: Arc<RwLock<RTree<Block>>>, // interior mutability to get around the
|
||||
// questionable architecture of this project
|
||||
}
|
||||
pub struct World(RTree<Chunk>);
|
||||
|
||||
impl World {
|
||||
pub fn get(&self, block: Vec3) -> Option<Block> {
|
||||
let chunk = block.component_div(&CHUNK_VEC);
|
||||
let chunk = self.get_chunk(chunk)?;
|
||||
chunk.get(block)
|
||||
}
|
||||
|
||||
pub fn set(&mut self, block: Block) -> Option<Block> {
|
||||
let chunk = block.pos.component_div(&CHUNK_VEC);
|
||||
let chunk = self.get_chunk(chunk)?;
|
||||
chunk.set(block)
|
||||
}
|
||||
|
||||
fn get_chunk(&self, block: Vec3) -> &Chunk {
|
||||
let block = block.component_div(&CHUNK_VEC);
|
||||
if let Some(chunk) = self.0.locate_at_point(&block.into()) {
|
||||
return chunk;
|
||||
}
|
||||
self.0.insert(Chunk::new(block));
|
||||
&Chunk::new(block)
|
||||
}
|
||||
|
||||
pub fn get_bulk<const COUNT:usize>(&self, blocks: [Vec3;COUNT]) -> [Option<&Block>;COUNT] {
|
||||
let mut chunk: Option<&Chunk> = None;
|
||||
|
||||
blocks.iter().map(|b|{
|
||||
if !chunk.is_some_and(|c| c.contains(b)) {
|
||||
chunk = Some(self.get_chunk(b));
|
||||
}
|
||||
chunk.unwrap().get(b)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SharedWorld {
|
||||
state: Arc<RwLock<World>>, // interior mutability to get around the
|
||||
// questionable architecture of this project
|
||||
}
|
||||
|
||||
impl SharedWorld {
|
||||
pub fn new() -> Self { Self { state: Arc::new(RwLock::new(RTree::new())) } }
|
||||
pub fn from_tree(tree: RTree<Block>) -> Self { Self { state: Arc::new(RwLock::new(tree)) } }
|
||||
pub async fn to_tree(self) -> RTree<Block> { self.state.write().await.to_owned() }
|
||||
pub async fn tree(&self) -> RTree<Block> { self.state.read().await.clone() }
|
||||
pub fn from_world(tree: World) -> Self { Self { state: Arc::new(RwLock::new(tree)) } }
|
||||
|
||||
pub async fn get(&self, block: Vec3) -> Option<Block> {
|
||||
self.state.read().await.locate_at_point(&block.into()).map(|b| b.to_owned())
|
||||
self.state.read().await.get(block)
|
||||
}
|
||||
|
||||
pub async fn set(&self, block: Block) {
|
||||
self.state.write().await.remove_at_point(&block.pos.into());
|
||||
self.state.write().await.insert(block);
|
||||
self.state.write().await.set(block);
|
||||
}
|
||||
|
||||
/// Returns true if a known non-traversable block exists at the point
|
||||
pub async fn occupied(&self, block: Vec3) -> bool {
|
||||
self.state.read().await.locate_at_point(&block.into()).is_some_and(|b| !TRANSPARENT.contains(&b.name.as_str()))
|
||||
self.get(block).await.is_some_and(|b| !TRANSPARENT.contains(&b.name.as_str()))
|
||||
}
|
||||
|
||||
/// Returns true if a "garbage" block exists at the given point which you are free to destroy
|
||||
pub async fn garbage(&self, block: Vec3) -> bool {
|
||||
self.state.read().await.locate_at_point(&block.into()).is_some_and(|b| paths::difficulty(&b.name).is_some())
|
||||
self.get(block).await.is_some_and(|b| paths::difficulty(&b.name).is_some())
|
||||
}
|
||||
|
||||
pub async fn lock(self) -> WorldReadLock {
|
||||
pub async fn lock(self) -> OwnedRwLockReadGuard<World> {
|
||||
self.state.read_owned().await
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +89,50 @@ pub struct Block {
|
|||
pub pos: Vec3,
|
||||
}
|
||||
|
||||
impl RTreeObject for Block {
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct Chunk {
|
||||
pos: Vec3, /// position in chunk coordinates (world/16)
|
||||
data: [[[Option<Block>;CHUNK_SIZE];CHUNK_SIZE];CHUNK_SIZE]
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
fn new(pos: Vec3) -> Self {
|
||||
Self {
|
||||
pos,
|
||||
data:[[[None;CHUNK_SIZE];CHUNK_SIZE];CHUNK_SIZE]
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, pos: Block) -> Result<(), ()> {
|
||||
let chunk = self.pos.component_mul(&CHUNK_VEC);
|
||||
let local = pos.pos - chunk;
|
||||
if !self.contains(&pos) {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
self.data[local.x][local.y][local.z] = pos;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get(&self, pos: Position) -> Option<&Block> {
|
||||
let chunk = self.pos.component_mul(&CHUNK_VEC);
|
||||
let local = pos.pos - chunk;
|
||||
if !self.contains(&pos) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Ok(self.data[local.x][local.y][local.z])
|
||||
}
|
||||
|
||||
fn contains(&self, pos:&Position) -> bool {
|
||||
let chunk = self.pos.component_mul(&CHUNK_VEC);
|
||||
let local = pos.pos - chunk;
|
||||
AABB::from_corners(chunk, chunk+CHUNK_VEC).contains_point(&local)
|
||||
}
|
||||
}
|
||||
|
||||
impl RTreeObject for Chunk {
|
||||
type Envelope = AABB<[i32; 3]>;
|
||||
|
||||
fn envelope(&self) -> Self::Envelope {
|
||||
|
@ -59,7 +140,7 @@ impl RTreeObject for Block {
|
|||
}
|
||||
}
|
||||
|
||||
impl PointDistance for Block {
|
||||
impl PointDistance for Chunk {
|
||||
fn distance_2(&self, point: &[i32; 3]) -> i32 {
|
||||
(self.pos - Vec3::from(*point)).abs().sum()
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use axum::{
|
|||
routing::{get},
|
||||
Router,
|
||||
};
|
||||
use blocks::{World, Position, };
|
||||
use blocks::{SharedWorld, Position, };
|
||||
use depot::Depots;
|
||||
use opentelemetry::global;
|
||||
use opentelemetry_sdk::{runtime::Tokio, trace::BatchConfig};
|
||||
|
@ -220,7 +220,7 @@ struct SavedState {
|
|||
struct LiveState {
|
||||
turtles: Vec<Arc<RwLock<turtle::Turtle>>>,
|
||||
tasks: Scheduler,
|
||||
world: blocks::World,
|
||||
world: blocks::SharedWorld,
|
||||
depots: Depots,
|
||||
started: Instant,
|
||||
kill: watch::Sender<bool>,
|
||||
|
@ -244,7 +244,7 @@ impl LiveState {
|
|||
};
|
||||
let depots = Depots::from_vec(save.depots);
|
||||
|
||||
Self { turtles: turtles.into_iter().map(|t| Arc::new(RwLock::new(t))).collect(), tasks: scheduler, world: World::from_tree(save.world),
|
||||
Self { turtles: turtles.into_iter().map(|t| Arc::new(RwLock::new(t))).collect(), tasks: scheduler, world: SharedWorld::from_tree(save.world),
|
||||
depots,
|
||||
started: Instant::now(),
|
||||
kill:sender,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
blocks::{World, Position, Direction, Vec3, WorldReadLock},
|
||||
blocks::{SharedWorld, Position, Direction, Vec3, World, nearest, Block},
|
||||
};
|
||||
use rstar::{AABB, Envelope};
|
||||
use tokio::task::spawn_blocking;
|
||||
use tracing::{trace, error};
|
||||
use pathfinding::prelude::astar;
|
||||
|
@ -8,7 +9,7 @@ use pathfinding::prelude::astar;
|
|||
const LOOKUP_LIMIT: usize = 10_000_000;
|
||||
|
||||
#[tracing::instrument(skip(world))]
|
||||
pub async fn route_facing(from: Position, to: Vec3, world: &World) -> Option<Vec<Position>> {
|
||||
pub async fn route_facing(from: Position, to: Vec3, world: &SharedWorld) -> Option<Vec<Position>> {
|
||||
let facing = move |p: &Position| {
|
||||
let ahead = p.dir.unit() + p.pos;
|
||||
let above = Vec3::y() + p.pos;
|
||||
|
@ -19,7 +20,7 @@ pub async fn route_facing(from: Position, to: Vec3, world: &World) -> Option<Vec
|
|||
}
|
||||
|
||||
#[tracing::instrument(skip(world))]
|
||||
pub async fn route(from: Position, to: Position, world: &World) -> Option<Vec<Position>> {
|
||||
pub async fn route(from: Position, to: Position, world: &SharedWorld) -> Option<Vec<Position>> {
|
||||
trace!("routing from {from:?} to {to:?}");
|
||||
// attempt at not crashing by looking infinitely into the abyss
|
||||
if world.get(to.pos).await
|
||||
|
@ -30,7 +31,7 @@ pub async fn route(from: Position, to: Position, world: &World) -> Option<Vec<Po
|
|||
route_to(from, to.pos, move |p| p == &to, world).await
|
||||
}
|
||||
|
||||
async fn route_to<D>(from: Position, to: Vec3, mut done: D, world: &World) -> Option<Vec<Position>>
|
||||
async fn route_to<D>(from: Position, to: Vec3, mut done: D, world: &SharedWorld) -> Option<Vec<Position>>
|
||||
where D: FnMut(&Position) -> bool + Send + 'static {
|
||||
// lock once, we'll be doing a lot of lookups
|
||||
let world = world.clone().lock().await;
|
||||
|
@ -62,14 +63,14 @@ where D: FnMut(&Position) -> bool + Send + 'static {
|
|||
}
|
||||
}
|
||||
|
||||
fn next(from: &Position, world: &WorldReadLock) -> Vec<(Position, u32)> {
|
||||
fn next(from: &Position, world: &World) -> Vec<(Position, u32)> {
|
||||
let mut vec: Vec<(Position, u32)> = Vec::new();
|
||||
|
||||
fn insert(
|
||||
vec: &mut Vec<(Position, u32)>,
|
||||
point: Vec3,
|
||||
orientation: Direction,
|
||||
world: &WorldReadLock,
|
||||
world: &World,
|
||||
unknown: Option<u32>,
|
||||
) {
|
||||
world
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::blocks::Block;
|
|||
use crate::blocks::Direction;
|
||||
use crate::blocks::Position;
|
||||
use crate::blocks::Vec3;
|
||||
use crate::blocks::World;
|
||||
use crate::blocks::SharedWorld;
|
||||
use crate::depot::Depots;
|
||||
use crate::paths::route_facing;
|
||||
|
||||
|
@ -144,7 +144,7 @@ impl Turtle {
|
|||
#[derive(Clone)]
|
||||
pub struct TurtleCommander {
|
||||
sender: Arc<Sender>,
|
||||
world: World,
|
||||
world: SharedWorld,
|
||||
depots: Depots,
|
||||
// everything below is best-effort
|
||||
// TODO: make not bad
|
||||
|
@ -221,7 +221,7 @@ impl TurtleCommander {
|
|||
self.max_fuel.load(std::sync::atomic::Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub fn world(&self) -> World {
|
||||
pub fn world(&self) -> SharedWorld {
|
||||
self.world.clone()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue