Skip to main content

World

Struct World 

Source
pub struct World {
    pub ecs: DynEcs,
}
Expand description

The engine’s ECS: a freecs::dynamic::DynEcs group with the core and retained-UI member worlds over one shared entity allocator, plus the engine’s resources. The group keeps the lifecycle log (handle allocation and death anywhere); each member world keeps its own row-level structural log. Member access is world.ecs.worlds[CORE] / world.ecs.worlds[UI]; group operations (spawning, despawn broadcast, liveness) are available directly on World through deref.

Fields§

§ecs: DynEcs

Implementations§

Source§

impl World

Source

pub fn plugin_resource<T>(&self) -> &T
where T: Send + Sync + 'static,

Borrows a plugin-owned resource stored in the ECS resource map, panicking with the type name if the owning plugin was never composed.

Source

pub fn plugin_resource_mut<T>(&mut self) -> &mut T
where T: Send + Sync + 'static,

Mutably borrows a plugin-owned resource stored in the ECS resource map, panicking with the type name if the owning plugin was never composed.

Source

pub fn set<T>(&mut self, entity: Entity, value: T)
where T: Send + Sync + Default + 'static,

Writes T on the member world that registered it, exactly as the group-typed DynEcs::set does. A type no member world has registered is an app component: it lazily registers into the app member world (GAME), creating that world the first time one is written, so game code stores components on engine entities without declaring a schema. Reads of an unregistered type already come back empty (get, has, query_ref); a component a game serializes into snapshots still earns an explicit serde schema, which lazy registration cannot carry.

Methods from Deref<Target = DynEcs>§

Source

pub fn structural_sequence(&self) -> u64

Source

pub fn structural_changes_since(&self, cursor: u64) -> &[StructuralChange]

The group-level lifecycle log: handle allocation (Spawned with mask 0), handle death anywhere (Despawned with mask 0), and group tag flips (TagsAdded/TagsRemoved carrying the tag index in the mask field, since group tags have no mask bits). Row-level history lives in each member world’s own structural log, where an entity is Spawned with a component mask when its first components arrive there.

Source

pub fn trim_structural_log(&mut self, up_to_sequence: u64)

Source

pub fn clear_structural_log(&mut self)

Source

pub fn add_world(&mut self, registry: ComponentRegistry) -> usize

Adds a world built from the given registry and returns its index. Grouped worlds insert rows for live handles they have never stored, which is what lets an entity gain components per world lazily.

Source

pub fn spawn(&mut self) -> Entity

Allocates a handle with no rows anywhere. Give it components through any member world’s set/add_components.

Source

pub fn spawn_with<B>(&mut self, bundle: B) -> Entity
where B: Bundle,

Spawns one group entity carrying the bundle, with each component routed to the member world that registered its type, so a bundle can span worlds. Panics like set if a component type is registered nowhere.

Source

pub fn route<T>(&mut self) -> Option<usize>
where T: Send + Sync + Default + 'static,

Which member world holds T, scanning members in index order and caching the answer in type_routes. Returns None when no member world has registered T; group-typed access never registers lazily, because only a schema decides where a type lives.

Source

pub fn get<T>(&self, entity: Entity) -> Option<&T>
where T: Send + Sync + Default + 'static,

Reads T from whichever member world holds it, no world index required.

Source

pub fn get_mut<T>(&mut self, entity: Entity) -> Option<&mut T>
where T: Send + Sync + Default + 'static,

The mutable form of get; stamps change ticks exactly like the member world’s accessor.

Source

pub fn set<T>(&mut self, entity: Entity, value: T)
where T: Send + Sync + Default + 'static,

Writes T on the member world that registered it, adding the component if the entity lacks it. Panics if no member world has registered T: group-typed access never picks a world for a new type, that is a schema decision.

Source

pub fn has<T>(&self, entity: Entity) -> bool
where T: Send + Sync + Default + 'static,

Whether the entity carries T in whichever member world holds it.

Source

pub fn remove<T>(&mut self, entity: Entity) -> bool
where T: Send + Sync + Default + 'static,

Removes T from the member world that holds it. Returns false when the type is registered nowhere or the entity lacks it.

Source

pub fn query<Q>(&mut self) -> DynQuery<'_, Q>
where Q: QueryTuple,

