feat: add global & server leveling, quests, achievements, guilds land-claiming, social & toggleable configs
This commit is contained in:
1 parent
4b79f69c20
commit
b4cef85b1f
40 files changed
+10261
-27
No files matched your search
@@ -6,7 +6,11 @@ use crate::settings::Settings;
|
||||
use crate::state::{build, AppState};
|
||||
use crate::updater;
|
||||
use scopenet_core::ping::ServerStatus;
|
||||
use scopenet_shared::{LauncherManifest, PlayerProfile, SkinProfile};
|
||||
use scopenet_shared::{
|
||||
Achievement, DirectMessage, FriendInfo, GameInvite, Guild, GuildClaim, GuildMember, GuildPost,
|
||||
LauncherManifest, PlayerProfile, SkinProfile, UserLevelInfo, UserPost, UserProfileView,
|
||||
UserQuest,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use tauri::{AppHandle, Manager, State};
|
||||
use tauri_plugin_opener::OpenerExt;
|
||||
@@ -520,3 +524,382 @@ pub async fn get_public_servers(state: State<'_, AppState>) -> Res<serde_json::V
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Leveling & Quests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_my_level(state: State<'_, AppState>) -> Res<UserLevelInfo> {
|
||||
let req = account_api(&state, reqwest::Method::GET, "/levels/me").await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load user level".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_my_quests(state: State<'_, AppState>) -> Res<Vec<UserQuest>> {
|
||||
let req = account_api(&state, reqwest::Method::GET, "/quests/my").await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load quests".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn claim_quest(state: State<'_, AppState>, quest_id: String) -> Res<UserQuest> {
|
||||
let req = account_api(&state, reqwest::Method::POST, &format!("/quests/{quest_id}/claim")).await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to claim quest").to_string());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Achievements
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_my_achievements(state: State<'_, AppState>) -> Res<Vec<Achievement>> {
|
||||
let req = account_api(&state, reqwest::Method::GET, "/achievements/my").await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load achievements".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Guilds & Land Claims
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_guilds(state: State<'_, AppState>, instance_id: Option<String>) -> Res<Vec<Guild>> {
|
||||
let panel = state.panel_url().ok_or("no panel configured")?;
|
||||
let q = instance_id.map(|i| format!("?instance_id={i}")).unwrap_or_default();
|
||||
let resp = state.http.get(format!("{panel}/api/v1/guilds{q}")).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load guilds".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_my_guild(state: State<'_, AppState>, instance_id: Option<String>) -> Res<Option<Guild>> {
|
||||
let q = instance_id.map(|i| format!("?instance_id={i}")).unwrap_or_default();
|
||||
let req = account_api(&state, reqwest::Method::GET, &format!("/guilds/my{q}")).await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Ok(None);
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn create_guild(
|
||||
state: State<'_, AppState>,
|
||||
instance_id: String,
|
||||
name: String,
|
||||
tag: String,
|
||||
description: String,
|
||||
) -> Res<Guild> {
|
||||
let req = account_api(&state, reqwest::Method::POST, "/guilds").await?;
|
||||
let resp = req.json(&serde_json::json!({
|
||||
"instance_id": instance_id,
|
||||
"name": name,
|
||||
"tag": tag,
|
||||
"description": description,
|
||||
})).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to create guild").to_string());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_guild_claims(
|
||||
state: State<'_, AppState>,
|
||||
instance_id: String,
|
||||
dimension: Option<String>,
|
||||
) -> Res<Vec<GuildClaim>> {
|
||||
let panel = state.panel_url().ok_or("no panel configured")?;
|
||||
let dim = dimension.unwrap_or_else(|| "minecraft:overworld".into());
|
||||
let resp = state.http.get(format!("{panel}/api/v1/guilds/claims/grid?instance_id={instance_id}&dimension={dim}"))
|
||||
.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load claims".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn claim_guild_chunk(
|
||||
state: State<'_, AppState>,
|
||||
guild_id: String,
|
||||
instance_id: String,
|
||||
dimension: String,
|
||||
chunk_x: i32,
|
||||
chunk_z: i32,
|
||||
) -> Res<GuildClaim> {
|
||||
let req = account_api(&state, reqwest::Method::POST, &format!("/guilds/{guild_id}/claim")).await?;
|
||||
let resp = req.json(&serde_json::json!({
|
||||
"instance_id": instance_id,
|
||||
"dimension": dimension,
|
||||
"chunk_x": chunk_x,
|
||||
"chunk_z": chunk_z,
|
||||
})).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to claim chunk").to_string());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn unclaim_guild_chunk(
|
||||
state: State<'_, AppState>,
|
||||
guild_id: String,
|
||||
instance_id: String,
|
||||
dimension: String,
|
||||
chunk_x: i32,
|
||||
chunk_z: i32,
|
||||
) -> Res<()> {
|
||||
let req = account_api(&state, reqwest::Method::POST, &format!("/guilds/{guild_id}/unclaim")).await?;
|
||||
let resp = req.json(&serde_json::json!({
|
||||
"instance_id": instance_id,
|
||||
"dimension": dimension,
|
||||
"chunk_x": chunk_x,
|
||||
"chunk_z": chunk_z,
|
||||
})).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to unclaim chunk").to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_guild_posts(state: State<'_, AppState>, guild_id: String) -> Res<Vec<GuildPost>> {
|
||||
let req = account_api(&state, reqwest::Method::GET, &format!("/guilds/{guild_id}/posts")).await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load guild posts".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn create_guild_post(
|
||||
state: State<'_, AppState>,
|
||||
guild_id: String,
|
||||
title: String,
|
||||
content: String,
|
||||
) -> Res<GuildPost> {
|
||||
let req = account_api(&state, reqwest::Method::POST, &format!("/guilds/{guild_id}/posts")).await?;
|
||||
let resp = req.json(&serde_json::json!({
|
||||
"title": title,
|
||||
"content": content,
|
||||
})).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to post announcement").to_string());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_guild_members(state: State<'_, AppState>, guild_id: String) -> Res<Vec<GuildMember>> {
|
||||
let req = account_api(&state, reqwest::Method::GET, &format!("/guilds/{guild_id}/members")).await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load members".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Social: Friends, DMs, Invites, Profiles & Feed
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_friends(state: State<'_, AppState>) -> Res<Vec<FriendInfo>> {
|
||||
let req = account_api(&state, reqwest::Method::GET, "/friends").await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load friends".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn send_friend_request(state: State<'_, AppState>, username: String) -> Res<()> {
|
||||
let req = account_api(&state, reqwest::Method::POST, "/friends/request").await?;
|
||||
let resp = req.json(&serde_json::json!({ "username": username })).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to send friend request").to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn respond_friend_request(state: State<'_, AppState>, target_uuid: String, accept: bool) -> Res<()> {
|
||||
let req = account_api(&state, reqwest::Method::POST, "/friends/respond").await?;
|
||||
let resp = req.json(&serde_json::json!({ "target_uuid": target_uuid, "accept": accept })).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to respond to friend request").to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn remove_friend(state: State<'_, AppState>, target_uuid: String) -> Res<()> {
|
||||
let req = account_api(&state, reqwest::Method::DELETE, &format!("/friends/{target_uuid}")).await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to remove friend").to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_direct_messages(state: State<'_, AppState>, friend_uuid: String) -> Res<Vec<DirectMessage>> {
|
||||
let req = account_api(&state, reqwest::Method::GET, &format!("/messages/{friend_uuid}")).await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load messages".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn send_direct_message(state: State<'_, AppState>, friend_uuid: String, content: String) -> Res<DirectMessage> {
|
||||
let req = account_api(&state, reqwest::Method::POST, &format!("/messages/{friend_uuid}")).await?;
|
||||
let resp = req.json(&serde_json::json!({ "content": content })).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to send message").to_string());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_game_invites(state: State<'_, AppState>) -> Res<Vec<GameInvite>> {
|
||||
let req = account_api(&state, reqwest::Method::GET, "/invites").await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load invites".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn send_game_invite(
|
||||
state: State<'_, AppState>,
|
||||
recipient_uuid: String,
|
||||
instance_id: String,
|
||||
server_id: Option<i64>,
|
||||
) -> Res<GameInvite> {
|
||||
let req = account_api(&state, reqwest::Method::POST, "/invites").await?;
|
||||
let resp = req.json(&serde_json::json!({
|
||||
"recipient_uuid": recipient_uuid,
|
||||
"instance_id": instance_id,
|
||||
"server_id": server_id,
|
||||
})).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to send invite").to_string());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn respond_game_invite(state: State<'_, AppState>, invite_id: String, accept: bool) -> Res<()> {
|
||||
let req = account_api(&state, reqwest::Method::POST, &format!("/invites/{invite_id}/respond")).await?;
|
||||
let resp = req.json(&serde_json::json!({ "accept": accept })).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to respond to invite").to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_user_profile(state: State<'_, AppState>, uuid: String) -> Res<UserProfileView> {
|
||||
let req = account_api(&state, reqwest::Method::GET, &format!("/profiles/{uuid}")).await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load user profile".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn update_my_profile(
|
||||
state: State<'_, AppState>,
|
||||
bio: String,
|
||||
banner_url: Option<String>,
|
||||
custom_badge: Option<String>,
|
||||
featured_achievement_id: Option<String>,
|
||||
) -> Res<UserProfileView> {
|
||||
let req = account_api(&state, reqwest::Method::PUT, "/profiles/me").await?;
|
||||
let resp = req.json(&serde_json::json!({
|
||||
"bio": bio,
|
||||
"banner_url": banner_url,
|
||||
"custom_badge": custom_badge,
|
||||
"featured_achievement_id": featured_achievement_id,
|
||||
})).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to update profile").to_string());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_user_posts(state: State<'_, AppState>, user_uuid: Option<String>) -> Res<Vec<UserPost>> {
|
||||
let path = user_uuid.map(|u| format!("/posts?uuid={u}")).unwrap_or_else(|| "/posts".into());
|
||||
let req = account_api(&state, reqwest::Method::GET, &path).await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to load posts".into());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn create_user_post(
|
||||
state: State<'_, AppState>,
|
||||
content: String,
|
||||
image_url: Option<String>,
|
||||
) -> Res<UserPost> {
|
||||
let req = account_api(&state, reqwest::Method::POST, "/posts").await?;
|
||||
let resp = req.json(&serde_json::json!({
|
||||
"content": content,
|
||||
"image_url": image_url,
|
||||
})).send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
let body: serde_json::Value = resp.json().await.unwrap_or_default();
|
||||
return Err(body["error"].as_str().unwrap_or("unable to publish post").to_string());
|
||||
}
|
||||
resp.json().await.map_err(err)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn like_user_post(state: State<'_, AppState>, post_id: i64) -> Res<()> {
|
||||
let req = account_api(&state, reqwest::Method::POST, &format!("/posts/{post_id}/like")).await?;
|
||||
let resp = req.send().await.map_err(err)?;
|
||||
if !resp.status().is_success() {
|
||||
return Err("unable to like post".into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -84,6 +84,33 @@ pub fn run() {
|
||||
commands::get_player_stats,
|
||||
commands::get_leaderboard,
|
||||
commands::get_public_servers,
|
||||
commands::get_my_level,
|
||||
commands::get_my_quests,
|
||||
commands::claim_quest,
|
||||
commands::get_my_achievements,
|
||||
commands::get_guilds,
|
||||
commands::get_my_guild,
|
||||
commands::create_guild,
|
||||
commands::get_guild_claims,
|
||||
commands::claim_guild_chunk,
|
||||
commands::unclaim_guild_chunk,
|
||||
commands::get_guild_posts,
|
||||
commands::create_guild_post,
|
||||
commands::get_guild_members,
|
||||
commands::get_friends,
|
||||
commands::send_friend_request,
|
||||
commands::respond_friend_request,
|
||||
commands::remove_friend,
|
||||
commands::get_direct_messages,
|
||||
commands::send_direct_message,
|
||||
commands::get_game_invites,
|
||||
commands::send_game_invite,
|
||||
commands::respond_game_invite,
|
||||
commands::get_user_profile,
|
||||
commands::update_my_profile,
|
||||
commands::get_user_posts,
|
||||
commands::create_user_post,
|
||||
commands::like_user_post,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running the launcher");
|
||||
|
||||
Reference in new issue
Block a user