Advertisement
Armaldio

Untitled

Apr 4th, 2025
274
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 16.36 KB | None | 0 0
  1. use futures_util::StreamExt;
  2. use std::env;
  3. use std::error::Error;
  4. use std::net::SocketAddr;
  5. use std::sync::Arc;
  6. use std::{borrow::Cow, sync::Mutex, time::Instant};
  7. use steamworks::AppId;
  8. use steamworks::Client;
  9. use steamworks::FriendFlags;
  10. use steamworks::PersonaStateChange;
  11. use tauri::WebviewWindow;
  12. use tauri::{async_runtime, Emitter, Manager, RunEvent, WindowEvent};
  13. use tokio::sync::mpsc::{Receiver, Sender};
  14. use tokio::sync::oneshot;
  15. use warp::Filter;
  16.  
  17. pub struct WgpuState<'win> {
  18.    pub queue: wgpu::Queue,
  19.    pub device: wgpu::Device,
  20.    pub surface: wgpu::Surface<'win>,
  21.     pub render_pipeline: wgpu::RenderPipeline,
  22.     pub config: Mutex<wgpu::SurfaceConfiguration>,
  23. }
  24.  
  25. impl WgpuState<'_> {
  26.    pub async fn new(window: WebviewWindow) -> Self {
  27.        let size = window.inner_size().unwrap();
  28.        let instance = wgpu::Instance::default();
  29.        let surface = instance.create_surface(window).unwrap();
  30.        let adapter = instance
  31.            .request_adapter(&wgpu::RequestAdapterOptions {
  32.                power_preference: wgpu::PowerPreference::default(),
  33.                force_fallback_adapter: false,
  34.                compatible_surface: Some(&surface),
  35.            })
  36.            .await
  37.            .expect("Failed to find an appropriate adapter");
  38.  
  39.        let (device, queue) = adapter
  40.            .request_device(
  41.                &wgpu::DeviceDescriptor {
  42.                    label: None,
  43.                    required_features: wgpu::Features::empty(),
  44.                    required_limits: wgpu::Limits::downlevel_webgl2_defaults()
  45.                        .using_resolution(adapter.limits()),
  46.                },
  47.                None,
  48.            )
  49.            .await
  50.            .expect("Failed to create device");
  51.  
  52.        let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
  53.            label: None,
  54.            source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(
  55.                r#"
  56. @vertex
  57. fn vs_main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4<f32> {
  58.    var position: vec4<f32>;
  59.    switch (vertex_index) {
  60.        case 0u: {
  61.            position = vec4<f32>(-1.0, -1.0, 0.0, 1.0); // Bottom-left
  62.        }
  63.        case 1u: {
  64.            position = vec4<f32>( 1.0, -1.0, 0.0, 1.0); // Bottom-right
  65.        }
  66.        case 2u: {
  67.            position = vec4<f32>( 0.0,  1.0, 0.0, 1.0); // Top-center
  68.        }
  69.        default: {
  70.            position = vec4<f32>(0.0, 0.0, 0.0, 1.0); // Default case (should not be reached)
  71.        }
  72.    }
  73.    return position;
  74. }
  75.  
  76. @fragment
  77. fn fs_main() -> @location(0) vec4<f32> {
  78.    // Output a solid color
  79.    return vec4<f32>(0.0, 1.0, 0.0, 0.5); // Green
  80. }
  81.  
  82.    "#,
  83.            )),
  84.        });
  85.  
  86.        let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
  87.            label: None,
  88.            push_constant_ranges: &[],
  89.            bind_group_layouts: &[],
  90.        });
  91.  
  92.        let swapchain_capabilities = surface.get_capabilities(&adapter);
  93.        println!("swapchain_capabilities {:?}", swapchain_capabilities);
  94.        let swapchain_format = swapchain_capabilities.formats[0];
  95.  
  96.        let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
  97.            label: None,
  98.            layout: Some(&pipeline_layout),
  99.            vertex: wgpu::VertexState {
  100.                module: &shader,
  101.                entry_point: "vs_main",
  102.                buffers: &[],
  103.                compilation_options: wgpu::PipelineCompilationOptions::default(),
  104.            },
  105.            fragment: Some(wgpu::FragmentState {
  106.                module: &shader,
  107.                entry_point: "fs_main",
  108.                targets: &[Some(wgpu::ColorTargetState {
  109.                    format: swapchain_format,
  110.                    blend: Some(wgpu::BlendState::ALPHA_BLENDING),
  111.                    write_mask: wgpu::ColorWrites::ALL,
  112.                })],
  113.                compilation_options: wgpu::PipelineCompilationOptions::default(),
  114.            }),
  115.            primitive: wgpu::PrimitiveState::default(),
  116.            depth_stencil: None,
  117.            multisample: wgpu::MultisampleState::default(),
  118.            multiview: None,
  119.        });
  120.  
  121.        let alpha_mode = if swapchain_capabilities
  122.            .alpha_modes
  123.            .contains(&wgpu::CompositeAlphaMode::PreMultiplied)
  124.        {
  125.            wgpu::CompositeAlphaMode::PreMultiplied
  126.        } else {
  127.            swapchain_capabilities.alpha_modes[0]
  128.        };
  129.  
  130.        let config = wgpu::SurfaceConfiguration {
  131.            width: size.width,
  132.            height: size.height,
  133.            format: swapchain_format,
  134.            usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
  135.            present_mode: wgpu::PresentMode::Fifo,
  136.            alpha_mode,
  137.            view_formats: vec![],
  138.            desired_maximum_frame_latency: 2,
  139.        };
  140.  
  141.        surface.configure(&device, &config);
  142.  
  143.        Self {
  144.            device,
  145.            queue,
  146.            surface,
  147.            render_pipeline,
  148.            config: Mutex::new(config),
  149.        }
  150.    }
  151. }
  152.  
  153. #[tauri::command]
  154. fn showOverlay() {
  155.    println!("Showing overlay");
  156.    match Client::init_app(480) {
  157.        Ok((client, _single)) => {
  158.            println!("Client created");
  159.            client.friends().activate_game_overlay("hey");
  160.            println!("Overlay shown");
  161.        }
  162.        Err(e) => eprintln!("Failed to initialize Steam client: {:?}", e),
  163.    }
  164. }
  165.  
  166. async fn websocket_server(tx: Sender<String>, mut rx: Receiver<String>) {
  167.    let addr = SocketAddr::from(([127, 0, 0, 1], 31753));
  168.  
  169.    // WebSocket upgrade
  170.    let ws_route = warp::path::end()
  171.        .and(warp::ws())
  172.        .map(move |ws: warp::ws::Ws| {
  173.            let tx = tx.clone();
  174.            ws.on_upgrade(move |websocket| async move {
  175.                let (mut ws_tx, mut ws_rx) = websocket.split();
  176.  
  177.                // Forward messages to the sender
  178.                while let Some(result) = ws_rx.next().await {
  179.                    if let Ok(msg) = result {
  180.                        if let Ok(text) = msg.to_str() {
  181.                            println!("Received WebSocket message: {}", text);
  182.                            if tx.send(text.to_string()).await.is_err() {
  183.                                eprintln!("Failed to send message to channel");
  184.                                break;
  185.                            }
  186.                        }
  187.                    }
  188.                }
  189.            })
  190.        });
  191.  
  192.    let routes = ws_route;
  193.  
  194.    // Spawn HTTP server
  195.    tokio::spawn(warp::serve(routes).run(addr));
  196.    println!("WebSocket server running on ws://{}", addr);
  197.  
  198.    // Process messages from the receiver
  199.    while let Some(message) = rx.recv().await {
  200.        println!("Processing message: {}", message);
  201.        // Handle messages as needed
  202.    }
  203. }
  204.  
  205. fn setup_wgpu_overlay(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
  206.    println!("Webgpu rendering");
  207.  
  208.    let window = app.get_webview_window("main").unwrap();
  209.    let size = window.inner_size()?;
  210.  
  211.    // Create a WgpuState (containing the device, instance, adapter etc.)
  212.    // And store it in the state
  213.    let wgpu_state = async_runtime::block_on(WgpuState::new(window));
  214.    app.manage(Arc::new(wgpu_state));
  215.  
  216.    let app_handle = app.app_handle().clone();
  217.  
  218.    async_runtime::spawn(async move {
  219.        let wgpu_state = app_handle.state::<Arc<WgpuState>>();
  220.  
  221.        while true {
  222.            let t = Instant::now();
  223.  
  224.            let output = match wgpu_state.surface.get_current_texture() {
  225.                Ok(output) => output,
  226.                Err(wgpu::SurfaceError::Lost) => {
  227.                    println!("Surface lost, recreating surface...");
  228.                    continue;
  229.                }
  230.                Err(wgpu::SurfaceError::OutOfMemory) => {
  231.                    eprintln!("Out of memory error");
  232.                    continue;
  233.                }
  234.                Err(e) => {
  235.                    eprintln!("Failed to acquire next swap chain texture: {:?}", e);
  236.                    continue;
  237.                }
  238.            };
  239.            // let view = output
  240.            //     .texture
  241.            //     .create_view(&wgpu::TextureViewDescriptor::default());
  242.  
  243.            // let mut encoder = wgpu_state
  244.            //     .device
  245.            //     .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
  246.            // {
  247.            //     let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
  248.            //         label: None,
  249.            //         color_attachments: &[Some(wgpu::RenderPassColorAttachment {
  250.            //             view: &view,
  251.            //             resolve_target: None,
  252.            //             ops: wgpu::Operations {
  253.            //                 load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
  254.            //                 store: wgpu::StoreOp::Store,
  255.            //             },
  256.            //         })],
  257.            //         depth_stencil_attachment: None,
  258.            //         timestamp_writes: None,
  259.            //         occlusion_query_set: None,
  260.            //     });
  261.            //     rpass.set_pipeline(&wgpu_state.render_pipeline);
  262.            //     rpass.draw(0..3, 0..1);
  263.            // }
  264.  
  265.            // wgpu_state.queue.submit(Some(encoder.finish()));
  266.  
  267.            // Read the texture data before calling present
  268.            let width = output.texture.size().width as usize;
  269.            let height = output.texture.size().height as usize;
  270.            let bytes_per_pixel = 4; // RGBA8 format
  271.            let unaligned_bytes_per_row = width * bytes_per_pixel;
  272.            let aligned_bytes_per_row = ((unaligned_bytes_per_row + 255) / 256) * 256;
  273.            let buffer_size = aligned_bytes_per_row * output.texture.size().height as usize;
  274.  
  275.            println!(
  276.                "Texture size: width={}, height={}",
  277.                output.texture.size().width,
  278.                output.texture.size().height
  279.            );
  280.  
  281.            let buffer_desc = wgpu::BufferDescriptor {
  282.                label: Some("Staging Buffer"),
  283.                size: buffer_size as wgpu::BufferAddress,
  284.                usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
  285.                mapped_at_creation: false,
  286.            };
  287.            let staging_buffer = wgpu_state.device.create_buffer(&buffer_desc);
  288.  
  289.            let mut encoder = wgpu_state
  290.                .device
  291.                .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
  292.            encoder.copy_texture_to_buffer(
  293.                wgpu::ImageCopyTexture {
  294.                    texture: &output.texture,
  295.                    mip_level: 0,
  296.                    origin: wgpu::Origin3d::ZERO,
  297.                    aspect: wgpu::TextureAspect::All,
  298.                },
  299.                wgpu::ImageCopyBuffer {
  300.                    buffer: &staging_buffer,
  301.                    layout: wgpu::ImageDataLayout {
  302.                        offset: 0,
  303.                        bytes_per_row: Some(aligned_bytes_per_row as u32),
  304.                        rows_per_image: Some(output.texture.size().height),
  305.                    },
  306.                },
  307.                wgpu::Extent3d {
  308.                    width: output.texture.size().width,
  309.                    height: output.texture.size().height,
  310.                    depth_or_array_layers: 1,
  311.                },
  312.            );
  313.            wgpu_state.queue.submit(Some(encoder.finish()));
  314.  
  315.            /** Export frame */
  316.            // Map the buffer to read the data
  317.            // println!("buffer {:?}", staging_buffer);
  318.  
  319.            // Map the staging buffer to read the data
  320.            let buffer_slice = staging_buffer.slice(..);
  321.            let (sender, receiver) = futures::channel::oneshot::channel();
  322.            buffer_slice.map_async(wgpu::MapMode::Read, move |result| {
  323.                sender.send(result).unwrap();
  324.            });
  325.            wgpu_state.device.poll(wgpu::Maintain::Wait);
  326.  
  327.            receiver.await;
  328.  
  329.            let unaligned_width = output.texture.size().width as usize;
  330.            let height = output.texture.size().height as usize;
  331.  
  332.            let data = buffer_slice.get_mapped_range();
  333.            let image_data = data.to_vec(); // Copy buffer data to a Vec<u8>.
  334.            drop(data); // Release the buffer mapping.
  335.  
  336.            // println!("image_data {:?}", image_data);
  337.  
  338.            let mut reconstructed_data = Vec::with_capacity(unaligned_bytes_per_row * height);
  339.  
  340.            for row in 0..height {
  341.                let start = row * aligned_bytes_per_row;
  342.                let end = start + unaligned_bytes_per_row; // Only take the valid portion
  343.                reconstructed_data.extend_from_slice(&image_data[start..end]);
  344.            }
  345.  
  346.            assert_eq!(reconstructed_data.len(), unaligned_bytes_per_row * height);
  347.            println!("Reconstructed data size: {}", reconstructed_data.len());
  348.  
  349.            // println!(
  350.            //     "image_data {:?}, expected {:?}",
  351.            //     image_data.len(),
  352.            //     aligned_bytes_per_row * height
  353.            // );
  354.            // println!(
  355.            //     "reconstructed_data {:?}, expected {:?}",
  356.            //     reconstructed_data.len(),
  357.            //     aligned_bytes_per_row * height
  358.            // );
  359.            // println!("Expected 1920000");
  360.  
  361.            // Send the data to the webview
  362.            let window = app_handle.get_webview_window("main").unwrap();
  363.            if let Err(e) = window.emit("frame-data", reconstructed_data) {
  364.                eprintln!("Failed to emit data: {:?}", e);
  365.            }
  366.  
  367.            /** End */
  368.            // Now call present
  369.            output.present();
  370.  
  371.            println!("Frame rendered in: {}ms", t.elapsed().as_millis());
  372.        }
  373.    });
  374.  
  375.    Ok(())
  376. }
  377.  
  378. async fn setup_app<'a>(app: &'a mut tauri::App) -> Result<(), Box<dyn Error>> {
  379.    // Setup HTTP + WebSocket server
  380.    let (tx, rx) = tokio::sync::mpsc::channel::<String>(32);
  381.  
  382.    tokio::spawn(async move {
  383.        websocket_server(tx, rx).await;
  384.    });
  385.  
  386.    Ok(())
  387. }
  388.  
  389. #[cfg_attr(mobile, tauri::mobile_entry_point)]
  390. pub fn run() {
  391.    let init = match Client::init_app(480) {
  392.        Ok(val) => {
  393.            let (client, single) = val;
  394.            let _cb = client.register_callback(|p: PersonaStateChange| {
  395.                println!("Got callback: {:?}", p);
  396.            });
  397.  
  398.            let utils = client.utils();
  399.            println!("Utils:");
  400.            println!("AppId: {:?}", utils.app_id());
  401.            println!("UI Language: {}", utils.ui_language());
  402.  
  403.            let apps = client.apps();
  404.            println!("Apps");
  405.            println!("IsInstalled(480): {}", apps.is_app_installed(AppId(480)));
  406.            println!("InstallDir(480): {}", apps.app_install_dir(AppId(480)));
  407.            println!("BuildId: {}", apps.app_build_id());
  408.            println!("AppOwner: {:?}", apps.app_owner());
  409.            println!("Langs: {:?}", apps.available_game_languages());
  410.            println!("Lang: {}", apps.current_game_language());
  411.            println!("Beta: {:?}", apps.current_beta_name());
  412.  
  413.            let friends = client.friends();
  414.            println!("Friends");
  415.            let list = friends.get_friends(FriendFlags::IMMEDIATE);
  416.            println!("{:?}", list);
  417.            for f in &list {
  418.                println!("Friend: {:?} - {}({:?})", f.id(), f.name(), f.state());
  419.                friends.request_user_information(f.id(), true);
  420.            }
  421.        }
  422.        Err(err) => {
  423.            println!("Error {}", err);
  424.        }
  425.    };
  426.  
  427.    tauri::Builder::default()
  428.        .plugin(tauri_plugin_fs::init())
  429.        .setup(move |app| {
  430.            println!("setup");
  431.            let _ = setup_wgpu_overlay(app);
  432.            setup_app(app);
  433.            Ok(())
  434.        })
  435.        .invoke_handler(tauri::generate_handler![showOverlay])
  436.        .build(tauri::generate_context!())
  437.        .expect("error while running tauri application")
  438.        .run(|app_handle, event| match event {
  439.            RunEvent::WindowEvent {
  440.                label: _,
  441.                event: WindowEvent::Resized(size),
  442.                ..
  443.            } => {
  444.                //
  445.            }
  446.            RunEvent::MainEventsCleared => {}
  447.            _ => (),
  448.        });
  449. }
  450.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement