@pipelab/asset-tauri 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/LICENSE +110 -0
  2. package/package.json +18 -0
  3. package/template/README.md +7 -0
  4. package/template/index.html +45 -0
  5. package/template/package.json +23 -0
  6. package/template/pnpm-lock.yaml +715 -0
  7. package/template/src-tauri/Cargo.lock +11191 -0
  8. package/template/src-tauri/Cargo.toml +40 -0
  9. package/template/src-tauri/build.rs +3 -0
  10. package/template/src-tauri/capabilities/default.json +7 -0
  11. package/template/src-tauri/icons/128x128.png +0 -0
  12. package/template/src-tauri/icons/128x128@2x.png +0 -0
  13. package/template/src-tauri/icons/32x32.png +0 -0
  14. package/template/src-tauri/icons/Square107x107Logo.png +0 -0
  15. package/template/src-tauri/icons/Square142x142Logo.png +0 -0
  16. package/template/src-tauri/icons/Square150x150Logo.png +0 -0
  17. package/template/src-tauri/icons/Square284x284Logo.png +0 -0
  18. package/template/src-tauri/icons/Square30x30Logo.png +0 -0
  19. package/template/src-tauri/icons/Square310x310Logo.png +0 -0
  20. package/template/src-tauri/icons/Square44x44Logo.png +0 -0
  21. package/template/src-tauri/icons/Square71x71Logo.png +0 -0
  22. package/template/src-tauri/icons/Square89x89Logo.png +0 -0
  23. package/template/src-tauri/icons/StoreLogo.png +0 -0
  24. package/template/src-tauri/icons/icon.icns +0 -0
  25. package/template/src-tauri/icons/icon.ico +0 -0
  26. package/template/src-tauri/icons/icon.png +0 -0
  27. package/template/src-tauri/src/lib copy 2.rs +438 -0
  28. package/template/src-tauri/src/lib copy.rs +449 -0
  29. package/template/src-tauri/src/lib.rs +616 -0
  30. package/template/src-tauri/src/lib_webview_screenshot.rs +430 -0
  31. package/template/src-tauri/src/main.rs +6 -0
  32. package/template/src-tauri/tauri.conf.json +36 -0
  33. package/template/tsconfig.json +23 -0
