Rust (Bevy): ECS Network data structure
I am not quite sure if I completely understand the Entity Component System approach, and probably that is one of the reasons for the emergence of this question. Still struggling with the OOP mindset!
I am trying to create a data structure similar to a network, so for instance, something like a circuit:
So, for instance, entity 4 is connected to 1, 1 to 2, and so on. So far I have understood how to create the components, but I can't understand how the connectivity information should be stored. I believe that the entity should point to another entity?!? I have also imagined that would be even better practice to have a component that would have the connectivity information, but in that case, once again, what should it store? Ideally would be the entities themself, right? How to do it?
do you know?
how many words do you know
See also questions close to this topic
-
how to store a closure to map and call it in another thread?
I just try to write a consumer for rocketmq with rust, and have a PushConsumer like below:
pub struct PushConsumer { consumer: Consumer, handler_map: HashMap<String, Box<dyn Fn(Message) -> ConsumerReturn + Send + 'static>>, } impl Debug for PushConsumer { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { self.consumer.fmt(f) } }
You can see I tried to store a handler with
handler_map
, which must be a trait object as the compiler told me.impl PushConsumer { pub fn new() -> Result<Self, Error> { Ok(Self { consumer: Consumer::new()?, handler_map: HashMap::new(), }) } pub fn with_options(options: ConsumerOptions) -> Result<Self, Error> { Ok(Self { consumer: Consumer::with_options(options)?, handler_map: HashMap::new(), }) } pub fn start(&self) { self.consumer.start(); let handler = self.handler_map.get("").unwrap(); tokio::spawn( async move { loop { handler(Message::new("".to_string(), "".to_string(), "".to_string(), 0, Vec::new(), false)); sleep(Duration::from_secs(5)) } } ); } pub fn shutdown(&self) { self.consumer.shutdown(); } pub fn subscribe<Handler>(&mut self, topic: String, handler: Handler) where Handler: Send + 'static + Fn(Message) -> ConsumerReturn { self.handler_map.insert(topic, Box::new(handler)); } }
I tried to register the handler with method
subscribe
, and use the registered handler instart
method, which have a loop in new tokio thread for recv message (here just a mock). but I got a error here. compiler tell mefuture cannot be sent between threads safely
. I triedArc
、Mutex
but not work correctly. I wan't to know what is the best practice to implement what I want: store a closure or function, and use it in where they need. Please help me, thank you very much.the minimum case as below:
use std::collections::HashMap; use std::thread::sleep; use std::time::Duration; pub struct PushConsumer { handler_map: HashMap<String, Box<dyn Fn() -> String + Send + 'static>>, } impl PushConsumer { pub fn start(&self) { let handler = self.handler_map.get("").unwrap(); tokio::spawn( async move { loop { handler(); sleep(Duration::from_secs(5)) } } ); } pub fn subscribe<Handler>(&mut self, topic: String, handler: Handler) where Handler: Send + 'static + Fn() -> String { self.handler_map.insert(topic, Box::new(handler)); } }
-
HashMap with key referring a field in the value
I want to create a hash map from a vector of entities. I want the key to be a reference to a field in the corresponding value. This is something I have come up with.
struct Entity { id: String, patterns: Vec<Pattern>, } struct Package<'ent> { entity_map: HashMap<&'ent String, Entity>, } impl<'ent> Package<'ent> { fn from(entities: Vec<Entity>) -> Self { let entity_map: HashMap<&String, Entity> = entities.into_iter().map(|e| (&e.id, e)).collect(); Package { entity_map } } }
Of course, this isn't working. I am pretty new to Rust. Is there anything wrong with this approach? How can I achieve what I want? Any help will be appreciated.
-
How to use if let statement with conditions?
I know it's possible to express AND logic between if let statement and a condition like this
if let (Some(a), true) = (b, c == d) { // do something }
But what if I need an OR logic?
if let (Some(a)) = b /* || c == d */ { // do something } else { // do something else }
The only way I figure it out is as follows, but I think it's a little bit ugly as I have to write some code twice
if let (Some(a)) = b { // do something } else if c == d { // do something } else { // do something else }
-
Sending Cisco commands from a text file using Netmiko fails. send_config_set works but send_config_from_file doesn't
- I have been using this link as guide.
XXXXXX:/Test # cat test2.py from netmiko import ConnectHandler with open('commands_ios') as f: commands_list = f.read().splitlines() cisco_D = { 'device_type': 'cisco_ios', 'host': '10.1.1.1', 'username': 'username', 'password': 'password', } net_connect = ConnectHandler(**cisco_D) output = net_connect.send_config_from_file('commands_ios.txt') print(output)
XXXXXX:/Test # python3 test2.py
Traceback (most recent call last): File "test2.py", line 14, in <module> output = net_connect.send_config_from_file('commands_ios.txt') File "/usr/lib/python3.6/site-packages/netmiko/base_connection.py", line 1808, in send_config_from_file with io.open(config_file, "rt", encoding="utf-8") as cfg_file: FileNotFoundError: [Errno 2] No such file or directory: 'commands_ios.txt' AL108564:/Test #
-
NetworkStream.read taking 2 seconds to read data from stream (TCP C#)
I have a TCP request response model in C# where I am communicating with a server. Once the server has written data to the stream, I am reading that data. But
stream.read
is taking 2 seconds to read the data. I need to send an explicit acknowledgement to the server, within 2 seconds but am unable to do so because of the time taken to read the data. Below is my code to read data:byte[] resp = new byte[100000]; var memoryStream = new MemoryStream(); int bytes; String timeStamp = GetTimestamp(DateTime.Now); Console.WriteLine("Before reading data: "); Console.WriteLine(timeStamp); do { bytes = stream.Read(resp, 0, resp.Length); memoryStream.Write(resp, 0, bytes); } while (bytes > 0); timeStamp = GetTimestamp(DateTime.Now); Console.WriteLine("After reading data: "); Console.WriteLine(timeStamp); GenerateAcknowledgemnt(stream); timeStamp = GetTimestamp(DateTime.Now); Console.WriteLine("After sending ack: "); Console.WriteLine(timeStamp);
Below are the timestamps read, in the format yyyyMMddHHmmssff:
Before reading data: 2022050615490817
After reading data: 2022050615491019
After sending ack: 2022050615491020
I have highlighted the seconds bold.
How do I reduce the time that
stream.read
is taking to read? I have tried to wrap the network stream in a BufferedStream as well, but it didn't help. -
Multiple HTTP active sessions connected to an application
Given a C++-application running on a linux-pc. It has an integrated webserver associated with one thread.
Considering that, is it possible to have more than one client (active HTTP-Sessions) connected to the webserver ?
In my mind, I always though we need something like a thread pool in the webserver task. Acceptor threads on a listen socket accept new connection and put it into a connection queue. The task will then pick up connections and service requests.
Is there any possibilities to have multiple session with one thread ?
Many thanks
-
Turn based move -> animation queue
I am trying to build a simple turn based game in bevy-engine and have a design dilemma. During the CPU-player-state there has to be an unit queue, where each of the units' first plans it's move, then the move is animated. Next unit should ideally not start planning (or at least animating) before preceding animation is finished.
How would one approach that in Bevy?
- Should I have a global queue in a resource, and send animation-finished events to take next unit from the queue?
- Or should I rather be very granular with my states and have a: movement-planning(unit) state -> animation(unit) state -> movement-planning(next-unit) etc. (also need a global queue here probably).
- Or should I handle all the units in a loop within a system and perform animations in an async way (is it even possible to await events coming?)
I believe there might be a better way :) On top of that there might be also more complex situations where one unit's turn influences another (eg. one kills another or smth)...
-
How to get Bevy to run longer than 5 seconds on Windows 11 with Geforce RTX 2060
I'm trying to go through the Bevy docs and have noticed that I absoilutely cannot run a single example or basic app for longer than about 5 seconds without getting errors breaking execution. Is there something special outside of the doc's setup needed to get things to run or is Bevy just broken for an up-to-date Windows 11 + Geforce RTX 2060 machine?
Doesn't matter which example I run or try to follow along with the docs, this always happens:
PS C:\Development\GameDev\my_bevy_game> cargo run warning: unused manifest key: target.aarch64-apple-darwin.rustflags warning: unused manifest key: target.x86_64-apple-darwin.rustflags warning: unused manifest key: target.x86_64-pc-windows-msvc.linker warning: unused manifest key: target.x86_64-pc-windows-msvc.rustflags warning: unused manifest key: target.x86_64-unknown-linux-gnu.linker warning: unused manifest key: target.x86_64-unknown-linux-gnu.rustflags Compiling my_bevy_game v0.1.0 (C:\Development\GameDev\my_bevy_game) Finished dev [unoptimized + debuginfo] target(s) in 4.01s Running `target\debug\my_bevy_game.exe` 2022-04-18T15:56:45.590239Z ERROR wgpu_hal::vulkan::instance: GENERAL [Loader Message (0x0)] setupLoaderTrampPhysDevs: Failed during dispatch call of 'vkEnumeratePhysicalDevices' to lower layers or loader to get count. 2022-04-18T15:56:45.591644Z ERROR wgpu_hal::vulkan::instance: objects: (type: INSTANCE, hndl: 0x207c17a7b00, name: ?) 2022-04-18T15:56:45.592432Z ERROR wgpu_hal::vulkan::instance: GENERAL [Loader Message (0x0)] setupLoaderTrampPhysDevs: Failed during dispatch call of 'vkEnumeratePhysicalDevices' to lower layers or loader to get count. 2022-04-18T15:56:45.592561Z ERROR wgpu_hal::vulkan::instance: objects: (type: INSTANCE, hndl: 0x207c17a7b00, name: ?) 2022-04-18T15:56:45.901926Z INFO bevy_render::renderer: AdapterInfo { name: "NVIDIA GeForce RTX 2060", vendor: 4318, device: 7957, device_type: DiscreteGpu, backend: Dx12 } hello Elaina Proctor! hello Renzo Hume! hello Zayna Nieves! 2022-04-18T15:56:48.506223Z ERROR present_frames: wgpu_hal::dx12::instance: ID3D12CommandQueue::Present: Resource state (0x800: D3D12_RESOURCE_STATE_COPY_SOURCE) (promoted from COMMON state) of resource (0x00000207DD7D0A70:'Unnamed ID3D12Resource Object') (subresource: 0) must be in COMMON state when transitioning to use in a different Command List type, because resource state on previous Command List type : D3D12_COMMAND_LIST_TYPE_COPY, is actually incompatible and different from that on the next Command List type : D3D12_COMMAND_LIST_TYPE_DIRECT. [ RESOURCE_MANIPULATION ERROR #990: RESOURCE_BARRIER_MISMATCHING_COMMAND_LIST_TYPE] error: process didn't exit successfully: `target\debug\my_bevy_game.exe` (exit code: 1) PS C:\Development\GameDev\my_bevy_game>
The Rust code I made from the book (please note this happens with the bevy repo's untouched example code as well):
use bevy::prelude::*; pub struct HelloPlugin; struct GreetTimer(Timer); #[derive(Component)] struct Person; #[derive(Component)] struct Name(String); impl Plugin for HelloPlugin { fn build(&self, app: &mut App) { // the reason we call from_seconds with the true flag is to make the timer repeat itself app.insert_resource(GreetTimer(Timer::from_seconds(2.0, true))) .add_startup_system(add_people) .add_system(greet_people); } } fn greet_people(time: Res<Time>, mut timer: ResMut<GreetTimer>, query: Query<&Name, With<Person>>) { // update our timer with the time elapsed since the last update // if that caused the timer to finish, we say hello to everyone if timer.0.tick(time.delta()).just_finished() { for name in query.iter() { println!("hello {}!", name.0); } } } fn add_people(mut commands: Commands) { commands .spawn() .insert(Person) .insert(Name("Elaina Proctor".to_string())); commands .spawn() .insert(Person) .insert(Name("Renzo Hume".to_string())); commands .spawn() .insert(Person) .insert(Name("Zayna Nieves".to_string())); } fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugin(HelloPlugin) .run(); }
You can see from the output that I'm trying to run the my_bevy_game example from the book, but this exact same issue with wgpu occurs on all the examples I've run thus far. What does one need to do to run anything with Bevy?
-- edit --
It would appear that this is a dx12 issue that WGPU needs to address. The proposed workarounds in the Bevy issue don't work for my, and other's, machine. It would appear that Bevy is "broken" irreparably for the time being, due to depending on WGPU.