A typed query against the first member world where every required element of the tuple is registered; optional elements do not constrain the routing. When no member world qualifies the query is empty rather than a panic, mirroring query_ref: an unregistered component matches nothing, and a tuple whose parts live in different member worlds runs through query_join to iterate for real.

Source

pub fn query_join<Q>(&mut self) -> DynJoin<'_, Q>
where Q: QueryTuple,

A typed query whose tuple may span member worlds, joined by entity. One world drives the iteration at full slice speed, the world holding every mutable element; the other worlds resolve their elements per entity at get speed, read-only, skipping entities that lack a required foreign component. Mutable elements in two different worlds panic at for_each: mutate your own state, read theirs, or co-locate the types in one schema when a hot loop needs slice speed for everything. A tuple that resolves to a single world degenerates to a plain scan of it.

Source

pub fn query_join_ref<Q>(&self) -> DynJoinRef<'_, Q>
where Q: ReadQueryTuple,

The read-only cross-world join, a real Iterator on &self: items borrow the group, the driver world walks its tables, and foreign elements resolve per entity, read-only like every join element. Unresolvable routing or filters degrade to an empty iterator, matching query_ref.

Source

pub fn query_ref<Q>(&self) -> DynQueryRef<'_, Q>
where Q: ReadQueryTuple,

The read-only routed query. When no member world registers every required element the query is empty rather than a panic, matching DynWorld::query_ref’s graceful degradation.

Source

pub fn step(&mut self)

Advances the group frame: expires group events past their two-frame window and steps every member world, so one call at frame end drives group-level and world-level event lifetimes and change windows together. This call replaces per-member stepping; call either this or the members’ own steps each frame, never both, or change windows and event expiry advance twice per frame.

Source

pub fn send<T>(&mut self, event: T)
where T: Send + Sync + 'static,

Sends a group-level event, the shared channel for events that cross member-world (and plugin) boundaries; world-local events stay on DynWorld::send. Same two-frame buffer, expired by step.

Source

pub fn read_events<T>(&self) -> &[T]
where T: Send + Sync + 'static,

Everything still buffered for T at the group level, oldest first.

Source

pub fn read_frame_events<T>(&self) -> &[T]
where T: Send + Sync + 'static,

The group-level T events settled at the last step: the previous frame’s frozen set, broadcast without a cursor. See EventChannel::read_frame.

Source

pub fn read_events_since<T>(&self, cursor: u64) -> &[T]
where T: Send + Sync + 'static,

Source

pub fn consume_events<T>(&self, cursor: &mut u64) -> &[T]
where T: Send + Sync + 'static,

The exactly-once group read: yields events sent after the cursor and advances it past them. Keep one u64 cursor per consumer.

Source

pub fn event_sequence<T>(&self) -> u64
where T: Send + Sync + 'static,

Source

pub fn clear_events<T>(&mut self)
where T: Send + Sync + 'static,

Source

pub fn insert_resource<T>(&mut self, value: T)
where T: Send + Sync + 'static,

Inserts a group-level resource, the home for state shared across member worlds and plugins; world-local resources stay on DynWorld::insert_resource.

Source

pub fn insert_resources<B>(&mut self, bundle: B)
where B: ResourceBundle,

Inserts several group-level resources at once from a tuple, each replacing any existing resource of its type. Equivalent to one insert_resource per element.

Source

pub fn resource<T>(&self) -> Option<&T>
where T: Send + Sync + 'static,

Source

pub fn resource_mut<T>(&mut self) -> Option<&mut T>
where T: Send + Sync + 'static,

Source

pub fn res<T>(&self) -> &T
where T: Send + Sync + 'static,

resource for resources that must exist: panics with the type name instead of returning Option.

Source

pub fn res_mut<T>(&mut self) -> &mut T
where T: Send + Sync + 'static,

The mutable form of res.

Source

pub fn remove_resource<T>(&mut self) -> Option<T>
where T: Send + Sync + 'static,

Source

pub fn resource_scope<R, T>( &mut self, f: impl FnOnce(&mut DynEcs, &mut R) -> T, ) -> T
where R: Send + Sync + 'static,

Takes a group resource out, runs the closure with the group and the resource as independent borrows, then puts it back, even when the closure panics. Panics if R is not present.

The closure receives the bare DynEcs, so a host that wraps the group in its own state struct implements ResourceHost and imports ResourceHostExt, whose scope methods lend the host itself to the closure.

Source

pub fn resources_scope<B, T>( &mut self, f: impl FnOnce(&mut DynEcs, &mut B) -> T, ) -> T
where B: ResourceBundle,

The tuple form of resource_scope, same semantics as DynWorld::resources_scope.

Source

pub fn add_world_at( &mut self, expected_index: usize, registry: ComponentRegistry, ) -> usize

add_world with the index asserted against the constant a schema pairs with this member, replacing the hand-written add-then-assert dance. Panics when members register out of declaration order.

Source

pub fn spawn_count(&mut self, count: usize) -> Vec<Entity>

Source

pub fn spawn_entities( &mut self, world_index: usize, mask: u64, count: usize, ) -> Vec<Entity>

Spawns entities with rows in one member world. The handles land in the group lifecycle log as Spawned with mask 0; the component mask lands in that world’s own structural log.

Source

pub fn is_alive(&self, entity: Entity) -> bool

Source

pub fn despawn(&mut self, entity: Entity) -> bool

Despawns the entity across every world, dropping its group tags. Returns false for stale or already-despawned handles. Retirement broadcasts the bumped generation into every world’s location table, 16 bytes per despawned id per world, which is what makes stale writes refusable everywhere.

Source

pub fn despawn_entities(&mut self, entities: &[Entity]) -> Vec<Entity>

Source

pub fn despawn_recursive(&mut self, root: Entity) -> Vec<Entity>

Despawns an entity and every descendant reachable through ChildOf links in any member world, breadth-first over on-demand scans. This is the grouped form of DynWorld::despawn_recursive: each entity dies through the group, so retirement broadcasts into every member world, group tags drop, and the lifecycle log records each death. Link cycles are tolerated, each entity despawns once. Returns the despawned entities.

Source

pub fn register_tag(&mut self) -> usize

Registers a group-level tag and returns its index. Group tags have no mask bit; they filter queries by set reference.

Source

pub fn add_tag(&mut self, tag_index: usize, entity: Entity)

Source

pub fn remove_tag(&mut self, tag_index: usize, entity: Entity) -> bool

Source

pub fn has_tag(&self, tag_index: usize, entity: Entity) -> bool

Source

pub fn query_tag(&self, tag_index: usize) -> impl Iterator<Item = Entity>

Source

pub fn stats(&self) -> EcsStats

The group-level census. See EcsStats for the fields.

Source

pub fn compact(&mut self) -> usize

DynWorld::compact over every member world. Returns the total number of tables dropped.

Source

pub fn tag_type_index<T>(&mut self) -> usize
where T: 'static,

The group tag index for marker type T, registering the tag on first use. Group tags are the natural home for entity-scoped markers: they consume no member world’s mask bits and need no world index to touch.

Source

pub fn lookup_tag_type<T>(&self) -> Option<usize>
where T: 'static,

The group tag index for marker type T if it has been used, without registering it. Falls back to the persisted type names, so marker tags restored by DynEcs::from_snapshot resolve here before the TypeId map is rebuilt.

Source

pub fn add_tag_type<T>(&mut self, entity: Entity)
where T: 'static,

Adds the marker type T’s group tag to an entity, registering the tag on first use.

Source

pub fn remove_tag_type<T>(&mut self, entity: Entity) -> bool
where T: 'static,

Removes the marker type T’s group tag from an entity. Unregistered marker types remove nothing.

Source

pub fn has_tag_type<T>(&self, entity: Entity) -> bool
where T: 'static,

Whether an entity carries the marker type T’s group tag. Unregistered marker types read as absent.

Source

pub fn query_tag_type<T>(&self) -> impl Iterator<Item = Entity>
where T: 'static,

Iterates entities carrying the marker type T’s group tag. Unregistered marker types match nothing.

Source

pub fn tag_set_type<T>(&self) -> Option<&SparseTagSet>
where T: 'static,

The marker type T’s group tag set, for composing into per-world typed queries with with_tag_set/without_tag_set. None until the tag’s first use.

Source

pub fn delta_cursor(&mut self) -> DynEcsDeltaCursor