@@ -0,0 +1,40 @@
1
+ [package]
2
+ name = "pipelab"
3
+ version = "1.0.0"
4
+ description = "A Tauri App"
5
+ authors = ["you"]
6
+ edition = "2021"
7
+
8
+ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
9
+
10
+ [profile.dev]
11
+ opt-level = 0 # Optimize for size
12
+
13
+ [lib]
14
+ # The `_lib` suffix may seem redundant but it is necessary
15
+ # to make the lib name unique and wouldn't conflict with the bin name.
16
+ # This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
17
+ name = "tauri_lib"
18
+ crate-type = ["staticlib", "cdylib", "rlib"]
19
+
20
+ [build-dependencies]
21
+ tauri-build = { version = "2", features = [] }
22
+
23
+ [dependencies]
24
+ tauri = { version = "2", features = [] }
25
+ tauri-cli = "2.4.1"
26
+
27
+ serde = { version = "1", features = ["derive"] }
28
+ serde_json = "1"
29
+ # steamworks = "0.11.0"
30
+ tokio = { version = "1.32", features = ["full"] }
31
+ tokio-tungstenite = "0.20"
32
+ futures-util = "0.3"
33
+ anyhow = "1.0"
34
+ dirs = "5.0"
35
+
36
+ tauri-plugin-shell = "2"
37
+ tauri-plugin-fs = "2"
38
+ tauri-plugin-opener = "2"
39
+ tauri-plugin-devtools = "2.0.0"
40
+ tauri-plugin-localhost = "2"
@@ -0,0 +1,3 @@
1
+ fn main() {
2
+ tauri_build::build()
3
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "../gen/schemas/desktop-schema.json",
3
+ "identifier": "default",
4
+ "description": "Capability for the main window",
5
+ "windows": ["main"],
6
+ "permissions": ["core:default", "opener:default"]
7
+ }
@@ -0,0 +1,438 @@
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::Window;
12
+ use tauri::{
13
+ async_runtime, LogicalPosition, LogicalSize, Manager, RunEvent, WebviewUrl, WindowEvent,
14
+ };
15
+ use tokio::sync::mpsc::{Receiver, Sender};
16
+ use warp::Filter;
17
+
18
+ pub struct WgpuState<'win> {
19
+ pub queue: wgpu::Queue,
20
+ pub device: wgpu::Device,
21
+ pub surface: wgpu::Surface<'win>,
22
+ pub render_pipeline: wgpu::RenderPipeline,
23
+ pub config: Mutex<wgpu::SurfaceConfiguration>,
24
+ }
25
+
26
+ impl<'win> WgpuState<'win> {
27
+ pub async fn new(window: Window) -> Self {
28
+ let size = window.inner_size().unwrap();
29
+ let instance = wgpu::Instance::default();
30
+ let surface = instance.create_surface(window).unwrap();
31
+
32
+ let adapters = instance.enumerate_adapters(wgpu::Backends::all()); // Enumerate all backends
33
+
34
+ println!("Available wgpu backends:");
35
+ for adapter in adapters {
36
+ let info = adapter.get_info();
37
+ println!("- {:?}: {:?}", info.backend, info.name);
38
+ }
39
+
40
+ let adapter = instance
41
+ .request_adapter(&wgpu::RequestAdapterOptions {
42
+ power_preference: wgpu::PowerPreference::default(),
43
+ force_fallback_adapter: false,
44
+ compatible_surface: Some(&surface),
45
+ })
46
+ .await
47
+ .expect("Failed to find an appropriate adapter");
48
+
49
+ let (device, queue) = adapter
50
+ .request_device(
51
+ &wgpu::DeviceDescriptor {
52
+ label: None,
53
+ required_features: wgpu::Features::empty(),
54
+ required_limits: wgpu::Limits::downlevel_webgl2_defaults()
55
+ .using_resolution(adapter.limits()),
56
+ },
57
+ None,
58
+ )
59
+ .await
60
+ .expect("Failed to create device");
61
+
62
+ let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
63
+ label: None,
64
+ source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(
65
+ r#"
66
+ @vertex
67
+ fn vs_main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4<f32> {
68
+ var position: vec4<f32>;
69
+ switch (vertex_index) {
70
+ case 0u: {
71
+ position = vec4<f32>(-1.0, -1.0, 0.0, 1.0); // Bottom-left
72
+ }
73
+ case 1u: {
74
+ position = vec4<f32>( 1.0, -1.0, 0.0, 1.0); // Bottom-right
75
+ }
76
+ case 2u: {
77
+ position = vec4<f32>( 0.0, 1.0, 0.0, 1.0); // Top-center
78
+ }
79
+ default: {
80
+ position = vec4<f32>(0.0, 0.0, 0.0, 1.0); // Default case (should not be reached)
81
+ }
82
+ }
83
+ return position;
84
+ }
85
+
86
+ @fragment
87
+ fn fs_main() -> @location(0) vec4<f32> {
88
+ // Output a solid color
89
+ return vec4<f32>(1.0, 0.0, 0.0, 0.5); // Green
90
+ }
91
+
92
+ "#,
93
+ )),
94
+ });
95
+
96
+ let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
97
+ label: None,
98
+ push_constant_ranges: &[],
99
+ bind_group_layouts: &[],
100
+ });
101
+
102
+ let swapchain_capabilities = surface.get_capabilities(&adapter);
103
+ println!("swapchain_capabilities {:?}", swapchain_capabilities);
104
+ let swapchain_format = swapchain_capabilities.formats[0];
105
+
106
+ let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
107
+ label: None,
108
+ layout: Some(&pipeline_layout),
109
+ vertex: wgpu::VertexState {
110
+ module: &shader,
111
+ entry_point: "vs_main",
112
+ buffers: &[],
113
+ compilation_options: wgpu::PipelineCompilationOptions::default(),
114
+ },
115
+ fragment: Some(wgpu::FragmentState {
116
+ module: &shader,
117
+ entry_point: "fs_main",
118
+ targets: &[Some(wgpu::ColorTargetState {
119
+ format: swapchain_format,
120
+ blend: Some(wgpu::BlendState::ALPHA_BLENDING),
121
+ write_mask: wgpu::ColorWrites::ALL,
122
+ })],
123
+ compilation_options: wgpu::PipelineCompilationOptions::default(),
124
+ }),
125
+ primitive: wgpu::PrimitiveState::default(),
126
+ depth_stencil: None,
127
+ multisample: wgpu::MultisampleState::default(),
128
+ multiview: None,
129
+ });
130
+
131
+ if swapchain_capabilities
132
+ .alpha_modes
133
+ .contains(&wgpu::CompositeAlphaMode::PreMultiplied)
134
+ {
135
+ println!("PreMultiplied alpha mode is supported!");
136
+ } else if swapchain_capabilities
137
+ .alpha_modes
138
+ .contains(&wgpu::CompositeAlphaMode::Opaque)
139
+ {
140
+ println!("Only Opaque alpha mode is supported. Transparency will not work.");
141
+ } else {
142
+ println!("No known alpha modes are supported.");
143
+ }
144
+
145
+ let alpha_mode = if swapchain_capabilities
146
+ .alpha_modes
147
+ .contains(&wgpu::CompositeAlphaMode::PreMultiplied)
148
+ {
149
+ wgpu::CompositeAlphaMode::PreMultiplied
150
+ } else {
151
+ swapchain_capabilities.alpha_modes[0]
152
+ };
153
+
154
+ let config = wgpu::SurfaceConfiguration {
155
+ width: size.width,
156
+ height: size.height,
157
+ format: swapchain_format,
158
+ usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
159
+ present_mode: wgpu::PresentMode::Fifo,
160
+ alpha_mode,
161
+ view_formats: vec![],
162
+ desired_maximum_frame_latency: 2,
163
+ };
164
+
165
+ surface.configure(&device, &config);
166
+
167
+ Self {
168
+ device,
169
+ queue,
170
+ surface,
171
+ render_pipeline,
172
+ config: Mutex::new(config),
173
+ }
174
+ }
175
+ }
176
+
177
+ #[tauri::command]
178
+ fn showOverlay() {
179
+ println!("Showing overlay");
180
+ match Client::init_app(480) {
181
+ Ok((client, _single)) => {
182
+ println!("Client created");
183
+ client.friends().activate_game_overlay("hey");
184
+ println!("Overlay shown");
185
+ }
186
+ Err(e) => eprintln!("Failed to initialize Steam client: {:?}", e),
187
+ }
188
+ }
189
+
190
+ async fn websocket_server(tx: Sender<String>, mut rx: Receiver<String>) {
191
+ let addr = SocketAddr::from(([127, 0, 0, 1], 31753));
192
+
193
+ // WebSocket upgrade
194
+ let ws_route = warp::path::end()
195
+ .and(warp::ws())
196
+ .map(move |ws: warp::ws::Ws| {
197
+ let tx = tx.clone();
198
+ ws.on_upgrade(move |websocket| async move {
199
+ let (mut ws_tx, mut ws_rx) = websocket.split();
200
+
201
+ // Forward messages to the sender
202
+ while let Some(result) = ws_rx.next().await {
203
+ if let Ok(msg) = result {
204
+ if let Ok(text) = msg.to_str() {
205
+ println!("Received WebSocket message: {}", text);
206
+ if tx.send(text.to_string()).await.is_err() {
207
+ eprintln!("Failed to send message to channel");
208
+ break;
209
+ }
210
+ }
211
+ }
212
+ }
213
+ })
214
+ });
215
+
216
+ let routes = ws_route;
217
+
218
+ // Spawn HTTP server
219
+ tokio::spawn(warp::serve(routes).run(addr));
220
+ println!("WebSocket server running on ws://{}", addr);
221
+
222
+ // Process messages from the receiver
223
+ while let Some(message) = rx.recv().await {
224
+ println!("Processing message: {}", message);
225
+ // Handle messages as needed
226
+ }
227
+ }
228
+
229
+ fn setup_wgpu_overlay(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
230
+ println!("Webgpu rendering");
231
+
232
+ // let window = app.get_webview_window("main").unwrap();
233
+ let _window = tauri::window::WindowBuilder::new(app, "main")
234
+ .inner_size(800.0, 600.0)
235
+ .transparent(true)
236
+ .build()?;
237
+ let overlay = tauri::window::WindowBuilder::new(app, "overlay")
238
+ .parent(&_window)
239
+ .unwrap()
240
+ .inner_size(800.0, 600.0)
241
+ .transparent(true)
242
+ .always_on_top(true)
243
+ .build()?;
244
+ overlay.set_resizable(false);
245
+ overlay.set_maximizable(false);
246
+ overlay.set_minimizable(false);
247
+ overlay.set_closable(false);
248
+ overlay.set_decorations(false);
249
+ overlay.set_ignore_cursor_events(true);
250
+
251
+ let _overlay = Arc::new(Mutex::new(overlay));
252
+
253
+ let _webview1 = _window.add_child(
254
+ tauri::webview::WebviewBuilder::new("main1", WebviewUrl::App(Default::default()))
255
+ .transparent(true)
256
+ .auto_resize(),
257
+ LogicalPosition::new(0., 0.),
258
+ LogicalSize::new(800.0, 600.0),
259
+ )?;
260
+
261
+ // let _webview2 = app
262
+ // .get_window("overlay")
263
+ // .expect("Overlay window not found")
264
+ // .add_child(
265
+ // tauri::webview::WebviewBuilder::new("overlay1", WebviewUrl::App(Default::default()))
266
+ // .transparent(true)
267
+ // .auto_resize(),
268
+ // LogicalPosition::new(0., 0.),
269
+ // LogicalSize::new(800.0, 600.0),
270
+ // )?;
271
+
272
+ let overlay_window = app.get_window("overlay").expect("Overlay window not found");
273
+
274
+ let wgpu_state = async_runtime::block_on(WgpuState::new(overlay_window));
275
+ let wgpu_state = Arc::new(wgpu_state); // Make wgpu_state Arc<T>
276
+ app.manage(wgpu_state.clone()); // Store a clone in app state
277
+
278
+ Ok(())
279
+ }
280
+
281
+ async fn setup_app<'a>(app: &'a mut tauri::App) -> Result<(), Box<dyn Error>> {
282
+ // Setup HTTP + WebSocket server
283
+ let (tx, rx) = tokio::sync::mpsc::channel::<String>(32);
284
+
285
+ tokio::spawn(async move {
286
+ websocket_server(tx, rx).await;
287
+ });
288
+
289
+ Ok(())
290
+ }
291
+
292
+ #[cfg_attr(mobile, tauri::mobile_entry_point)]
293
+ pub fn run() {
294
+ let init = match Client::init_app(480) {
295
+ Ok(val) => {
296
+ let (client, single) = val;
297
+ let _cb = client.register_callback(|p: PersonaStateChange| {
298
+ println!("Got callback: {:?}", p);
299
+ });
300
+
301
+ let utils = client.utils();
302
+ println!("Utils:");
303
+ println!("AppId: {:?}", utils.app_id());
304
+ println!("UI Language: {}", utils.ui_language());
305
+
306
+ let apps = client.apps();
307
+ println!("Apps");
308
+ println!("IsInstalled(480): {}", apps.is_app_installed(AppId(480)));
309
+ println!("InstallDir(480): {}", apps.app_install_dir(AppId(480)));
310
+ println!("BuildId: {}", apps.app_build_id());
311
+ println!("AppOwner: {:?}", apps.app_owner());
312
+ println!("Langs: {:?}", apps.available_game_languages());
313
+ println!("Lang: {}", apps.current_game_language());
314
+ println!("Beta: {:?}", apps.current_beta_name());
315
+
316
+ let friends = client.friends();
317
+ println!("Friends");
318
+ let list = friends.get_friends(FriendFlags::IMMEDIATE);
319
+ println!("{:?}", list);
320
+ for f in &list {
321
+ println!("Friend: {:?} - {}({:?})", f.id(), f.name(), f.state());
322
+ friends.request_user_information(f.id(), true);
323
+ }
324
+ }
325
+ Err(err) => {
326
+ println!("Error {}", err);
327
+ }
328
+ };
329
+
330
+ tauri::Builder::default()
331
+ .plugin(tauri_plugin_fs::init())
332
+ .setup(move |app| {
333
+ println!("setup");
334
+ let _ = setup_wgpu_overlay(app);
335
+ setup_app(app);
336
+ Ok(())
337
+ })
338
+ .invoke_handler(tauri::generate_handler![showOverlay])
339
+ .build(tauri::generate_context!())
340
+ .expect("error while running tauri application")
341
+ .run(|app_handle, event| match event {
342
+ RunEvent::WindowEvent {
343
+ label: _,
344
+ event: WindowEvent::Resized(size),
345
+ ..
346
+ } => {
347
+ let wgpu_state = app_handle.state::<Arc<WgpuState>>();
348
+ let mut config = wgpu_state.config.lock().unwrap();
349
+ config.width = size.width;
350
+ config.height = size.height;
351
+ wgpu_state.surface.configure(&wgpu_state.device, &config);
352
+ }
353
+ RunEvent::MainEventsCleared => {
354
+ let wgpu_state = app_handle.state::<Arc<WgpuState>>();
355
+ let overlay = app_handle
356
+ .get_window("overlay")
357
+ .expect("Overlay window not found");
358
+ let _window = app_handle.get_window("main").unwrap();
359
+
360
+ let window_position = _window.inner_position().unwrap();
361
+ let window_position2 = _window.outer_position().unwrap();
362
+ let window_size = _window.inner_size().unwrap();
363
+ let window_size2 = _window.outer_size().unwrap();
364
+
365
+ println!("inner_position {:?}", window_position);
366
+ println!("outer_position {:?}", window_position2);
367
+ println!("inner_size {:?}", window_size);
368
+ println!("outer_size {:?}", window_size2);
369
+
370
+ let offsetU = 100 as u32;
371
+ let offsetI = 100 as i32;
372
+
373
+ overlay
374
+ .set_position(LogicalPosition::new(
375
+ window_position.x + offsetI,
376
+ window_position.y + offsetI,
377
+ ))
378
+ .unwrap();
379
+ // overlay.set_position(window_position).unwrap();
380
+ overlay
381
+ .set_size(LogicalSize::new(
382
+ window_size.width - offsetU,
383
+ window_size.height - offsetU,
384
+ ))
385
+ .unwrap();
386
+ // overlay.set_size(window_size).unwrap();
387
+
388
+ let t = Instant::now();
389
+
390
+ let output = match wgpu_state.surface.get_current_texture() {
391
+ Ok(output) => output,
392
+ Err(wgpu::SurfaceError::Lost) => {
393
+ eprintln!("Surface lost, recreating surface...");
394
+ return ();
395
+ }
396
+ Err(wgpu::SurfaceError::OutOfMemory) => {
397
+ eprintln!("Out of memory error");
398
+ return ();
399
+ }
400
+ Err(e) => {
401
+ eprintln!("Failed to acquire next swap chain texture: {:?}", e);
402
+ return ();
403
+ }
404
+ };
405
+ let view = output
406
+ .texture
407
+ .create_view(&wgpu::TextureViewDescriptor::default());
408
+
409
+ let mut encoder = wgpu_state
410
+ .device
411
+ .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
412
+ {
413
+ let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
414
+ label: None,
415
+ color_attachments: &[Some(wgpu::RenderPassColorAttachment {
416
+ view: &view,
417
+ resolve_target: None,
418
+ ops: wgpu::Operations {
419
+ load: wgpu::LoadOp::Clear(wgpu::Color::RED),
420
+ store: wgpu::StoreOp::Store,
421
+ },
422
+ })],
423
+ depth_stencil_attachment: None,
424
+ timestamp_writes: None,
425
+ occlusion_query_set: None,
426
+ });
427
+ rpass.set_pipeline(&wgpu_state.render_pipeline);
428
+ rpass.draw(0..3, 0..1);
429
+ }
430
+
431
+ wgpu_state.queue.submit(Some(encoder.finish()));
432
+ // output.present();
433
+
434
+ println!("Frame rendered in: {}ms", t.elapsed().as_millis());
435
+ }
436
+ _ => (),
437
+ });
438
+ }