@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,430 @@
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
+ use image::{ImageBuffer, Rgba};
18
+
19
+
20
+ pub struct WgpuState<'win> {
21
+ pub queue: wgpu::Queue,
22
+ pub device: wgpu::Device,
23
+ pub surface: wgpu::Surface<'win>,
24
+ pub render_pipeline: wgpu::RenderPipeline,
25
+ pub config: Mutex<wgpu::SurfaceConfiguration>,
26
+ pub webview_texture: Option<wgpu::Texture>, // Add this field
27
+
28
+ }
29
+
30
+ impl<'win> WgpuState<'win> {
31
+ pub async fn new(window: Window) -> Self {
32
+ let size = window.inner_size().unwrap();
33
+ let instance = wgpu::Instance::default();
34
+ let surface = instance.create_surface(window).unwrap();
35
+
36
+ let adapters = instance.enumerate_adapters(wgpu::Backends::all()); // Enumerate all backends
37
+
38
+ println!("Available wgpu backends:");
39
+ for adapter in adapters {
40
+ let info = adapter.get_info();
41
+ println!("- {:?}: {:?}", info.backend, info.name);
42
+ }
43
+
44
+ let adapter = instance
45
+ .request_adapter(&wgpu::RequestAdapterOptions {
46
+ power_preference: wgpu::PowerPreference::default(),
47
+ force_fallback_adapter: false,
48
+ compatible_surface: Some(&surface),
49
+ })
50
+ .await
51
+ .expect("Failed to find an appropriate adapter");
52
+
53
+ let (device, queue) = adapter
54
+ .request_device(
55
+ &wgpu::DeviceDescriptor {
56
+ label: None,
57
+ required_features: wgpu::Features::empty(),
58
+ required_limits: wgpu::Limits::downlevel_webgl2_defaults()
59
+ .using_resolution(adapter.limits()),
60
+ },
61
+ None,
62
+ )
63
+ .await
64
+ .expect("Failed to create device");
65
+
66
+ let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
67
+ label: None,
68
+ source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(
69
+ r#"
70
+ @vertex
71
+ fn vs_main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4<f32> {
72
+ var position: vec4<f32>;
73
+ switch (vertex_index) {
74
+ case 0u: {
75
+ position = vec4<f32>(-1.0, -1.0, 0.0, 1.0); // Bottom-left
76
+ }
77
+ case 1u: {
78
+ position = vec4<f32>( 1.0, -1.0, 0.0, 1.0); // Bottom-right
79
+ }
80
+ case 2u: {
81
+ position = vec4<f32>( 0.0, 1.0, 0.0, 1.0); // Top-center
82
+ }
83
+ default: {
84
+ position = vec4<f32>(0.0, 0.0, 0.0, 1.0); // Default case (should not be reached)
85
+ }
86
+ }
87
+ return position;
88
+ }
89
+
90
+ @fragment
91
+ fn fs_main() -> @location(0) vec4<f32> {
92
+ // Output a solid color
93
+ return vec4<f32>(0.0, 0.0, 0.0, 0.0); // Green
94
+ }
95
+
96
+ "#,
97
+ )),
98
+ });
99
+
100
+ let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
101
+ label: None,
102
+ push_constant_ranges: &[],
103
+ bind_group_layouts: &[],
104
+ });
105
+
106
+ let swapchain_capabilities = surface.get_capabilities(&adapter);
107
+ println!("swapchain_capabilities {:?}", swapchain_capabilities);
108
+ let swapchain_format = swapchain_capabilities.formats[0];
109
+
110
+ let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
111
+ label: None,
112
+ layout: Some(&pipeline_layout),
113
+ vertex: wgpu::VertexState {
114
+ module: &shader,
115
+ entry_point: "vs_main",
116
+ buffers: &[],
117
+ compilation_options: wgpu::PipelineCompilationOptions::default(),
118
+ },
119
+ fragment: Some(wgpu::FragmentState {
120
+ module: &shader,
121
+ entry_point: "fs_main",
122
+ targets: &[Some(wgpu::ColorTargetState {
123
+ format: swapchain_format,
124
+ blend: Some(wgpu::BlendState::ALPHA_BLENDING),
125
+ write_mask: wgpu::ColorWrites::ALL,
126
+ })],
127
+ compilation_options: wgpu::PipelineCompilationOptions::default(),
128
+ }),
129
+ primitive: wgpu::PrimitiveState::default(),
130
+ depth_stencil: None,
131
+ multisample: wgpu::MultisampleState::default(),
132
+ multiview: None,
133
+ });
134
+
135
+ if swapchain_capabilities
136
+ .alpha_modes
137
+ .contains(&wgpu::CompositeAlphaMode::PreMultiplied)
138
+ {
139
+ println!("PreMultiplied alpha mode is supported!");
140
+ } else if swapchain_capabilities
141
+ .alpha_modes
142
+ .contains(&wgpu::CompositeAlphaMode::Opaque)
143
+ {
144
+ println!("Only Opaque alpha mode is supported. Transparency will not work.");
145
+ } else {
146
+ println!("No known alpha modes are supported.");
147
+ }
148
+
149
+ let alpha_mode = if swapchain_capabilities
150
+ .alpha_modes
151
+ .contains(&wgpu::CompositeAlphaMode::PreMultiplied)
152
+ {
153
+ wgpu::CompositeAlphaMode::PreMultiplied
154
+ } else {
155
+ swapchain_capabilities.alpha_modes[0]
156
+ };
157
+
158
+ let config = wgpu::SurfaceConfiguration {
159
+ width: size.width,
160
+ height: size.height,
161
+ format: swapchain_format,
162
+ usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
163
+ present_mode: wgpu::PresentMode::Fifo,
164
+ alpha_mode,
165
+ view_formats: vec![],
166
+ desired_maximum_frame_latency: 2,
167
+ };
168
+
169
+ surface.configure(&device, &config);
170
+
171
+ Self {
172
+ device,
173
+ queue,
174
+ surface,
175
+ render_pipeline,
176
+ config: Mutex::new(config),
177
+ webview_texture: None, // Initialize as None
178
+ }
179
+ }
180
+ }
181
+
182
+ fn render_webview(
183
+ render_pass: &mut wgpu::RenderPass,
184
+ window: &tauri::Window,
185
+ device: &wgpu::Device,
186
+ queue: &wgpu::Queue,
187
+ wgpu_state: &mut WgpuState,
188
+ ) {
189
+ if let Ok(png) = window.get_webview("main1").unwrap().capture(). {
190
+ let image = image::load_from_memory(&png).unwrap();
191
+ let rgba = image.to_rgba8();
192
+ let (width, height) = rgba.dimensions();
193
+ let texture_size = wgpu::Extent3d {
194
+ width,
195
+ height,
196
+ depth_or_array_layers: 1,
197
+ };
198
+ let texture = device.create_texture(&wgpu::TextureDescriptor {
199
+ size: texture_size,
200
+ mip_level_count: 1,
201
+ sample_count: 1,
202
+ dimension: wgpu::TextureDimension::D2,
203
+ format: wgpu::TextureFormat::Rgba8UnormSrgb,
204
+ usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
205
+ label: Some("webview_texture"),
206
+ view_formats: &[],
207
+ });
208
+ queue.write_texture(
209
+ wgpu::ImageCopyTexture {
210
+ texture: &texture,
211
+ mip_level: 0,
212
+ origin: wgpu::Origin3d::ZERO,
213
+ aspect: wgpu::TextureAspect::All,
214
+ },
215
+ &rgba,
216
+ wgpu::ImageDataLayout {
217
+ offset: 0,
218
+ bytes_per_row: Some(4 * width),
219
+ rows_per_image: Some(height),
220
+ },
221
+ texture_size,
222
+ );
223
+ wgpu_state.webview_texture = Some(texture); // Update the texture
224
+ }
225
+ }
226
+
227
+ #[tauri::command]
228
+ fn showOverlay() {
229
+ println!("Showing overlay");
230
+ match Client::init_app(480) {
231
+ Ok((client, _single)) => {
232
+ println!("Client created");
233
+ client.friends().activate_game_overlay("hey");
234
+ println!("Overlay shown");
235
+ }
236
+ Err(e) => eprintln!("Failed to initialize Steam client: {:?}", e),
237
+ }
238
+ }
239
+
240
+ async fn websocket_server(tx: Sender<String>, mut rx: Receiver<String>) {
241
+ let addr = SocketAddr::from(([127, 0, 0, 1], 31753));
242
+
243
+ // WebSocket upgrade
244
+ let ws_route = warp::path::end()
245
+ .and(warp::ws())
246
+ .map(move |ws: warp::ws::Ws| {
247
+ let tx = tx.clone();
248
+ ws.on_upgrade(move |websocket| async move {
249
+ let (mut ws_tx, mut ws_rx) = websocket.split();
250
+
251
+ // Forward messages to the sender
252
+ while let Some(result) = ws_rx.next().await {
253
+ if let Ok(msg) = result {
254
+ if let Ok(text) = msg.to_str() {
255
+ println!("Received WebSocket message: {}", text);
256
+ if tx.send(text.to_string()).await.is_err() {
257
+ eprintln!("Failed to send message to channel");
258
+ break;
259
+ }
260
+ }
261
+ }
262
+ }
263
+ })
264
+ });
265
+
266
+ let routes = ws_route;
267
+
268
+ // Spawn HTTP server
269
+ tokio::spawn(warp::serve(routes).run(addr));
270
+ println!("WebSocket server running on ws://{}", addr);
271
+
272
+ // Process messages from the receiver
273
+ while let Some(message) = rx.recv().await {
274
+ println!("Processing message: {}", message);
275
+ // Handle messages as needed
276
+ }
277
+ }
278
+
279
+ fn setup_wgpu_overlay(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
280
+ println!("Webgpu rendering");
281
+
282
+ // let window = app.get_webview_window("main").unwrap();
283
+ let _window = tauri::window::WindowBuilder::new(app, "main")
284
+ .inner_size(800.0, 600.0)
285
+ .transparent(true)
286
+ .build()?;
287
+
288
+ let _webview1 = _window.add_child(
289
+ tauri::webview::WebviewBuilder::new("main1", WebviewUrl::App(Default::default()))
290
+ .transparent(true)
291
+ .auto_resize(),
292
+ LogicalPosition::new(0., 0.),
293
+ LogicalSize::new(800.0, 600.0),
294
+ )?;
295
+
296
+ let wgpu_state = async_runtime::block_on(WgpuState::new(_window));
297
+ let wgpu_state = Arc::new(wgpu_state); // Make wgpu_state Arc<T>
298
+ app.manage(wgpu_state.clone()); // Store a clone in app state
299
+
300
+ Ok(())
301
+ }
302
+
303
+ async fn setup_app<'a>(app: &'a mut tauri::App) -> Result<(), Box<dyn Error>> {
304
+ // Setup HTTP + WebSocket server
305
+ let (tx, rx) = tokio::sync::mpsc::channel::<String>(32);
306
+
307
+ tokio::spawn(async move {
308
+ websocket_server(tx, rx).await;
309
+ });
310
+
311
+ Ok(())
312
+ }
313
+
314
+ #[cfg_attr(mobile, tauri::mobile_entry_point)]
315
+ pub fn run() {
316
+ let init = match Client::init_app(480) {
317
+ Ok(val) => {
318
+ let (client, single) = val;
319
+ let _cb = client.register_callback(|p: PersonaStateChange| {
320
+ println!("Got callback: {:?}", p);
321
+ });
322
+
323
+ let utils = client.utils();
324
+ println!("Utils:");
325
+ println!("AppId: {:?}", utils.app_id());
326
+ println!("UI Language: {}", utils.ui_language());
327
+
328
+ let apps = client.apps();
329
+ println!("Apps");
330
+ println!("IsInstalled(480): {}", apps.is_app_installed(AppId(480)));
331
+ println!("InstallDir(480): {}", apps.app_install_dir(AppId(480)));
332
+ println!("BuildId: {}", apps.app_build_id());
333
+ println!("AppOwner: {:?}", apps.app_owner());
334
+ println!("Langs: {:?}", apps.available_game_languages());
335
+ println!("Lang: {}", apps.current_game_language());
336
+ println!("Beta: {:?}", apps.current_beta_name());
337
+
338
+ let friends = client.friends();
339
+ println!("Friends");
340
+ let list = friends.get_friends(FriendFlags::IMMEDIATE);
341
+ println!("{:?}", list);
342
+ for f in &list {
343
+ println!("Friend: {:?} - {}({:?})", f.id(), f.name(), f.state());
344
+ friends.request_user_information(f.id(), true);
345
+ }
346
+ }
347
+ Err(err) => {
348
+ println!("Error {}", err);
349
+ }
350
+ };
351
+
352
+ tauri::Builder::default()
353
+ .plugin(tauri_plugin_fs::init())
354
+ .setup(move |app| {
355
+ println!("setup");
356
+ let _ = setup_wgpu_overlay(app);
357
+ setup_app(app);
358
+ Ok(())
359
+ })
360
+ .invoke_handler(tauri::generate_handler![showOverlay])
361
+ .build(tauri::generate_context!())
362
+ .expect("error while running tauri application")
363
+ .run(|app_handle, event| match event {
364
+ RunEvent::WindowEvent {
365
+ label: _,
366
+ event: WindowEvent::Resized(size),
367
+ ..
368
+ } => {
369
+ let wgpu_state = app_handle.state::<Arc<WgpuState>>();
370
+ let mut config = wgpu_state.config.lock().unwrap();
371
+ config.width = size.width;
372
+ config.height = size.height;
373
+ wgpu_state.surface.configure(&wgpu_state.device, &config);
374
+ }
375
+ RunEvent::MainEventsCleared => {
376
+ let wgpu_state = app_handle.state::<Arc<WgpuState>>();
377
+ let _window = app_handle.get_window("main").unwrap();
378
+
379
+ let t = Instant::now();
380
+
381
+ let output = match wgpu_state.surface.get_current_texture() {
382
+ Ok(output) => output,
383
+ Err(wgpu::SurfaceError::Lost) => {
384
+ eprintln!("Surface lost, recreating surface...");
385
+ return ();
386
+ }
387
+ Err(wgpu::SurfaceError::OutOfMemory) => {
388
+ eprintln!("Out of memory error");
389
+ return ();
390
+ }
391
+ Err(e) => {
392
+ eprintln!("Failed to acquire next swap chain texture: {:?}", e);
393
+ return ();
394
+ }
395
+ };
396
+ let view = output
397
+ .texture
398
+ .create_view(&wgpu::TextureViewDescriptor::default());
399
+
400
+ let mut encoder = wgpu_state
401
+ .device
402
+ .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
403
+ {
404
+ let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
405
+ label: None,
406
+ color_attachments: &[Some(wgpu::RenderPassColorAttachment {
407
+ view: &view,
408
+ resolve_target: None,
409
+ ops: wgpu::Operations {
410
+ load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
411
+ store: wgpu::StoreOp::Store,
412
+ },
413
+ })],
414
+ depth_stencil_attachment: None,
415
+ timestamp_writes: None,
416
+ occlusion_query_set: None,
417
+ });
418
+ render_webview(&mut rpass, &_window, &wgpu_state.device, &wgpu_state.queue, wgpu_state);
419
+ rpass.set_pipeline(&wgpu_state.render_pipeline);
420
+ rpass.draw(0..3, 0..1);
421
+ }
422
+
423
+ wgpu_state.queue.submit(Some(encoder.finish()));
424
+ // output.present();
425
+
426
+ println!("Frame rendered in: {}ms", t.elapsed().as_millis());
427
+ }
428
+ _ => (),
429
+ });
430
+ }
@@ -0,0 +1,6 @@
1
+ // Prevents additional console window on Windows in release, DO NOT REMOVE!!
2
+ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
3
+
4
+ fn main() {
5
+ tauri_lib::run()
6
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "$schema": "https://schema.tauri.app/config/2",
3
+ "productName": "app",
4
+ "version": "0.1.0",
5
+ "identifier": "xyz.armaldio.app",
6
+ "build": {
7
+ "beforeDevCommand": "echo 1",
8
+ "devUrl": "http://localhost:1420",
9
+ "beforeBuildCommand": "echo 1",
10
+ "frontendDist": "../src/app"
11
+ },
12
+ "app": {
13
+ "withGlobalTauri": true,
14
+ "windows": [
15
+ {
16
+ "title": "App",
17
+ "width": 800,
18
+ "height": 600
19
+ }
20
+ ],
21
+ "security": {
22
+ "csp": null
23
+ }
24
+ },
25
+ "bundle": {
26
+ "active": true,
27
+ "targets": "all",
28
+ "icon": [
29
+ "icons/32x32.png",
30
+ "icons/128x128.png",
31
+ "icons/128x128@2x.png",
32
+ "icons/icon.icns",
33
+ "icons/icon.ico"
34
+ ]
35
+ }
36
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "module": "ESNext",
6
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true,
15
+
16
+ /* Linting */
17
+ "strict": true,
18
+ "noUnusedLocals": true,
19
+ "noUnusedParameters": true,
20
+ "noFallthroughCasesInSwitch": true
21
+ },
22
+ "include": ["src"]
23
+ }