2024-05-01 20:26:37 +03:00
|
|
|
use bitcode::{Decode, Encode};
|
2024-08-13 00:45:51 +03:00
|
|
|
use bookkeeping::{
|
|
|
|
noita_launcher::{LaunchTokenResult, NoitaLauncher},
|
|
|
|
save_state::SaveState,
|
|
|
|
};
|
2024-05-17 17:55:50 +03:00
|
|
|
use clipboard::{ClipboardContext, ClipboardProvider};
|
2024-08-13 00:45:51 +03:00
|
|
|
use eframe::egui::{
|
2024-08-22 12:46:28 +03:00
|
|
|
self, Align2, Button, Color32, Context, DragValue, FontDefinitions, FontFamily, ImageButton,
|
|
|
|
InnerResponse, Key, Margin, OpenUrl, Rect, RichText, ScrollArea, Slider, TextureOptions, Ui,
|
|
|
|
Vec2, Window,
|
2024-08-13 00:45:51 +03:00
|
|
|
};
|
2024-06-21 23:59:44 +03:00
|
|
|
use egui_plot::{Plot, PlotPoint, PlotUi, Text};
|
2024-08-15 23:58:13 +03:00
|
|
|
use image::DynamicImage::ImageRgba8;
|
2024-08-14 15:13:25 -04:00
|
|
|
use image::RgbaImage;
|
2024-06-08 14:25:57 +03:00
|
|
|
use lang::{set_current_locale, tr, LANGS};
|
2024-05-23 21:02:39 +03:00
|
|
|
use mod_manager::{Modmanager, ModmanagerSettings};
|
2024-08-16 18:25:02 +03:00
|
|
|
use net::{
|
|
|
|
omni::PeerVariant,
|
|
|
|
steam_networking::{ExtraPeerState, PerPeerStatusEntry},
|
|
|
|
NetManagerInit, RunInfo,
|
|
|
|
};
|
2024-05-24 00:41:55 +03:00
|
|
|
use self_update::SelfUpdateManager;
|
2024-05-23 21:02:39 +03:00
|
|
|
use serde::{Deserialize, Serialize};
|
2024-08-13 00:45:51 +03:00
|
|
|
use std::{
|
|
|
|
fmt::Display,
|
|
|
|
net::SocketAddr,
|
|
|
|
ops::Deref,
|
|
|
|
sync::{atomic::Ordering, Arc},
|
|
|
|
thread::JoinHandle,
|
|
|
|
time::Duration,
|
|
|
|
};
|
2024-09-28 10:44:05 +03:00
|
|
|
use std::{net::IpAddr, path::PathBuf};
|
2024-05-17 17:55:50 +03:00
|
|
|
use steamworks::{LobbyId, SteamAPIInitError};
|
2024-05-11 22:15:21 +03:00
|
|
|
use tangled::Peer;
|
2024-05-17 17:55:50 +03:00
|
|
|
use tracing::info;
|
2024-06-08 14:25:57 +03:00
|
|
|
use unic_langid::LanguageIdentifier;
|
2024-05-01 20:26:37 +03:00
|
|
|
|
2024-07-04 23:27:35 +03:00
|
|
|
mod util;
|
2024-07-06 13:44:31 +03:00
|
|
|
use util::args::Args;
|
2024-07-04 23:27:35 +03:00
|
|
|
pub use util::{args, lang, steam_helper};
|
|
|
|
|
|
|
|
mod bookkeeping;
|
2024-08-15 15:47:45 +03:00
|
|
|
use crate::player_cosmetics::{
|
|
|
|
display_player_skin, player_path, player_select_current_color_slot,
|
|
|
|
player_skin_display_color_picker, shift_hue,
|
|
|
|
};
|
2024-07-04 23:27:35 +03:00
|
|
|
pub use bookkeeping::{mod_manager, releases, self_update};
|
2024-07-29 18:44:59 +03:00
|
|
|
mod net;
|
2024-08-14 15:13:25 -04:00
|
|
|
mod player_cosmetics;
|
2024-08-15 15:47:45 +03:00
|
|
|
pub mod recorder;
|
2024-09-28 10:44:05 +03:00
|
|
|
|
|
|
|
const DEFAULT_PORT: u16 = 5123;
|
|
|
|
|
2024-08-07 13:00:41 +03:00
|
|
|
#[derive(Debug, Decode, Encode, Clone, Serialize, Deserialize, PartialEq, Eq, Copy)]
|
|
|
|
pub(crate) enum GameMode {
|
|
|
|
SharedHealth,
|
|
|
|
LocalHealth,
|
|
|
|
// MestariMina, // TODO later
|
|
|
|
}
|
|
|
|
|
2024-07-02 00:45:30 +03:00
|
|
|
#[derive(Debug, Decode, Encode, Clone, Serialize, Deserialize)]
|
2024-05-01 20:26:37 +03:00
|
|
|
pub struct GameSettings {
|
|
|
|
seed: u64,
|
2024-05-13 21:00:00 +03:00
|
|
|
debug_mode: bool,
|
2024-06-06 15:25:01 +03:00
|
|
|
world_sync_version: u32,
|
2024-07-02 00:45:30 +03:00
|
|
|
player_tether: bool,
|
2024-07-02 01:32:51 +03:00
|
|
|
tether_length: u32,
|
2024-07-10 15:33:29 +03:00
|
|
|
use_constant_seed: bool,
|
2024-07-18 13:15:21 +03:00
|
|
|
item_dedup: bool,
|
2024-07-18 16:27:28 +03:00
|
|
|
enemy_hp_mult: f32,
|
2024-08-01 12:50:13 +03:00
|
|
|
world_sync_interval: u32,
|
2024-08-07 13:00:41 +03:00
|
|
|
game_mode: GameMode,
|
2024-08-13 17:54:37 -04:00
|
|
|
friendly_fire: bool,
|
2024-08-25 08:55:49 -04:00
|
|
|
chunk_target: u32,
|
2024-08-17 18:27:58 +03:00
|
|
|
enemy_sync_interval: u32,
|
2024-09-17 06:20:38 -04:00
|
|
|
randomize_perks: bool,
|
2024-08-21 21:15:22 +03:00
|
|
|
progress: Vec<String>,
|
2024-07-02 00:45:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for GameSettings {
|
|
|
|
fn default() -> Self {
|
|
|
|
GameSettings {
|
|
|
|
seed: 0,
|
|
|
|
debug_mode: false,
|
|
|
|
world_sync_version: 2,
|
2024-08-29 18:01:52 -04:00
|
|
|
player_tether: true,
|
|
|
|
tether_length: 2048,
|
2024-07-10 15:33:29 +03:00
|
|
|
use_constant_seed: false,
|
2024-07-18 13:15:21 +03:00
|
|
|
item_dedup: true,
|
2024-09-17 06:20:38 -04:00
|
|
|
randomize_perks: true,
|
2024-07-18 16:27:28 +03:00
|
|
|
enemy_hp_mult: 1.0,
|
2024-08-30 17:12:17 -04:00
|
|
|
world_sync_interval: 3,
|
2024-08-29 18:01:52 -04:00
|
|
|
game_mode: GameMode::LocalHealth,
|
2024-08-15 15:47:45 +03:00
|
|
|
friendly_fire: false,
|
2024-08-25 08:55:49 -04:00
|
|
|
chunk_target: 32,
|
2024-08-30 17:12:17 -04:00
|
|
|
enemy_sync_interval: 3,
|
2024-08-21 21:15:22 +03:00
|
|
|
progress: Vec::new(),
|
2024-07-02 00:45:30 +03:00
|
|
|
}
|
|
|
|
}
|
2024-05-01 20:26:37 +03:00
|
|
|
}
|
|
|
|
|
2024-08-01 20:07:12 +03:00
|
|
|
pub struct NetManStopOnDrop(pub Arc<net::NetManager>, Option<JoinHandle<()>>);
|
|
|
|
|
|
|
|
impl Deref for NetManStopOnDrop {
|
|
|
|
type Target = Arc<net::NetManager>;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for NetManStopOnDrop {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.0.continue_running.store(false, Ordering::Relaxed);
|
|
|
|
self.1.take().unwrap().join().unwrap();
|
|
|
|
}
|
2024-08-12 16:49:12 -04:00
|
|
|
}
|
2024-08-01 20:07:12 +03:00
|
|
|
|
2024-05-01 20:26:37 +03:00
|
|
|
enum AppState {
|
2024-05-23 21:02:39 +03:00
|
|
|
Connect,
|
|
|
|
ModManager,
|
2024-07-06 13:44:31 +03:00
|
|
|
Netman {
|
2024-08-01 20:07:12 +03:00
|
|
|
netman: NetManStopOnDrop,
|
2024-07-06 13:44:31 +03:00
|
|
|
noita_launcher: NoitaLauncher,
|
|
|
|
},
|
|
|
|
Error {
|
|
|
|
message: String,
|
|
|
|
},
|
2024-05-24 00:41:55 +03:00
|
|
|
SelfUpdate,
|
2024-06-08 14:25:57 +03:00
|
|
|
LangPick,
|
2024-08-01 20:07:12 +03:00
|
|
|
AskSavestateReset,
|
2024-05-17 17:55:50 +03:00
|
|
|
}
|
|
|
|
|
2024-08-18 11:27:33 +03:00
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
struct PlayerAppearance {
|
|
|
|
player_color: PlayerColor,
|
|
|
|
player_picker: PlayerPicker,
|
|
|
|
hue: f32,
|
|
|
|
cosmetics: (bool, bool, bool),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for PlayerAppearance {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
player_color: PlayerColor::default(),
|
|
|
|
player_picker: PlayerPicker::None,
|
|
|
|
hue: 0.0,
|
|
|
|
cosmetics: (true, true, true),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-23 21:02:39 +03:00
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
struct AppSavedState {
|
2024-05-02 20:24:27 +03:00
|
|
|
addr: String,
|
2024-05-27 19:53:29 +03:00
|
|
|
nickname: Option<String>,
|
2024-05-31 16:40:18 +03:00
|
|
|
times_started: u32,
|
2024-06-08 14:25:57 +03:00
|
|
|
lang_id: Option<LanguageIdentifier>,
|
2024-08-01 12:50:13 +03:00
|
|
|
#[serde(default)]
|
2024-07-02 00:45:30 +03:00
|
|
|
game_settings: GameSettings,
|
2024-07-06 14:18:43 +03:00
|
|
|
start_game_automatically: bool,
|
2024-08-12 15:42:26 +03:00
|
|
|
#[serde(default)]
|
|
|
|
show_extra_debug_stuff: bool,
|
|
|
|
#[serde(default)]
|
|
|
|
record_all: bool,
|
2024-08-14 13:21:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for AppSavedState {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
addr: "127.0.0.1:5123".to_string(),
|
|
|
|
nickname: None,
|
|
|
|
times_started: 0,
|
|
|
|
lang_id: None,
|
|
|
|
game_settings: GameSettings::default(),
|
|
|
|
start_game_automatically: false,
|
|
|
|
show_extra_debug_stuff: false,
|
|
|
|
record_all: false,
|
|
|
|
}
|
|
|
|
}
|
2024-05-23 21:02:39 +03:00
|
|
|
}
|
|
|
|
|
2024-08-13 11:11:46 -04:00
|
|
|
#[derive(Debug, Serialize, Deserialize, Decode, Encode, Copy, Clone)]
|
|
|
|
pub struct PlayerColor {
|
|
|
|
player_main: [u8; 4],
|
|
|
|
player_alt: [u8; 4],
|
|
|
|
player_arm: [u8; 4],
|
|
|
|
player_cape: [u8; 4],
|
|
|
|
player_cape_edge: [u8; 4],
|
|
|
|
player_forearm: [u8; 4],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for PlayerColor {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
player_main: [155, 111, 154, 255],
|
|
|
|
player_alt: [127, 84, 118, 255],
|
|
|
|
player_arm: [89, 67, 84, 255],
|
|
|
|
player_cape: [118, 84, 127, 255],
|
|
|
|
player_cape_edge: [154, 111, 155, 255],
|
|
|
|
player_forearm: [158, 115, 154, 255],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
|
|
|
enum PlayerPicker {
|
|
|
|
None,
|
|
|
|
PlayerMain,
|
|
|
|
PlayerAlt,
|
|
|
|
PlayerArm,
|
|
|
|
PlayerCape,
|
|
|
|
PlayerCapeEdge,
|
|
|
|
PlayerForearm,
|
|
|
|
}
|
|
|
|
|
2024-05-23 21:02:39 +03:00
|
|
|
pub struct App {
|
|
|
|
state: AppState,
|
|
|
|
modmanager: Modmanager,
|
2024-05-27 16:08:21 +03:00
|
|
|
steam_state: Result<steam_helper::SteamState, SteamAPIInitError>,
|
2024-08-01 20:07:12 +03:00
|
|
|
app_saved_state: AppSavedState,
|
|
|
|
run_save_state: SaveState,
|
2024-05-24 00:41:55 +03:00
|
|
|
modmanager_settings: ModmanagerSettings,
|
|
|
|
self_update: SelfUpdateManager,
|
2024-06-21 20:18:01 +03:00
|
|
|
show_map_plot: bool,
|
2024-07-10 15:33:29 +03:00
|
|
|
/// Show settings in netman screen?
|
|
|
|
show_settings: bool,
|
2024-06-28 14:30:49 +03:00
|
|
|
lobby_id_field: String,
|
2024-07-06 13:44:31 +03:00
|
|
|
args: Args,
|
2024-07-10 15:33:29 +03:00
|
|
|
/// `true` if we haven't started noita automatically yet.
|
2024-07-06 14:18:43 +03:00
|
|
|
can_start_automatically: bool,
|
2024-08-15 15:47:45 +03:00
|
|
|
player_image: RgbaImage,
|
2024-08-16 16:51:45 -04:00
|
|
|
end_run_confirmation: bool,
|
2024-08-18 11:27:33 +03:00
|
|
|
appearance: PlayerAppearance,
|
2024-05-23 21:02:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const MODMANAGER: &str = "modman";
|
2024-08-18 11:27:33 +03:00
|
|
|
const APPEARANCE: &str = "appearance";
|
2024-05-23 21:02:39 +03:00
|
|
|
|
2024-05-31 16:40:18 +03:00
|
|
|
fn filled_group<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
|
|
|
|
let style = ui.style();
|
|
|
|
let frame = egui::Frame {
|
|
|
|
inner_margin: Margin::same(6.0), // same and symmetric looks best in corners when nesting groups
|
|
|
|
rounding: style.visuals.widgets.noninteractive.rounding,
|
|
|
|
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
|
|
|
fill: Color32::from_rgba_premultiplied(20, 20, 20, 180),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
frame.show(ui, add_contents)
|
|
|
|
}
|
|
|
|
|
2024-06-06 15:25:01 +03:00
|
|
|
fn heading_with_underline(ui: &mut Ui, text: impl Into<RichText>) {
|
|
|
|
ui.vertical_centered_justified(|ui| {
|
|
|
|
ui.heading(text);
|
|
|
|
});
|
|
|
|
ui.separator();
|
|
|
|
}
|
|
|
|
|
2024-06-12 19:07:03 +03:00
|
|
|
fn square_button_text(ui: &mut Ui, text: &str, size: f32) -> egui::Response {
|
2024-06-08 23:25:40 +03:00
|
|
|
let side = ui.available_width();
|
2024-06-12 19:07:03 +03:00
|
|
|
ui.add_sized([side, side], Button::new(RichText::new(text).size(size)))
|
2024-06-08 23:25:40 +03:00
|
|
|
}
|
|
|
|
|
2024-08-22 08:42:38 +07:00
|
|
|
fn square_button_icon(ui: &mut Ui, icon: egui::Image) -> egui::Response {
|
|
|
|
let side = ui.available_width();
|
2024-08-22 12:46:28 +03:00
|
|
|
ui.add_sized(
|
|
|
|
[side, side],
|
|
|
|
ImageButton::new(icon).rounding(ui.style().visuals.widgets.noninteractive.rounding), // Somewhy it doesnt inherit style correctly
|
|
|
|
)
|
2024-08-22 08:42:38 +07:00
|
|
|
}
|
|
|
|
|
2024-05-01 20:26:37 +03:00
|
|
|
impl App {
|
2024-07-06 13:44:31 +03:00
|
|
|
pub fn new(cc: &eframe::CreationContext<'_>, args: Args) -> Self {
|
2024-05-31 16:40:18 +03:00
|
|
|
let mut saved_state: AppSavedState = cc
|
2024-05-27 16:36:15 +03:00
|
|
|
.storage
|
|
|
|
.and_then(|storage| eframe::get_value(storage, eframe::APP_KEY))
|
|
|
|
.unwrap_or_default();
|
2024-08-13 20:14:06 -04:00
|
|
|
let modmanager_settings: ModmanagerSettings = cc
|
2024-05-27 16:36:15 +03:00
|
|
|
.storage
|
|
|
|
.and_then(|storage| eframe::get_value(storage, MODMANAGER))
|
2024-05-23 21:02:39 +03:00
|
|
|
.unwrap_or_default();
|
2024-08-18 11:27:33 +03:00
|
|
|
let appearance: PlayerAppearance = cc
|
|
|
|
.storage
|
|
|
|
.and_then(|storage| {
|
|
|
|
eframe::get_value(storage, APPEARANCE).inspect(|x| info!("Loaded appearance {x:?}"))
|
|
|
|
})
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
// Fallback to loading from the old location
|
|
|
|
cc.storage
|
|
|
|
.and_then(|storage| {
|
|
|
|
eframe::get_value(storage, eframe::APP_KEY)
|
|
|
|
.inspect(|x| info!("Loaded appearance from fallback: {x:?}"))
|
|
|
|
})
|
|
|
|
.unwrap_or_default()
|
|
|
|
});
|
2024-05-31 16:40:18 +03:00
|
|
|
saved_state.times_started += 1;
|
2024-06-08 14:25:57 +03:00
|
|
|
|
2024-07-23 05:29:41 +09:00
|
|
|
Self::set_fonts(&cc.egui_ctx);
|
2024-06-08 14:25:57 +03:00
|
|
|
let state = if let Some(lang_id) = &saved_state.lang_id {
|
|
|
|
set_current_locale(lang_id.clone());
|
|
|
|
AppState::ModManager
|
|
|
|
} else {
|
|
|
|
AppState::LangPick
|
|
|
|
};
|
|
|
|
|
2024-05-31 16:40:18 +03:00
|
|
|
egui_extras::install_image_loaders(&cc.egui_ctx);
|
2024-07-06 14:24:27 +03:00
|
|
|
|
2024-08-24 00:59:39 +03:00
|
|
|
let steam_state = steam_helper::SteamState::new();
|
|
|
|
|
|
|
|
let running_on_steamdeck = steam_state
|
|
|
|
.as_ref()
|
|
|
|
.map(|steam| steam.client.utils().is_steam_running_on_steam_deck())
|
|
|
|
.unwrap_or(false);
|
|
|
|
let default_zoom_factor = if running_on_steamdeck { 0.3 } else { 1.0 };
|
|
|
|
|
2024-07-07 11:18:41 +03:00
|
|
|
cc.egui_ctx
|
2024-08-24 00:59:39 +03:00
|
|
|
.set_zoom_factor(args.ui_zoom_factor.unwrap_or(default_zoom_factor));
|
2024-05-23 21:02:39 +03:00
|
|
|
info!("Creating the app...");
|
2024-08-13 00:45:51 +03:00
|
|
|
let run_save_state = if let Ok(path) = std::env::current_exe() {
|
2024-08-02 10:16:55 -04:00
|
|
|
SaveState::new(path.parent().unwrap().join("save_state"))
|
2024-08-13 00:45:51 +03:00
|
|
|
} else {
|
2024-08-02 10:16:55 -04:00
|
|
|
SaveState::new("./save_state/".into())
|
|
|
|
};
|
2024-08-15 16:46:35 -04:00
|
|
|
let path = player_path(modmanager_settings.mod_path());
|
|
|
|
let player_image = if path.exists() {
|
|
|
|
image::open(path)
|
|
|
|
.unwrap_or(ImageRgba8(RgbaImage::new(20, 20)))
|
|
|
|
.crop(1, 1, 8, 18)
|
|
|
|
.into_rgba8()
|
2024-08-15 23:58:13 +03:00
|
|
|
} else {
|
2024-08-15 16:46:35 -04:00
|
|
|
RgbaImage::new(1, 1)
|
|
|
|
};
|
2024-05-23 21:02:39 +03:00
|
|
|
Self {
|
2024-06-08 14:25:57 +03:00
|
|
|
state,
|
2024-05-23 21:02:39 +03:00
|
|
|
modmanager: Modmanager::default(),
|
2024-08-24 00:59:39 +03:00
|
|
|
steam_state,
|
2024-08-01 20:07:12 +03:00
|
|
|
app_saved_state: saved_state,
|
2024-05-23 21:02:39 +03:00
|
|
|
modmanager_settings,
|
2024-05-24 00:41:55 +03:00
|
|
|
self_update: SelfUpdateManager::new(),
|
2024-06-21 20:18:01 +03:00
|
|
|
show_map_plot: false,
|
2024-07-10 15:33:29 +03:00
|
|
|
show_settings: false,
|
2024-06-28 14:30:49 +03:00
|
|
|
lobby_id_field: "".to_string(),
|
2024-07-06 13:44:31 +03:00
|
|
|
args,
|
2024-07-06 14:18:43 +03:00
|
|
|
can_start_automatically: false,
|
2024-08-13 00:45:51 +03:00
|
|
|
run_save_state,
|
2024-08-15 15:47:45 +03:00
|
|
|
player_image,
|
2024-08-17 18:27:58 +03:00
|
|
|
end_run_confirmation: false,
|
2024-08-18 11:27:33 +03:00
|
|
|
appearance,
|
2024-05-23 21:02:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-27 19:53:29 +03:00
|
|
|
fn get_netman_init(&self) -> NetManagerInit {
|
|
|
|
let steam_nickname = if let Ok(steam) = &self.steam_state {
|
|
|
|
Some(steam.get_user_name(steam.get_my_id()))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2024-08-01 20:07:12 +03:00
|
|
|
let my_nickname = self.app_saved_state.nickname.clone().or(steam_nickname);
|
2024-08-15 15:47:45 +03:00
|
|
|
let mod_path = self.modmanager_settings.mod_path();
|
2024-08-18 11:27:33 +03:00
|
|
|
let mut cosmetics = self.appearance.cosmetics;
|
2024-08-15 10:39:21 -04:00
|
|
|
if let Some(path) = &self.modmanager_settings.game_save_path {
|
|
|
|
let flags = path.join("save00/persistent/flags");
|
|
|
|
let hat = flags.join("secret_hat").exists();
|
|
|
|
let amulet = flags.join("secret_amulet").exists();
|
|
|
|
let gem = flags.join("secret_amulet_gem").exists();
|
2024-08-15 23:58:13 +03:00
|
|
|
if !hat {
|
2024-08-15 10:39:21 -04:00
|
|
|
cosmetics.0 = false
|
|
|
|
}
|
2024-08-15 23:58:13 +03:00
|
|
|
if !amulet {
|
2024-08-15 10:39:21 -04:00
|
|
|
cosmetics.1 = false
|
|
|
|
}
|
2024-08-15 23:58:13 +03:00
|
|
|
if !gem {
|
2024-08-15 10:39:21 -04:00
|
|
|
cosmetics.2 = false
|
|
|
|
}
|
|
|
|
}
|
2024-08-12 16:49:12 -04:00
|
|
|
NetManagerInit {
|
|
|
|
my_nickname,
|
|
|
|
save_state: self.run_save_state.clone(),
|
2024-08-18 11:27:33 +03:00
|
|
|
player_color: self.appearance.player_color,
|
2024-08-15 10:39:21 -04:00
|
|
|
cosmetics,
|
2024-08-15 15:47:45 +03:00
|
|
|
mod_path,
|
|
|
|
player_path: player_path(self.modmanager_settings.mod_path()),
|
2024-08-12 16:49:12 -04:00
|
|
|
}
|
2024-05-27 19:53:29 +03:00
|
|
|
}
|
|
|
|
|
2024-08-12 16:49:12 -04:00
|
|
|
fn change_state_to_netman(&mut self, netman: Arc<net::NetManager>, player_path: PathBuf) {
|
|
|
|
let handle = netman.clone().start(player_path);
|
2024-07-06 13:44:31 +03:00
|
|
|
self.state = AppState::Netman {
|
2024-08-01 20:07:12 +03:00
|
|
|
netman: NetManStopOnDrop(netman, Some(handle)),
|
2024-07-06 13:44:31 +03:00
|
|
|
noita_launcher: NoitaLauncher::new(
|
|
|
|
&self.modmanager_settings.game_exe_path,
|
2024-07-20 12:29:20 +03:00
|
|
|
self.args.launch_cmd.as_deref(),
|
2024-08-13 00:45:51 +03:00
|
|
|
self.steam_state.as_mut().ok(),
|
2024-07-06 13:44:31 +03:00
|
|
|
),
|
|
|
|
};
|
2024-07-06 14:18:43 +03:00
|
|
|
self.can_start_automatically = true;
|
2024-07-06 13:44:31 +03:00
|
|
|
}
|
|
|
|
|
2024-05-01 20:26:37 +03:00
|
|
|
fn start_server(&mut self) {
|
2024-09-28 10:44:05 +03:00
|
|
|
let bind_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), DEFAULT_PORT);
|
2024-05-02 20:24:27 +03:00
|
|
|
let peer = Peer::host(bind_addr, None).unwrap();
|
2024-05-27 19:53:29 +03:00
|
|
|
let netman = net::NetManager::new(PeerVariant::Tangled(peer), self.get_netman_init());
|
2024-05-17 17:55:50 +03:00
|
|
|
self.set_netman_settings(&netman);
|
2024-08-13 20:14:06 -04:00
|
|
|
self.change_state_to_netman(netman, player_path(self.modmanager_settings.mod_path()));
|
2024-05-17 17:55:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_netman_settings(&mut self, netman: &Arc<net::NetManager>) {
|
2024-08-01 20:07:12 +03:00
|
|
|
let run_info: Option<RunInfo> = self.run_save_state.load();
|
2024-05-17 17:55:50 +03:00
|
|
|
let mut settings = netman.settings.lock().unwrap();
|
2024-08-01 20:07:12 +03:00
|
|
|
*settings = self.app_saved_state.game_settings.clone();
|
|
|
|
if !self.app_saved_state.game_settings.use_constant_seed {
|
|
|
|
if let Some(info) = run_info {
|
|
|
|
settings.seed = info.seed;
|
|
|
|
info!("Using saved seed: {}", settings.seed);
|
|
|
|
} else {
|
|
|
|
settings.seed = rand::random();
|
|
|
|
info!("Using random seed: {}", settings.seed);
|
|
|
|
}
|
2024-06-27 12:26:59 +03:00
|
|
|
} else {
|
|
|
|
info!("Using constant seed: {}", settings.seed);
|
2024-06-24 16:34:21 -04:00
|
|
|
}
|
2024-08-21 21:15:22 +03:00
|
|
|
settings.progress = self.modmanager_settings.get_progress().unwrap_or_default();
|
2024-07-12 23:31:54 +03:00
|
|
|
*netman.pending_settings.lock().unwrap() = settings.clone();
|
2024-05-18 12:55:31 +03:00
|
|
|
netman.accept_local.store(true, Ordering::SeqCst);
|
2024-05-01 20:26:37 +03:00
|
|
|
}
|
2024-09-28 10:44:05 +03:00
|
|
|
|
2024-05-02 20:24:27 +03:00
|
|
|
fn start_connect(&mut self, addr: SocketAddr) {
|
|
|
|
let peer = Peer::connect(addr, None).unwrap();
|
2024-05-27 19:53:29 +03:00
|
|
|
let netman = net::NetManager::new(PeerVariant::Tangled(peer), self.get_netman_init());
|
2024-08-13 20:14:06 -04:00
|
|
|
self.change_state_to_netman(netman, player_path(self.modmanager_settings.mod_path()));
|
2024-05-17 17:55:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn start_steam_host(&mut self) {
|
|
|
|
let peer = net::steam_networking::SteamPeer::new_host(
|
|
|
|
steamworks::LobbyType::Private,
|
|
|
|
self.steam_state.as_ref().unwrap().client.clone(),
|
|
|
|
);
|
2024-05-27 19:53:29 +03:00
|
|
|
let netman = net::NetManager::new(PeerVariant::Steam(peer), self.get_netman_init());
|
2024-05-17 17:55:50 +03:00
|
|
|
self.set_netman_settings(&netman);
|
2024-08-13 20:14:06 -04:00
|
|
|
self.change_state_to_netman(netman, player_path(self.modmanager_settings.mod_path()));
|
2024-05-17 17:55:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn notify_error(&mut self, error: impl Display) {
|
|
|
|
self.state = AppState::Error {
|
|
|
|
message: error.to_string(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn start_steam_connect(&mut self, id: LobbyId) {
|
|
|
|
let peer = net::steam_networking::SteamPeer::new_connect(
|
|
|
|
id,
|
|
|
|
self.steam_state.as_ref().unwrap().client.clone(),
|
|
|
|
);
|
2024-07-03 21:34:08 +03:00
|
|
|
|
|
|
|
let netman = net::NetManager::new(PeerVariant::Steam(peer), self.get_netman_init());
|
2024-08-13 20:14:06 -04:00
|
|
|
self.change_state_to_netman(netman, player_path(self.modmanager_settings.mod_path()));
|
2024-05-01 20:26:37 +03:00
|
|
|
}
|
2024-05-27 16:36:15 +03:00
|
|
|
|
2024-08-15 09:16:29 -04:00
|
|
|
fn connect_screen(&mut self, ctx: &Context) {
|
2024-05-31 15:27:55 +03:00
|
|
|
egui::CentralPanel::default().show(ctx, |ui| {
|
2024-08-01 20:07:12 +03:00
|
|
|
if self.app_saved_state.times_started % 20 == 0 {
|
2024-05-31 16:40:18 +03:00
|
|
|
let image = egui::Image::new(egui::include_image!("../assets/longleg.png"))
|
2024-06-11 00:42:43 +03:00
|
|
|
.texture_options(TextureOptions::NEAREST);
|
2024-05-31 16:40:18 +03:00
|
|
|
image.paint_at(ui, ui.ctx().screen_rect());
|
2024-06-11 00:42:43 +03:00
|
|
|
} else {
|
|
|
|
draw_bg(ui);
|
2024-05-31 16:40:18 +03:00
|
|
|
}
|
|
|
|
|
2024-06-08 23:25:40 +03:00
|
|
|
let group_shrink = ui.spacing().item_spacing.x * 0.5;
|
2024-05-31 15:27:55 +03:00
|
|
|
let rect = ui.max_rect();
|
2024-06-11 00:42:43 +03:00
|
|
|
let (rect, bottom_panel) =
|
|
|
|
rect.split_top_bottom_at_y(rect.height() - (25.0 + group_shrink * 2.0));
|
|
|
|
|
2024-06-08 14:25:57 +03:00
|
|
|
let (rect, right_b_panel) =
|
2024-06-11 00:42:43 +03:00
|
|
|
rect.split_left_right_at_x(rect.width() - (50.0 + group_shrink * 2.0));
|
2024-05-31 15:27:55 +03:00
|
|
|
let (settings_rect, right) = rect.split_left_right_at_fraction(0.5);
|
|
|
|
let (steam_connect_rect, ip_connect_rect) = right.split_top_bottom_at_fraction(0.5);
|
2024-06-08 14:25:57 +03:00
|
|
|
|
2024-06-11 00:42:43 +03:00
|
|
|
ui.allocate_ui_at_rect(bottom_panel.shrink(group_shrink), |ui| {
|
|
|
|
filled_group(ui, |ui| {
|
|
|
|
ui.set_min_size(ui.available_size());
|
|
|
|
self.self_update.display_version(ui);
|
|
|
|
|
|
|
|
if self.self_update.request_update {
|
|
|
|
self.state = AppState::SelfUpdate;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2024-06-08 23:25:40 +03:00
|
|
|
ui.allocate_ui_at_rect(right_b_panel.shrink(group_shrink), |ui| {
|
2024-05-31 16:40:18 +03:00
|
|
|
filled_group(ui, |ui| {
|
2024-05-31 15:27:55 +03:00
|
|
|
ui.set_min_size(ui.available_size());
|
2024-06-06 15:25:01 +03:00
|
|
|
|
2024-09-28 10:44:05 +03:00
|
|
|
self.panel_right_bar(ui, ctx);
|
2024-06-08 14:25:57 +03:00
|
|
|
})
|
|
|
|
});
|
|
|
|
|
2024-06-08 23:25:40 +03:00
|
|
|
ui.allocate_ui_at_rect(settings_rect.shrink(group_shrink), |ui| {
|
2024-06-08 14:25:57 +03:00
|
|
|
filled_group(ui, |ui| {
|
|
|
|
ui.set_min_size(ui.available_size());
|
2024-08-16 00:01:05 +03:00
|
|
|
ScrollArea::both().auto_shrink(false).show(ui, |ui| {
|
2024-08-16 16:51:45 -04:00
|
|
|
self.show_game_settings(ui, true);
|
2024-08-15 23:58:13 +03:00
|
|
|
});
|
2024-05-31 15:27:55 +03:00
|
|
|
});
|
|
|
|
});
|
2024-06-08 23:25:40 +03:00
|
|
|
ui.allocate_ui_at_rect(steam_connect_rect.shrink(group_shrink), |ui| {
|
2024-05-31 16:40:18 +03:00
|
|
|
filled_group(ui, |ui| {
|
2024-05-31 15:27:55 +03:00
|
|
|
ui.set_min_size(ui.available_size());
|
2024-06-06 15:25:01 +03:00
|
|
|
|
2024-09-28 10:44:05 +03:00
|
|
|
self.panel_connect_by_steam(ui);
|
2024-05-31 15:27:55 +03:00
|
|
|
});
|
|
|
|
});
|
2024-06-08 23:25:40 +03:00
|
|
|
ui.allocate_ui_at_rect(ip_connect_rect.shrink(group_shrink), |ui| {
|
2024-05-31 16:40:18 +03:00
|
|
|
filled_group(ui, |ui| {
|
2024-05-31 15:27:55 +03:00
|
|
|
ui.set_min_size(ui.available_size());
|
2024-06-06 15:25:01 +03:00
|
|
|
|
2024-09-28 10:44:05 +03:00
|
|
|
self.panel_connect_by_ip(ui);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2024-06-06 15:25:01 +03:00
|
|
|
|
2024-09-28 10:44:05 +03:00
|
|
|
fn panel_right_bar(&mut self, ui: &mut Ui, ctx: &Context) {
|
|
|
|
let lang_label = self
|
|
|
|
.app_saved_state
|
|
|
|
.lang_id
|
|
|
|
.clone()
|
|
|
|
.unwrap_or_default()
|
|
|
|
.language;
|
|
|
|
if square_button_text(ui, &lang_label.to_string().to_uppercase(), 21.0)
|
|
|
|
.on_hover_text(tr("button_set_lang"))
|
|
|
|
.clicked()
|
|
|
|
{
|
|
|
|
self.state = AppState::LangPick;
|
|
|
|
}
|
|
|
|
if square_button_icon(
|
|
|
|
ui,
|
|
|
|
egui::Image::new(egui::include_image!("../assets/discord-mark-white.png")),
|
|
|
|
)
|
|
|
|
.on_hover_text(tr("button_open_discord"))
|
|
|
|
.clicked()
|
|
|
|
{
|
|
|
|
ctx.open_url(OpenUrl::new_tab("https://discord.gg/uAK7utvVWN"));
|
|
|
|
}
|
|
|
|
let secret_active = ui.input(|i| i.modifiers.ctrl && i.key_down(Key::D));
|
|
|
|
if secret_active && ui.button("reset all data").clicked() {
|
|
|
|
self.app_saved_state = Default::default();
|
|
|
|
self.modmanager_settings = Default::default();
|
|
|
|
self.state = AppState::LangPick;
|
|
|
|
}
|
|
|
|
}
|
2024-05-31 15:27:55 +03:00
|
|
|
|
2024-09-28 10:44:05 +03:00
|
|
|
fn panel_connect_by_steam(&mut self, ui: &mut Ui) {
|
|
|
|
heading_with_underline(ui, tr("connect_steam"));
|
|
|
|
|
|
|
|
match &self.steam_state {
|
|
|
|
Ok(_) => {
|
|
|
|
if ui.button(tr("connect_steam_create")).clicked() {
|
|
|
|
self.start_steam_host();
|
|
|
|
}
|
|
|
|
if ui.button(tr("connect_steam_connect")).clicked() {
|
|
|
|
let id = ClipboardProvider::new()
|
|
|
|
.and_then(|mut ctx: ClipboardContext| ctx.get_contents());
|
|
|
|
match id {
|
|
|
|
Ok(id) => {
|
|
|
|
self.connect_to_steam_lobby(id);
|
2024-05-31 15:27:55 +03:00
|
|
|
}
|
2024-09-28 10:44:05 +03:00
|
|
|
Err(error) => self.notify_error(error),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if cfg!(target_os = "linux") {
|
|
|
|
ui.add_space(30.0);
|
|
|
|
ui.label(tr("connect_steam_workaround_label"));
|
|
|
|
ui.text_edit_singleline(&mut self.lobby_id_field);
|
|
|
|
if ui.button(tr("connect_steam_connect_2")).clicked() {
|
|
|
|
self.connect_to_steam_lobby(self.lobby_id_field.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
ui.label(format!("Could not init steam networking: {}", err));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn panel_connect_by_ip(&mut self, ui: &mut Ui) {
|
|
|
|
heading_with_underline(ui, tr("connect_ip"));
|
|
|
|
|
|
|
|
ui.label(tr("ip_note"));
|
|
|
|
if ui.button(tr("ip_host")).clicked() {
|
|
|
|
self.start_server();
|
|
|
|
}
|
|
|
|
|
|
|
|
ui.text_edit_singleline(&mut self.app_saved_state.addr);
|
|
|
|
let addr = self.app_saved_state.addr.parse();
|
|
|
|
|
|
|
|
let ip: Result<IpAddr, _> = self.app_saved_state.addr.parse();
|
|
|
|
let addr2 = ip.map(|ip| SocketAddr::new(ip, DEFAULT_PORT));
|
|
|
|
|
|
|
|
let addr = addr.or(addr2);
|
|
|
|
|
|
|
|
ui.add_enabled_ui(addr.is_ok(), |ui| {
|
|
|
|
if ui.button(tr("ip_connect")).clicked() {
|
|
|
|
if let Ok(addr) = addr {
|
|
|
|
self.start_connect(addr);
|
|
|
|
}
|
|
|
|
}
|
2024-05-27 16:08:21 +03:00
|
|
|
});
|
|
|
|
}
|
2024-06-28 14:30:49 +03:00
|
|
|
|
2024-08-16 16:51:45 -04:00
|
|
|
fn show_game_settings(&mut self, ui: &mut Ui, show_local: bool) {
|
2024-07-10 15:33:29 +03:00
|
|
|
heading_with_underline(ui, tr("connect_settings"));
|
2024-08-01 20:07:12 +03:00
|
|
|
let game_settings = &mut self.app_saved_state.game_settings;
|
2024-09-28 10:26:59 +03:00
|
|
|
ui.label(tr("Game-mode"));
|
2024-08-13 00:45:51 +03:00
|
|
|
ui.radio_value(
|
|
|
|
&mut game_settings.game_mode,
|
|
|
|
GameMode::SharedHealth,
|
2024-09-28 10:26:59 +03:00
|
|
|
tr("Shared-health"),
|
2024-08-13 00:45:51 +03:00
|
|
|
);
|
|
|
|
ui.radio_value(
|
|
|
|
&mut game_settings.game_mode,
|
|
|
|
GameMode::LocalHealth,
|
2024-09-28 10:26:59 +03:00
|
|
|
tr("Local-health"),
|
2024-08-13 00:45:51 +03:00
|
|
|
);
|
2024-09-06 22:09:24 +07:00
|
|
|
|
|
|
|
ui.scope(|ui| {
|
|
|
|
ui.set_height(60.0);
|
|
|
|
|
|
|
|
match game_settings.game_mode {
|
|
|
|
GameMode::SharedHealth => {
|
2024-09-28 10:26:59 +03:00
|
|
|
ui.label(tr("shared_health_desc_1"));
|
|
|
|
ui.label(tr("shared_health_desc_2"));
|
|
|
|
ui.label(tr("shared_health_desc_3"));
|
2024-09-06 22:09:24 +07:00
|
|
|
}
|
|
|
|
GameMode::LocalHealth => {
|
2024-09-28 10:26:59 +03:00
|
|
|
ui.label(tr("local_health_desc_1"));
|
|
|
|
ui.label(tr("local_health_desc_2"));
|
2024-09-06 22:09:24 +07:00
|
|
|
}
|
2024-09-21 13:48:25 +03:00
|
|
|
}
|
2024-09-06 22:09:24 +07:00
|
|
|
});
|
|
|
|
|
2024-08-07 13:00:41 +03:00
|
|
|
ui.add_space(20.0);
|
2024-07-10 15:33:29 +03:00
|
|
|
ui.label(tr("connect_settings_debug"));
|
|
|
|
ui.checkbox(
|
2024-08-01 12:50:13 +03:00
|
|
|
&mut game_settings.debug_mode,
|
2024-07-10 15:33:29 +03:00
|
|
|
tr("connect_settings_debug_en"),
|
|
|
|
);
|
|
|
|
ui.checkbox(
|
2024-08-01 12:50:13 +03:00
|
|
|
&mut game_settings.use_constant_seed,
|
2024-07-10 15:33:29 +03:00
|
|
|
tr("connect_settings_debug_fixed_seed"),
|
|
|
|
);
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.label(tr("connect_settings_seed"));
|
2024-08-01 12:50:13 +03:00
|
|
|
ui.add(DragValue::new(&mut game_settings.seed));
|
2024-07-10 15:33:29 +03:00
|
|
|
});
|
2024-08-25 08:55:49 -04:00
|
|
|
ui.add_space(10.0);
|
2024-09-28 10:26:59 +03:00
|
|
|
ui.label(tr("Amount-of-chunks-host-has-loaded-at-once-synced-enemies-and-physics-objects-need-to-be-loaded-in-by-host-to-be-rendered-by-clients"));
|
2024-08-25 08:55:49 -04:00
|
|
|
ui.add(Slider::new(&mut game_settings.chunk_target, 1..=64));
|
2024-08-17 18:27:58 +03:00
|
|
|
|
2024-07-10 15:33:29 +03:00
|
|
|
ui.add_space(20.0);
|
|
|
|
ui.label(tr("connect_settings_player_tether_desc"));
|
|
|
|
ui.checkbox(
|
2024-08-01 12:50:13 +03:00
|
|
|
&mut game_settings.player_tether,
|
2024-07-10 15:33:29 +03:00
|
|
|
tr("connect_settings_player_tether"),
|
|
|
|
);
|
|
|
|
ui.add(
|
2024-08-01 12:50:13 +03:00
|
|
|
Slider::new(&mut game_settings.tether_length, 10..=5000)
|
2024-07-10 15:33:29 +03:00
|
|
|
.text(tr("connect_settings_player_tether_length")),
|
|
|
|
);
|
2024-07-18 16:27:28 +03:00
|
|
|
ui.add_space(20.0);
|
2024-08-13 00:45:51 +03:00
|
|
|
ui.checkbox(
|
|
|
|
&mut game_settings.item_dedup,
|
|
|
|
tr("connect_settings_item_dedup"),
|
|
|
|
);
|
2024-07-18 16:27:28 +03:00
|
|
|
ui.add_space(20.0);
|
2024-09-17 06:20:38 -04:00
|
|
|
ui.checkbox(
|
|
|
|
&mut game_settings.randomize_perks,
|
2024-09-28 10:26:59 +03:00
|
|
|
tr("Have-perk-pools-be-independent-of-each-other"),
|
2024-09-17 06:20:38 -04:00
|
|
|
);
|
|
|
|
ui.add_space(20.0);
|
2024-08-13 00:45:51 +03:00
|
|
|
ui.add(
|
|
|
|
Slider::new(&mut game_settings.enemy_hp_mult, 1.0..=1000.0)
|
|
|
|
.logarithmic(true)
|
|
|
|
.text(tr("connect_settings_enemy_hp_scale")),
|
|
|
|
);
|
2024-08-13 17:54:37 -04:00
|
|
|
ui.add_space(20.0);
|
2024-09-28 10:26:59 +03:00
|
|
|
ui.checkbox(&mut game_settings.friendly_fire, tr("Enable-friendly-fire"));
|
2024-08-16 16:51:45 -04:00
|
|
|
if show_local {
|
2024-08-13 18:48:46 -04:00
|
|
|
heading_with_underline(ui, tr("connect_settings_local"));
|
|
|
|
ui.checkbox(
|
|
|
|
&mut self.app_saved_state.start_game_automatically,
|
|
|
|
tr("connect_settings_autostart"),
|
2024-08-13 20:01:40 +03:00
|
|
|
);
|
2024-08-13 18:48:46 -04:00
|
|
|
ui.add_space(20.0);
|
2024-08-15 23:58:13 +03:00
|
|
|
if self.player_image.width() == 1 {
|
2024-08-15 16:46:35 -04:00
|
|
|
self.player_image = image::open(player_path(self.modmanager_settings.mod_path()))
|
|
|
|
.unwrap_or(ImageRgba8(RgbaImage::new(20, 20)))
|
|
|
|
.crop(1, 1, 8, 18)
|
|
|
|
.into_rgba8();
|
|
|
|
}
|
2024-08-18 11:27:33 +03:00
|
|
|
let old_hue = self.appearance.hue;
|
2024-09-28 10:26:59 +03:00
|
|
|
ui.add(Slider::new(&mut self.appearance.hue, 0.0..=360.0).text(tr("Shift-hue")));
|
2024-08-18 11:27:33 +03:00
|
|
|
if old_hue != self.appearance.hue {
|
|
|
|
let diff = self.appearance.hue - old_hue;
|
|
|
|
shift_hue(diff, &mut self.appearance.player_color.player_main);
|
|
|
|
shift_hue(diff, &mut self.appearance.player_color.player_alt);
|
|
|
|
shift_hue(diff, &mut self.appearance.player_color.player_arm);
|
|
|
|
shift_hue(diff, &mut self.appearance.player_color.player_forearm);
|
|
|
|
shift_hue(diff, &mut self.appearance.player_color.player_cape);
|
|
|
|
shift_hue(diff, &mut self.appearance.player_color.player_cape_edge);
|
2024-08-13 18:48:46 -04:00
|
|
|
}
|
|
|
|
ui.horizontal(|ui| {
|
2024-08-14 15:13:25 -04:00
|
|
|
display_player_skin(ui, self);
|
|
|
|
player_select_current_color_slot(ui, self);
|
2024-08-15 15:47:45 +03:00
|
|
|
player_skin_display_color_picker(
|
|
|
|
ui,
|
2024-08-18 11:27:33 +03:00
|
|
|
&mut self.appearance.player_color,
|
|
|
|
&self.appearance.player_picker,
|
2024-08-15 15:47:45 +03:00
|
|
|
);
|
2024-08-13 18:48:46 -04:00
|
|
|
});
|
2024-09-28 10:26:59 +03:00
|
|
|
if ui.button(tr("Reset-colors-to-default")).clicked() {
|
2024-08-18 11:27:33 +03:00
|
|
|
self.appearance.player_color = PlayerColor::default();
|
|
|
|
self.appearance.hue = 0.0
|
2024-08-13 18:48:46 -04:00
|
|
|
}
|
2024-08-13 11:11:46 -04:00
|
|
|
}
|
2024-08-13 20:01:40 +03:00
|
|
|
}
|
|
|
|
|
2024-06-28 14:30:49 +03:00
|
|
|
fn connect_to_steam_lobby(&mut self, lobby_id: String) {
|
|
|
|
let id = lobby_id.trim().parse().map(LobbyId::from_raw);
|
|
|
|
match id {
|
|
|
|
Ok(id) => self.start_steam_connect(id),
|
|
|
|
Err(_error) => self.notify_error(tr("connect_steam_connect_invalid_lobby_id")),
|
|
|
|
}
|
|
|
|
}
|
2024-07-23 05:29:41 +09:00
|
|
|
|
|
|
|
fn set_fonts(ctx: &Context) {
|
|
|
|
let mut font_definitions = FontDefinitions::default();
|
|
|
|
|
|
|
|
font_definitions.font_data.insert(
|
|
|
|
"noto_sans".to_owned(),
|
|
|
|
egui::FontData::from_static(include_bytes!("../assets/font/NotoSans-Regular.ttf")),
|
|
|
|
);
|
|
|
|
font_definitions.font_data.insert(
|
|
|
|
"noto_sans_jp".to_owned(),
|
|
|
|
egui::FontData::from_static(include_bytes!("../assets/font/NotoSansJP-Light.ttf")),
|
|
|
|
);
|
2024-09-17 17:30:42 +08:00
|
|
|
font_definitions.font_data.insert(
|
|
|
|
"noto_sans_sc".to_owned(),
|
2024-09-21 13:48:25 +03:00
|
|
|
egui::FontData::from_static(include_bytes!(
|
|
|
|
"../assets/font/NotoSansSChinese-Light.ttf"
|
|
|
|
)),
|
2024-09-17 17:30:42 +08:00
|
|
|
);
|
2024-07-23 05:29:41 +09:00
|
|
|
|
|
|
|
font_definitions
|
|
|
|
.families
|
|
|
|
.entry(FontFamily::Proportional)
|
|
|
|
.or_default()
|
|
|
|
.push("noto_sans".to_owned());
|
|
|
|
font_definitions
|
|
|
|
.families
|
|
|
|
.entry(FontFamily::Proportional)
|
|
|
|
.or_default()
|
|
|
|
.push("noto_sans_jp".to_owned());
|
|
|
|
|
|
|
|
font_definitions
|
|
|
|
.families
|
|
|
|
.entry(FontFamily::Monospace)
|
|
|
|
.or_default()
|
|
|
|
.push("noto_sans".to_owned());
|
|
|
|
font_definitions
|
|
|
|
.families
|
|
|
|
.entry(FontFamily::Monospace)
|
|
|
|
.or_default()
|
|
|
|
.push("noto_sans_jp".to_owned());
|
|
|
|
|
2024-09-17 17:30:42 +08:00
|
|
|
font_definitions
|
|
|
|
.families
|
|
|
|
.entry(FontFamily::Proportional)
|
|
|
|
.or_default()
|
|
|
|
.push("noto_sans_sc".to_owned());
|
|
|
|
font_definitions
|
|
|
|
.families
|
|
|
|
.entry(FontFamily::Monospace)
|
|
|
|
.or_default()
|
|
|
|
.push("noto_sans_sc".to_owned());
|
2024-09-21 13:48:25 +03:00
|
|
|
|
2024-07-23 05:29:41 +09:00
|
|
|
ctx.set_fonts(font_definitions);
|
|
|
|
}
|
2024-08-12 16:49:12 -04:00
|
|
|
|
2024-08-01 20:07:12 +03:00
|
|
|
fn switch_to_connect(&mut self) {
|
|
|
|
self.state = if self.run_save_state.has_savestate() {
|
|
|
|
AppState::AskSavestateReset
|
|
|
|
} else {
|
|
|
|
AppState::Connect
|
|
|
|
};
|
|
|
|
}
|
2024-05-27 16:08:21 +03:00
|
|
|
}
|
|
|
|
|
2024-06-11 00:42:43 +03:00
|
|
|
fn draw_bg(ui: &mut Ui) {
|
|
|
|
let image = egui::Image::new(egui::include_image!("../assets/noita_ew_logo_sq.webp"))
|
|
|
|
.texture_options(TextureOptions::NEAREST);
|
|
|
|
|
|
|
|
let rect = ui.ctx().screen_rect();
|
|
|
|
let aspect_ratio = 1.0;
|
|
|
|
let new_height = f32::max(rect.width() * aspect_ratio, rect.height());
|
|
|
|
let new_width = new_height / aspect_ratio;
|
|
|
|
let rect = Rect::from_center_size(rect.center(), Vec2::new(new_width, new_height));
|
|
|
|
|
|
|
|
image.paint_at(ui, rect);
|
|
|
|
}
|
|
|
|
|
2024-05-27 16:08:21 +03:00
|
|
|
impl eframe::App for App {
|
2024-08-15 09:16:29 -04:00
|
|
|
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
|
2024-06-21 20:18:01 +03:00
|
|
|
ctx.request_repaint_after(Duration::from_millis(500));
|
2024-07-06 13:44:31 +03:00
|
|
|
match &mut self.state {
|
2024-05-27 16:08:21 +03:00
|
|
|
AppState::Connect => {
|
|
|
|
self.connect_screen(ctx);
|
2024-05-01 20:26:37 +03:00
|
|
|
}
|
2024-07-06 13:44:31 +03:00
|
|
|
AppState::Netman {
|
|
|
|
netman,
|
|
|
|
noita_launcher,
|
|
|
|
} => {
|
2024-07-03 21:34:08 +03:00
|
|
|
if let ExtraPeerState::CouldNotConnect(err) = netman.peer.state() {
|
|
|
|
self.notify_error(err);
|
|
|
|
return;
|
|
|
|
}
|
2024-05-18 12:55:31 +03:00
|
|
|
let stopped = netman.stopped.load(Ordering::Relaxed);
|
|
|
|
let accept_local = netman.accept_local.load(Ordering::Relaxed);
|
|
|
|
let local_connected = netman.local_connected.load(Ordering::Relaxed);
|
2024-05-27 16:36:15 +03:00
|
|
|
egui::TopBottomPanel::top("noita_status").show(ctx, |ui| {
|
|
|
|
ui.add_space(3.0);
|
|
|
|
if accept_local {
|
|
|
|
if local_connected {
|
2024-06-09 19:55:07 +03:00
|
|
|
ui.colored_label(Color32::GREEN, tr("noita_connected"));
|
2024-05-27 16:36:15 +03:00
|
|
|
} else {
|
2024-06-09 17:58:24 +03:00
|
|
|
ui.colored_label(Color32::YELLOW, tr("noita_can_connect"));
|
2024-05-27 16:08:21 +03:00
|
|
|
}
|
|
|
|
} else {
|
2024-06-09 17:58:24 +03:00
|
|
|
ui.label(tr("noita_not_yet"));
|
2024-05-27 16:08:21 +03:00
|
|
|
}
|
|
|
|
});
|
2024-05-27 16:36:15 +03:00
|
|
|
egui::SidePanel::left("players")
|
|
|
|
.resizable(false)
|
|
|
|
.exact_width(200.0)
|
|
|
|
.show(ctx, |ui| {
|
|
|
|
ui.add_space(3.0);
|
|
|
|
if netman.peer.is_steam() {
|
|
|
|
let steam = self.steam_state.as_mut().expect(
|
|
|
|
"steam should be available, as we are using steam networking",
|
|
|
|
);
|
2024-06-29 11:20:53 +03:00
|
|
|
ScrollArea::vertical().auto_shrink(false).show(ui, |ui| {
|
|
|
|
for peer in netman.peer.iter_peer_ids() {
|
|
|
|
let role = peer_role(peer, netman);
|
|
|
|
|
|
|
|
let username = steam.get_user_name(peer.into());
|
|
|
|
let avatar = steam.get_avatar(ctx, peer.into());
|
|
|
|
if let Some(avatar) = avatar {
|
|
|
|
avatar.display_with_labels(ui, &username, &role);
|
|
|
|
ui.add_space(5.0);
|
|
|
|
} else {
|
|
|
|
ui.label(&username);
|
|
|
|
}
|
2024-05-27 16:36:15 +03:00
|
|
|
}
|
2024-06-29 11:20:53 +03:00
|
|
|
});
|
2024-05-27 16:36:15 +03:00
|
|
|
} else {
|
|
|
|
for peer in netman.peer.iter_peer_ids() {
|
|
|
|
ui.label(peer.to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2024-05-01 20:26:37 +03:00
|
|
|
egui::CentralPanel::default().show(ctx, |ui| {
|
2024-05-18 12:55:31 +03:00
|
|
|
if stopped {
|
|
|
|
ui.colored_label(Color32::LIGHT_RED, "Netmanager thread has stopped");
|
|
|
|
if let Some(err) = netman.error.lock().unwrap().as_ref() {
|
|
|
|
ui.label("With the following error:");
|
|
|
|
ui.label(err.to_string());
|
|
|
|
}
|
|
|
|
ui.separator();
|
|
|
|
}
|
2024-05-27 16:36:15 +03:00
|
|
|
|
2024-05-27 16:08:21 +03:00
|
|
|
if netman.peer.is_steam() {
|
|
|
|
if let Some(id) = netman.peer.lobby_id() {
|
2024-07-08 12:22:13 +03:00
|
|
|
if cfg!(target_os = "linux") {
|
|
|
|
ui.label(id.raw().to_string());
|
|
|
|
}
|
|
|
|
|
2024-06-09 17:58:24 +03:00
|
|
|
if ui.button(tr("netman_save_lobby")).clicked() {
|
2024-05-27 16:08:21 +03:00
|
|
|
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
|
|
|
|
let _ = ctx.set_contents(id.raw().to_string());
|
|
|
|
}
|
2024-05-17 17:55:50 +03:00
|
|
|
}
|
2024-06-21 19:06:40 +03:00
|
|
|
} else {
|
2024-07-03 21:34:08 +03:00
|
|
|
ui.label(format!("Peer state: {:?}", netman.peer.state()));
|
2024-05-01 20:26:37 +03:00
|
|
|
}
|
2024-07-06 13:55:43 +03:00
|
|
|
ui.add_space(15.0);
|
2024-07-06 14:18:43 +03:00
|
|
|
if accept_local && !local_connected {
|
|
|
|
match noita_launcher.launch_token() {
|
|
|
|
LaunchTokenResult::Ok(mut token) => {
|
2024-08-01 20:07:12 +03:00
|
|
|
let start_auto = self.can_start_automatically && self.app_saved_state.start_game_automatically;
|
2024-07-06 14:18:43 +03:00
|
|
|
if start_auto || ui.button(tr("launcher_start_game")).clicked() {
|
|
|
|
info!("Starting the game now");
|
|
|
|
token.start_game();
|
|
|
|
self.can_start_automatically = false;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
LaunchTokenResult::AlreadyStarted => {
|
|
|
|
ui.label(tr("launcher_already_started"));
|
|
|
|
},
|
|
|
|
LaunchTokenResult::CantStart => {
|
|
|
|
ui.label(tr("launcher_no_command"));
|
|
|
|
ui.label(tr("launcher_no_command_2"));
|
|
|
|
ui.label(tr("launcher_no_command_3"));
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ui.label(tr("launcher_only_when_awaiting"));
|
2024-07-06 13:44:31 +03:00
|
|
|
}
|
|
|
|
|
2024-08-15 13:41:17 -04:00
|
|
|
if netman.peer.is_host() {
|
2024-08-16 16:51:45 -04:00
|
|
|
ui.add_space(15.0);
|
|
|
|
if !self.end_run_confirmation && ui.button("End run").clicked()
|
|
|
|
{
|
|
|
|
self.end_run_confirmation = true
|
|
|
|
}
|
|
|
|
else if self.end_run_confirmation && ui.button("Confirm").clicked()
|
|
|
|
{
|
|
|
|
self.end_run_confirmation = false;
|
|
|
|
netman.end_run.store(true, Ordering::Relaxed)
|
|
|
|
}
|
2024-08-15 13:41:17 -04:00
|
|
|
ui.add_space(15.0);
|
|
|
|
if ui.button(tr("netman_show_settings")).clicked() {
|
|
|
|
self.show_settings = true;
|
|
|
|
}
|
2024-07-10 15:33:29 +03:00
|
|
|
}
|
2024-08-12 15:42:26 +03:00
|
|
|
ui.add_space(15.0);
|
|
|
|
|
2024-09-28 10:26:59 +03:00
|
|
|
ui.checkbox(&mut self.app_saved_state.show_extra_debug_stuff, tr("Show-debug-info"));
|
2024-09-02 12:16:52 -04:00
|
|
|
ui.add_space(15.0);
|
2024-09-28 10:26:59 +03:00
|
|
|
ui.label(tr("hint_ping"));
|
|
|
|
ui.label(tr("hint_spectate"));
|
2024-09-02 12:16:52 -04:00
|
|
|
|
2024-08-12 15:42:26 +03:00
|
|
|
|
|
|
|
if self.app_saved_state.show_extra_debug_stuff {
|
2024-08-16 18:25:02 +03:00
|
|
|
Window::new("Connection status").show(ctx, |ui| {
|
|
|
|
match &netman.peer {
|
|
|
|
PeerVariant::Tangled(_) => {ui.label("No connection info available in tangled mode");}
|
|
|
|
PeerVariant::Steam(peer) => {
|
|
|
|
let steam = self.steam_state.as_ref().unwrap();
|
|
|
|
let report = peer.generate_report();
|
|
|
|
egui::Grid::new("Conn status grid").striped(true).show(ui, |ui| {
|
|
|
|
add_per_status_ui(&report, steam, ui);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2024-08-12 15:42:26 +03:00
|
|
|
if self.show_map_plot {
|
2024-08-30 21:33:44 +03:00
|
|
|
if ui.button("Close plot").clicked() {
|
|
|
|
self.show_map_plot = false;
|
|
|
|
}
|
|
|
|
ctx.request_repaint_after(Duration::from_millis(16));
|
2024-08-12 15:42:26 +03:00
|
|
|
let build_fn = |plot: &mut PlotUi| {
|
2024-08-30 21:33:44 +03:00
|
|
|
let markers = netman.debug_markers.lock().unwrap();
|
|
|
|
for marker in markers.iter() {
|
2024-08-30 15:36:00 -04:00
|
|
|
plot.text(Text::new(PlotPoint::new(marker.x, -marker.y), marker.message.clone()));
|
2024-08-30 21:33:44 +03:00
|
|
|
}
|
2024-08-12 15:42:26 +03:00
|
|
|
netman.world_info.with_player_infos(|peer, info| {
|
|
|
|
let username = if netman.peer.is_steam() {
|
|
|
|
let steam = self.steam_state.as_mut().expect(
|
|
|
|
"steam should be available, as we are using steam networking",
|
|
|
|
);
|
|
|
|
steam.get_user_name(peer.into())
|
|
|
|
} else {
|
|
|
|
peer.as_hex()
|
|
|
|
};
|
|
|
|
plot.text(Text::new(PlotPoint::new(info.x, -info.y), username).highlight(true))
|
|
|
|
});
|
|
|
|
};
|
|
|
|
Plot::new("map").data_aspect(1.0).show(ui, build_fn);
|
|
|
|
} else if ui.button("Show debug plot").clicked() {
|
|
|
|
self.show_map_plot = true;
|
|
|
|
}
|
|
|
|
ui.checkbox(&mut self.app_saved_state.record_all, "Record EVERYTHING sent to noita.");
|
2024-06-21 20:18:01 +03:00
|
|
|
}
|
2024-05-11 18:06:48 +03:00
|
|
|
});
|
2024-08-13 00:45:51 +03:00
|
|
|
netman
|
|
|
|
.enable_recorder
|
|
|
|
.store(self.app_saved_state.record_all, Ordering::Relaxed);
|
2024-07-10 15:37:58 +03:00
|
|
|
if netman.peer.is_host() {
|
|
|
|
let mut show = self.show_settings;
|
|
|
|
let netman = netman.clone();
|
2024-08-16 16:51:45 -04:00
|
|
|
Window::new(tr("connect_settings"))
|
2024-08-13 00:45:51 +03:00
|
|
|
.open(&mut show)
|
|
|
|
.show(ctx, |ui| {
|
2024-08-16 16:51:45 -04:00
|
|
|
self.show_game_settings(ui, false);
|
2024-08-13 00:45:51 +03:00
|
|
|
if ui.button(tr("netman_apply_settings")).clicked() {
|
|
|
|
*netman.pending_settings.lock().unwrap() =
|
|
|
|
self.app_saved_state.game_settings.clone();
|
|
|
|
}
|
|
|
|
});
|
2024-07-10 15:37:58 +03:00
|
|
|
self.show_settings = show;
|
|
|
|
}
|
2024-05-01 20:26:37 +03:00
|
|
|
}
|
2024-05-17 17:55:50 +03:00
|
|
|
AppState::Error { message } => {
|
2024-06-17 20:57:49 +03:00
|
|
|
let add_contents = |ui: &mut Ui| {
|
|
|
|
ui.heading(tr("error_occured"));
|
2024-07-06 13:44:31 +03:00
|
|
|
ui.label(&*message);
|
2024-06-17 20:57:49 +03:00
|
|
|
ui.button(tr("button_back")).clicked()
|
|
|
|
};
|
|
|
|
if egui::CentralPanel::default().show(ctx, add_contents).inner {
|
2024-05-23 21:02:39 +03:00
|
|
|
self.state = AppState::Connect;
|
2024-05-17 17:55:50 +03:00
|
|
|
}
|
|
|
|
}
|
2024-05-23 21:02:39 +03:00
|
|
|
AppState::ModManager => {
|
2024-06-11 00:42:43 +03:00
|
|
|
egui::CentralPanel::default().show(ctx, draw_bg);
|
2024-08-16 16:51:45 -04:00
|
|
|
Window::new(tr("modman"))
|
2024-05-27 16:36:15 +03:00
|
|
|
.auto_sized()
|
|
|
|
.anchor(Align2::CENTER_CENTER, [0.0, 0.0])
|
2024-05-23 21:02:39 +03:00
|
|
|
.show(ctx, |ui| {
|
2024-07-09 18:05:16 +03:00
|
|
|
ui.set_max_width(600.0);
|
2024-05-27 16:36:15 +03:00
|
|
|
self.modmanager.update(
|
|
|
|
ctx,
|
|
|
|
ui,
|
|
|
|
&mut self.modmanager_settings,
|
|
|
|
self.steam_state.as_mut().ok(),
|
|
|
|
)
|
2024-05-23 21:02:39 +03:00
|
|
|
});
|
2024-05-27 16:36:15 +03:00
|
|
|
if self.modmanager.is_done() {
|
2024-08-01 20:07:12 +03:00
|
|
|
self.switch_to_connect();
|
2024-05-27 16:36:15 +03:00
|
|
|
}
|
|
|
|
}
|
2024-05-24 00:41:55 +03:00
|
|
|
AppState::SelfUpdate => {
|
2024-06-11 00:42:43 +03:00
|
|
|
egui::CentralPanel::default().show(ctx, draw_bg);
|
2024-08-16 16:51:45 -04:00
|
|
|
Window::new(tr("selfupdate"))
|
2024-05-27 16:36:15 +03:00
|
|
|
.auto_sized()
|
|
|
|
.anchor(Align2::CENTER_CENTER, [0.0, 0.0])
|
2024-05-24 00:41:55 +03:00
|
|
|
.show(ctx, |ui| {
|
2024-07-09 18:05:16 +03:00
|
|
|
ui.set_max_width(600.0);
|
2024-05-24 00:41:55 +03:00
|
|
|
self.self_update.self_update(ui);
|
|
|
|
});
|
2024-05-27 16:36:15 +03:00
|
|
|
}
|
2024-06-08 14:25:57 +03:00
|
|
|
AppState::LangPick => {
|
2024-06-11 00:42:43 +03:00
|
|
|
egui::CentralPanel::default().show(ctx, draw_bg);
|
2024-08-16 16:51:45 -04:00
|
|
|
Window::new(tr("lang_picker"))
|
2024-06-08 14:25:57 +03:00
|
|
|
.auto_sized()
|
|
|
|
.anchor(Align2::CENTER_CENTER, [0.0, 0.0])
|
|
|
|
.show(ctx, |ui| {
|
|
|
|
for lang in &LANGS {
|
|
|
|
ui.set_max_width(200.0);
|
|
|
|
ui.vertical_centered_justified(|ui| {
|
|
|
|
if ui.button(lang.name()).clicked() {
|
2024-08-01 20:07:12 +03:00
|
|
|
self.app_saved_state.lang_id = Some(lang.id());
|
2024-06-08 14:25:57 +03:00
|
|
|
set_current_locale(lang.id())
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if ui.button(tr("button_confirm")).clicked() {
|
|
|
|
self.state = AppState::ModManager;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2024-08-01 20:07:12 +03:00
|
|
|
AppState::AskSavestateReset => {
|
2024-08-16 16:51:45 -04:00
|
|
|
Window::new(tr("An-in-progress-run-has-been-detected"))
|
2024-08-01 20:07:12 +03:00
|
|
|
.auto_sized()
|
|
|
|
.anchor(Align2::CENTER_CENTER, [0.0, 0.0])
|
|
|
|
.show(ctx, |ui| {
|
|
|
|
ui.label(tr("savestate_desc"));
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
if ui.button(tr("Continue")).clicked() {
|
|
|
|
self.state = AppState::Connect;
|
|
|
|
}
|
|
|
|
if ui.button(tr("New-game")).clicked() {
|
|
|
|
self.state = AppState::Connect;
|
|
|
|
self.run_save_state.reset();
|
|
|
|
}
|
|
|
|
});
|
2024-08-13 00:45:51 +03:00
|
|
|
});
|
|
|
|
}
|
2024-05-01 20:26:37 +03:00
|
|
|
};
|
2024-04-30 23:49:51 +03:00
|
|
|
}
|
2024-05-23 21:02:39 +03:00
|
|
|
|
|
|
|
fn save(&mut self, storage: &mut dyn eframe::Storage) {
|
2024-08-01 20:07:12 +03:00
|
|
|
eframe::set_value(storage, eframe::APP_KEY, &self.app_saved_state);
|
2024-05-23 21:02:39 +03:00
|
|
|
eframe::set_value(storage, MODMANAGER, &self.modmanager_settings);
|
2024-08-18 11:27:33 +03:00
|
|
|
eframe::set_value(storage, APPEARANCE, &self.appearance);
|
2024-05-23 21:02:39 +03:00
|
|
|
}
|
2024-04-30 23:49:51 +03:00
|
|
|
}
|
2024-05-27 16:08:21 +03:00
|
|
|
|
2024-08-16 18:25:02 +03:00
|
|
|
fn add_per_status_ui(
|
|
|
|
report: &net::steam_networking::ConnectionStatusReport,
|
|
|
|
steam: &steam_helper::SteamState,
|
|
|
|
ui: &mut Ui,
|
|
|
|
) {
|
|
|
|
ui.label("Name");
|
|
|
|
ui.label("Status");
|
|
|
|
ui.label("Ping");
|
|
|
|
ui.label("LocQ❓")
|
|
|
|
.on_hover_text("Local Connection Quality (percentage of packets we delivered).");
|
|
|
|
ui.label("RemQ❓")
|
|
|
|
.on_hover_text("Remote Connection Quality (percentage of packets delivered to us).");
|
|
|
|
ui.label("In");
|
|
|
|
ui.label("Out");
|
|
|
|
ui.label("MaxSendRate");
|
|
|
|
ui.label("PenUnr❓")
|
|
|
|
.on_hover_text("Pending unreliable messages");
|
|
|
|
ui.label("PenRel❓")
|
|
|
|
.on_hover_text("Pending reliable messages");
|
|
|
|
ui.label("UnAck❓").on_hover_text(
|
|
|
|
"Amount of reliable packages that were sent but weren't confirmed as received yet.",
|
|
|
|
);
|
|
|
|
ui.end_row();
|
|
|
|
|
|
|
|
for PerPeerStatusEntry { peer, status } in &report.per_peer_statuses {
|
|
|
|
let name = steam.get_user_name((*peer).into());
|
|
|
|
ui.label(&name);
|
|
|
|
match status {
|
|
|
|
net::steam_networking::PerPeerStatus::Connected { realtimeinfo } => {
|
|
|
|
ui.label("Ok❓").on_hover_text("Connected");
|
|
|
|
ui.label(format!("{}ms", realtimeinfo.ping()));
|
|
|
|
ui.label(format!(
|
|
|
|
"{:.2}%",
|
|
|
|
realtimeinfo.connection_quality_local() * 100.0
|
|
|
|
));
|
|
|
|
ui.label(format!(
|
|
|
|
"{:.2}%",
|
|
|
|
realtimeinfo.connection_quality_remote() * 100.0
|
|
|
|
));
|
|
|
|
ui.label(format!("{}by/s", realtimeinfo.in_bytes_per_sec()));
|
|
|
|
ui.label(format!("{}by/s", realtimeinfo.out_bytes_per_sec()));
|
|
|
|
ui.label(format!("{}by/s", realtimeinfo.send_rate_bytes_per_sec()));
|
|
|
|
ui.label(format!("{}", realtimeinfo.pending_unreliable()));
|
|
|
|
ui.label(format!("{}", realtimeinfo.pending_reliable()));
|
|
|
|
ui.label(format!("{}", realtimeinfo.sent_unacked_reliable()));
|
|
|
|
}
|
|
|
|
net::steam_networking::PerPeerStatus::AwaitingIncoming => {
|
|
|
|
ui.label("Awa❓")
|
|
|
|
.on_hover_text("Awaiting incoming connection from this peer.");
|
|
|
|
}
|
|
|
|
net::steam_networking::PerPeerStatus::ConnectionPending => {
|
|
|
|
ui.label("Pen❓").on_hover_text("Connection pending.");
|
|
|
|
}
|
|
|
|
net::steam_networking::PerPeerStatus::NoFurtherInfo => {
|
|
|
|
ui.label("NoI❓")
|
|
|
|
.on_hover_text("Connected, but no further info available.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ui.end_row();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-09 17:16:33 +03:00
|
|
|
fn peer_role(peer: net::omni::OmniPeerId, netman: &Arc<net::NetManager>) -> String {
|
2024-05-27 16:08:21 +03:00
|
|
|
if peer == netman.peer.host_id() {
|
2024-06-09 17:16:33 +03:00
|
|
|
tr("player_host")
|
2024-06-17 20:57:49 +03:00
|
|
|
} else if Some(peer) == netman.peer.my_id() {
|
|
|
|
tr("player_me")
|
2024-05-27 16:08:21 +03:00
|
|
|
} else {
|
2024-06-17 20:57:49 +03:00
|
|
|
tr("player_player")
|
2024-05-27 16:08:21 +03:00
|
|
|
}
|
2024-09-21 13:48:25 +03:00
|
|
|
}
|