mirror of
https://git.ethanthesleepy.one/ethanaobrien/ew
synced 2026-08-26 23:12:20 +08:00
Better support for custom card account flagging
This commit is contained in:
@@ -13,17 +13,23 @@ pub fn routes(cfg: &mut web::ServiceConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Custom cards live at id prefix 10000+ (imported 10000-14999, new 15000+).
|
// Custom cards live at id prefix 10000+ (imported 10000-14999, new 15000+).
|
||||||
// Like custom songs they need a protocol version (2, global::PROTOCOL_HEADER):
|
// Like custom songs they need a protocol version (global::PROTOCOL_HEADER):
|
||||||
// clients below it can't resolve the ids
|
// clients below it can't resolve the ids
|
||||||
|
pub const PROTOCOL_VERSION: u32 = 2;
|
||||||
|
|
||||||
pub fn is_custom(master_card_id: i64) -> bool {
|
pub fn is_custom(master_card_id: i64) -> bool {
|
||||||
master_card_id >= 100_000_000
|
master_card_id >= 100_000_000
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn client_supports_custom_cards(req: &HttpRequest) -> bool {
|
pub fn client_supports_custom_cards(req: &HttpRequest) -> bool {
|
||||||
global::client_protocol_version(req) >= 2
|
global::client_protocol_version(req) >= PROTOCOL_VERSION
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn owns_custom(user: &JsonValue) -> bool {
|
pub fn account_supports_custom_cards(auth_key: &str) -> bool {
|
||||||
|
userdata::get_protocol_version(auth_key) >= PROTOCOL_VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn account_has_custom_cards(user: &JsonValue) -> bool {
|
||||||
user["card_list"].members().any(|card| is_custom(card["master_card_id"].as_i64().unwrap_or(0)))
|
user["card_list"].members().any(|card| is_custom(card["master_card_id"].as_i64().unwrap_or(0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -268,7 +268,14 @@ pub async fn ranking(req: HttpRequest, Session { key, body }: Session) -> impl R
|
|||||||
let uid = data["user"].as_i64().unwrap();
|
let uid = data["user"].as_i64().unwrap();
|
||||||
let user = guest::get_user(uid, &object![], guest::UserView::Ranking, custom_cards);
|
let user = guest::get_user(uid, &object![], guest::UserView::Ranking, custom_cards);
|
||||||
let user_obj = if uid == self_id {
|
let user_obj = if uid == self_id {
|
||||||
userdata::get_acc_from_uid(uid)["user"].clone()
|
// The client wants the fields get_user hides from other players
|
||||||
|
let mut self_user = object!{
|
||||||
|
user: userdata::get_acc_from_uid(uid)["user"].clone()
|
||||||
|
};
|
||||||
|
if !custom_cards {
|
||||||
|
guest::proxy_user_cards(&mut self_user);
|
||||||
|
}
|
||||||
|
self_user["user"].clone()
|
||||||
} else {
|
} else {
|
||||||
user["user"].clone()
|
user["user"].clone()
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,6 @@ fn get_asset_hash(req: &HttpRequest, body: &JsonValue) -> Option<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn asset_hash(req: HttpRequest, Body(body): Body) -> impl Responder {
|
async fn asset_hash(req: HttpRequest, Body(body): Body) -> impl Responder {
|
||||||
|
|
||||||
match get_asset_hash(&req, &body) {
|
match get_asset_hash(&req, &body) {
|
||||||
Some(hash) => global::api(&req, Some(object!{
|
Some(hash) => global::api(&req, Some(object!{
|
||||||
"asset_hash": hash
|
"asset_hash": hash
|
||||||
@@ -35,7 +34,6 @@ async fn asset_hash(req: HttpRequest, Body(body): Body) -> impl Responder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn start(req: HttpRequest, Session { key, body }: Session) -> impl Responder {
|
async fn start(req: HttpRequest, Session { key, body }: Session) -> impl Responder {
|
||||||
|
|
||||||
let Some(asset_hash) = get_asset_hash(&req, &body) else {
|
let Some(asset_hash) = get_asset_hash(&req, &body) else {
|
||||||
return global::api_error(&req, global::RESULT_GAME_VERSION_UPDATED);
|
return global::api_error(&req, global::RESULT_GAME_VERSION_UPDATED);
|
||||||
};
|
};
|
||||||
@@ -47,6 +45,11 @@ async fn start(req: HttpRequest, Session { key, body }: Session) -> impl Respond
|
|||||||
user["user"]["last_login_time"] = global::timestamp().into();
|
user["user"]["last_login_time"] = global::timestamp().into();
|
||||||
|
|
||||||
userdata::save_acc(&key, user);
|
userdata::save_acc(&key, user);
|
||||||
|
userdata::save_protocol_version(&key, global::client_protocol_version(&req));
|
||||||
|
|
||||||
|
if !crate::router::card::client_supports_custom_cards(&req) && crate::router::card::account_supports_custom_cards(&key) {
|
||||||
|
return global::api_error(&req, global::RESULT_GAME_VERSION_UPDATED); // todo - maybe compatibility layer?
|
||||||
|
}
|
||||||
|
|
||||||
global::api(&req, Some(object!{
|
global::api(&req, Some(object!{
|
||||||
"asset_hash": asset_hash,
|
"asset_hash": asset_hash,
|
||||||
|
|||||||
@@ -83,25 +83,44 @@ pub fn proxy_user_cards(user: &mut JsonValue) {
|
|||||||
user["user"][key] = proxy_card_id(id).into();
|
user["user"][key] = proxy_card_id(id).into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// A card's id is its master_card_id, so both sides need proxying
|
||||||
for key in ["favorite_card", "guest_smile_card", "guest_cool_card", "guest_pure_card"] {
|
for key in ["favorite_card", "guest_smile_card", "guest_cool_card", "guest_pure_card"] {
|
||||||
let id = user[key]["master_card_id"].as_i64().unwrap_or(0);
|
let id = user[key]["master_card_id"].as_i64().unwrap_or(0);
|
||||||
if crate::router::card::is_custom(id) {
|
if crate::router::card::is_custom(id) {
|
||||||
|
user[key]["id"] = proxy_card_id(id).into();
|
||||||
user[key]["master_card_id"] = proxy_card_id(id).into();
|
user[key]["master_card_id"] = proxy_card_id(id).into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !user["main_deck_detail"].is_empty() {
|
if !user["main_deck_detail"].is_empty() {
|
||||||
|
let mut used = array![];
|
||||||
for id in user["main_deck_detail"]["deck"]["main_card_ids"].members_mut() {
|
for id in user["main_deck_detail"]["deck"]["main_card_ids"].members_mut() {
|
||||||
let card = id.as_i64().unwrap_or(0);
|
let card = proxy_card_id(id.as_i64().unwrap_or(0));
|
||||||
if crate::router::card::is_custom(card) {
|
// Whole characters share one proxy, and the client can't hold the
|
||||||
*id = proxy_card_id(card).into();
|
// same card twice
|
||||||
|
if card == 0 || used.contains(card) {
|
||||||
|
*id = (0).into();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
used.push(card).unwrap();
|
||||||
|
*id = card.into();
|
||||||
}
|
}
|
||||||
for card in user["main_deck_detail"]["card_list"].members_mut() {
|
let mut cards = array![];
|
||||||
|
let mut ids = array![];
|
||||||
|
for card in user["main_deck_detail"]["card_list"].members() {
|
||||||
let id = card["master_card_id"].as_i64().unwrap_or(0);
|
let id = card["master_card_id"].as_i64().unwrap_or(0);
|
||||||
if crate::router::card::is_custom(id) {
|
let proxy = proxy_card_id(id);
|
||||||
card["master_card_id"] = proxy_card_id(id).into();
|
if ids.contains(proxy) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
ids.push(proxy).unwrap();
|
||||||
|
let mut card = card.clone();
|
||||||
|
if proxy != id {
|
||||||
|
card["id"] = proxy.into();
|
||||||
|
card["master_card_id"] = proxy.into();
|
||||||
}
|
}
|
||||||
|
cards.push(card).unwrap();
|
||||||
|
}
|
||||||
|
user["main_deck_detail"]["card_list"] = cards;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,11 +59,6 @@ async fn deck(Session { key, body }: Session) -> impl Responder {
|
|||||||
async fn user(req: HttpRequest, Login(key): Login) -> impl Responder {
|
async fn user(req: HttpRequest, Login(key): Login) -> impl Responder {
|
||||||
let mut user = userdata::get_acc(&key);
|
let mut user = userdata::get_acc(&key);
|
||||||
|
|
||||||
// An account holding custom cards would break clients below protocol 2
|
|
||||||
if !crate::router::card::client_supports_custom_cards(&req) && crate::router::card::owns_custom(&user) {
|
|
||||||
return global::api_error(&req, global::RESULT_GAME_VERSION_UPDATED);
|
|
||||||
}
|
|
||||||
|
|
||||||
user["lottery_list"] = array![];
|
user["lottery_list"] = array![];
|
||||||
|
|
||||||
if crate::router::custom_song::client_supports_custom_songs(&req) {
|
if crate::router::custom_song::client_supports_custom_songs(&req) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use rand::RngExt;
|
|||||||
|
|
||||||
use crate::router::global;
|
use crate::router::global;
|
||||||
use crate::router::items;
|
use crate::router::items;
|
||||||
|
use crate::router::card;
|
||||||
use crate::database::custom_song;
|
use crate::database::custom_song;
|
||||||
use crate::sql::SQLite;
|
use crate::sql::SQLite;
|
||||||
use crate::include_file;
|
use crate::include_file;
|
||||||
@@ -35,7 +36,8 @@ CREATE TABLE IF NOT EXISTS tokens (
|
|||||||
CREATE TABLE IF NOT EXISTS userdata (
|
CREATE TABLE IF NOT EXISTS userdata (
|
||||||
user_id BIGINT NOT NULL PRIMARY KEY,
|
user_id BIGINT NOT NULL PRIMARY KEY,
|
||||||
userdata TEXT NOT NULL,
|
userdata TEXT NOT NULL,
|
||||||
friend_request_disabled INT NOT NULL
|
friend_request_disabled INT NOT NULL,
|
||||||
|
protocol_version INT NOT NULL DEFAULT 0
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS userhome (
|
CREATE TABLE IF NOT EXISTS userhome (
|
||||||
user_id BIGINT NOT NULL PRIMARY KEY,
|
user_id BIGINT NOT NULL PRIMARY KEY,
|
||||||
@@ -84,8 +86,63 @@ CREATE TABLE IF NOT EXISTS webui (
|
|||||||
);
|
);
|
||||||
INSERT OR IGNORE INTO exchange (user_id, exchange) SELECT user_id, '[]' FROM userdata;
|
INSERT OR IGNORE INTO exchange (user_id, exchange) SELECT user_id, '[]' FROM userdata;
|
||||||
").unwrap();
|
").unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
let is_updated = conn.prepare("SELECT protocol_version FROM userdata LIMIT 1;").is_ok();
|
||||||
|
if !is_updated {
|
||||||
|
println!("Upgrading userdata table");
|
||||||
|
conn.execute("ALTER TABLE userdata ADD COLUMN protocol_version INT NOT NULL DEFAULT 0;", []).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// maybe we will use this later
|
||||||
|
/*
|
||||||
|
pub fn downgrade_account_cards(user: &JsonValue) -> JsonValue {
|
||||||
|
let mut rv = user.clone();
|
||||||
|
|
||||||
|
let mut cards = array![];
|
||||||
|
let mut ids = array![];
|
||||||
|
for data in user["card_list"].members() {
|
||||||
|
let id = data["master_card_id"].as_i64().unwrap_or(0);
|
||||||
|
let downgraded = guest::proxy_card_id(id);
|
||||||
|
// Whole characters share one downgrade, and the client can't hold the
|
||||||
|
// same card twice
|
||||||
|
if ids.contains(downgraded) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ids.push(downgraded).unwrap();
|
||||||
|
let mut data = data.clone();
|
||||||
|
if downgraded != id {
|
||||||
|
data["id"] = downgraded.into();
|
||||||
|
data["master_card_id"] = downgraded.into();
|
||||||
|
}
|
||||||
|
cards.push(data).unwrap();
|
||||||
|
}
|
||||||
|
rv["card_list"] = cards;
|
||||||
|
|
||||||
|
for deck in rv["deck_list"].members_mut() {
|
||||||
|
let mut used = array![];
|
||||||
|
for slot in deck["main_card_ids"].members_mut() {
|
||||||
|
let id = guest::proxy_card_id(slot.as_i64().unwrap_or(0));
|
||||||
|
// Cards the downgrade merged away leave the slot empty
|
||||||
|
if id == 0 || used.contains(id) {
|
||||||
|
*slot = (0).into();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
used.push(id).unwrap();
|
||||||
|
*slot = id.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for key in ["favorite_master_card_id", "guest_smile_master_card_id", "guest_cool_master_card_id", "guest_pure_master_card_id"] {
|
||||||
|
let id = rv["user"][key].as_i64().unwrap_or(0);
|
||||||
|
rv["user"][key] = guest::proxy_card_id(id).into();
|
||||||
|
}
|
||||||
|
|
||||||
|
rv
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
fn acc_exists(uid: i64) -> bool {
|
fn acc_exists(uid: i64) -> bool {
|
||||||
DATABASE.lock_and_select("SELECT user_id FROM userdata WHERE user_id=?1", params!(uid)).is_ok()
|
DATABASE.lock_and_select("SELECT user_id FROM userdata WHERE user_id=?1", params!(uid)).is_ok()
|
||||||
}
|
}
|
||||||
@@ -120,10 +177,11 @@ fn add_user_to_database(uid: i64, user: JsonValue, user_home: JsonValue, user_mi
|
|||||||
let missions = jzon::stringify(user_missions.clone());
|
let missions = jzon::stringify(user_missions.clone());
|
||||||
let cards = jzon::stringify(sif_cards.clone());
|
let cards = jzon::stringify(sif_cards.clone());
|
||||||
|
|
||||||
DATABASE.lock_and_exec("INSERT INTO userdata (user_id, userdata, friend_request_disabled) VALUES (?1, ?2, ?3)", params!(
|
DATABASE.lock_and_exec("INSERT INTO userdata (user_id, userdata, friend_request_disabled, protocol_version) VALUES (?1, ?2, ?3, ?4)", params!(
|
||||||
uid,
|
uid,
|
||||||
jzon::stringify(user.clone()),
|
jzon::stringify(user.clone()),
|
||||||
user["user"]["friend_request_disabled"].as_i32().unwrap()
|
user["user"]["friend_request_disabled"].as_i32().unwrap(),
|
||||||
|
if card::account_has_custom_cards(&user) { card::PROTOCOL_VERSION } else { 0 }
|
||||||
));
|
));
|
||||||
DATABASE.lock_and_exec("INSERT INTO userhome (user_id, userhome) VALUES (?1, ?2)", params!(
|
DATABASE.lock_and_exec("INSERT INTO userhome (user_id, userhome) VALUES (?1, ?2)", params!(
|
||||||
uid,
|
uid,
|
||||||
@@ -325,6 +383,9 @@ pub fn get_acc_event(auth_key: &str) -> JsonValue {
|
|||||||
pub fn get_acc_eventlogin(auth_key: &str) -> JsonValue {
|
pub fn get_acc_eventlogin(auth_key: &str) -> JsonValue {
|
||||||
get_data(auth_key, "eventloginbonus")
|
get_data(auth_key, "eventloginbonus")
|
||||||
}
|
}
|
||||||
|
pub fn get_protocol_version(auth_key: &str) -> u32 {
|
||||||
|
DATABASE.lock_and_select("SELECT protocol_version FROM userdata WHERE user_id=?1", params!(get_key(auth_key))).unwrap_or_default().parse::<u32>().unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn save_data(auth_key: &str, row: &str, data: JsonValue) {
|
pub fn save_data(auth_key: &str, row: &str, data: JsonValue) {
|
||||||
let key = get_key(auth_key);
|
let key = get_key(auth_key);
|
||||||
@@ -363,6 +424,10 @@ pub fn save_acc_chats(auth_key: &str, data: JsonValue) {
|
|||||||
pub fn save_acc_exchange(auth_key: &str, data: JsonValue) {
|
pub fn save_acc_exchange(auth_key: &str, data: JsonValue) {
|
||||||
save_data(auth_key, "exchange", data);
|
save_data(auth_key, "exchange", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn save_protocol_version(auth_key: &str, version: u32) {
|
||||||
|
DATABASE.lock_and_exec("UPDATE userdata SET protocol_version=?1 WHERE user_id=?2 AND protocol_version<?1", params!(version as i64, get_key(auth_key)));
|
||||||
|
}
|
||||||
pub fn save_acc_sif(auth_key: &str, data: JsonValue) {
|
pub fn save_acc_sif(auth_key: &str, data: JsonValue) {
|
||||||
save_data(auth_key, "sifcards", data);
|
save_data(auth_key, "sifcards", data);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user