The group cursor a delta stream starts from, fencing every member’s change window like DynWorld::delta_cursor.

Source

pub fn delta_since( &mut self, cursor: &DynEcsDeltaCursor, ) -> Result<DynEcsDelta, SnapshotError>

DynWorld::delta_since across the whole group: the group’s structural window (handle lifecycle and group tags) plus one world delta per member, each fenced.

Source

pub fn apply_delta(&mut self, delta: &DynEcsDelta) -> Result<(), SnapshotError>

Replays a group delta: group handle lifecycle and group tags in order, then each member’s delta.

Source

pub fn set_component_by_name( &mut self, entity: Entity, name: &str, bytes: &[u8], ) -> Result<(), SnapshotError>

DynWorld::set_component_by_name routed to the member world whose registry carries the name.

Source

pub fn get_component_by_name( &self, entity: Entity, name: &str, ) -> Result<Option<Vec<u8>>, SnapshotError>

DynWorld::get_component_by_name routed to the member world whose registry carries the name.

Source

pub fn snapshot(&self) -> Result<DynEcsSnapshot, SnapshotError>

Trait Implementations§

Source§

impl Default for World

Source§

fn default() -> World

Returns the “default value” for a type. Read more
Source§

impl Deref for World

Source§

type Target = DynEcs

The resulting type after dereferencing.
Source§

fn deref(&self) -> &<World as Deref>::Target

Dereferences the value.
Source§

impl DerefMut for World

Source§

fn deref_mut(&mut self) -> &mut <World as Deref>::Target

Mutably dereferences the value.
Source§

impl EventHost for World

Source§

fn event_bus_mut(&mut self) -> &mut EventBus

The host’s event bus, for reading and writing events.
Source§

fn event_bus(&self) -> &EventBus

The same bus, shared, for reading events behind a &self, such as the frame-settled broadcast EventBus::read_frame. Must return the same bus as event_bus_mut.
Source§

impl ResourceHost for World

Source§

fn resource_map_mut(&mut self) -> &mut ResourceMap

Source§

fn resource_map(&self) -> &ResourceMap

The same map, shared, for reading a resource behind a &self, such as a run condition that checks a state. Must return the same map as resource_map_mut.

Auto Trait Implementations§

§

impl !RefUnwindSafe for World

§

impl !UnwindSafe for World

§

impl Freeze for World

§

impl Send for World

§

impl Sync for World

§

impl Unpin for World

§

impl UnsafeUnpin for World

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_sync(self: Box<T>) -> Box<dyn Any + Sync + Send>

Converts Box<Trait> (where Trait: DowncastSync) to Box<dyn Any + Send + Sync>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Converts Arc<Trait> (where Trait: DowncastSync) to Arc<Any>, which can then be downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T> NoneValue for T
where T: Default,

Source§

type NoneType = T

Source§

fn null_value() -> T

The none-equivalent value.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<H> ResourceHostExt for H
where H: ResourceHost,

Source§

fn resource_scope<R, T>(&mut self, f: impl FnOnce(&mut Self, &mut R) -> T) -> T
where R: Send + Sync + 'static,

Source§

fn resources_scope<B, T>(&mut self, f: impl FnOnce(&mut Self, &mut B) -> T) -> T
where B: ResourceBundle,

The tuple form of resource_scope, with the same presence and distinctness checks before anything is removed and the same reinsertion on panic.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, S> SimdFrom<T, S> for T
where S: Simd,

Source§

fn simd_from(value: T, _simd: S) -> T

Source§

impl<F, T, S> SimdInto<T, S> for F
where T: SimdFrom<F, S>, S: Simd,

Source§

fn simd_into(self, simd: S) -> T

Source§

impl<T> StorageAccess<T> for T

Source§

fn as_borrowed(&self) -> &T

Borrows the value.
Source§

fn into_taken(self) -> T

Takes the value.
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<S, T> Upcast<T> for S
where T: UpcastFrom<S> + ?Sized, S: ?Sized,

Source§

fn upcast(&self) -> &T
where Self: ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider ref type within the Wasm bindgen generics type system. Read more
Source§

fn upcast_into(self) -> T
where Self: Sized + ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider type within the Wasm bindgen generics type system. Read more
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more