mirror of
https://github.com/yoncodes/BD2PS.git
synced 2026-11-05 22:16:49 +01:00
changed file section
This commit is contained in:
1 parent
1badd8cb4f
commit
397c34bec1
1568 files changed
+3068
-3575
No files matched your search
@@ -1 +1,2 @@
|
||||
pub mod quest_clear;
|
||||
pub mod reward_object;
|
||||
@@ -0,0 +1,216 @@
|
||||
use anyhow::{Result, anyhow};
|
||||
use bd2::proto::proto_net::{ItemDbInfo, QuestClearResponse, QuestDbInfo, RewardDbInfoBundle};
|
||||
use data::exceldb;
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct QuestReward {
|
||||
pub item_id: i32,
|
||||
pub item_type: i32,
|
||||
pub count: i32,
|
||||
}
|
||||
|
||||
pub async fn handle_quest_clear(
|
||||
pool: &SqlitePool,
|
||||
uid: i64,
|
||||
quest_id: i32,
|
||||
) -> Result<QuestClearResponse> {
|
||||
let game_data = exceldb::get();
|
||||
|
||||
// Step 1: Find quest entry
|
||||
let quest = game_data
|
||||
.questtable1
|
||||
.get(quest_id)
|
||||
.ok_or_else(|| anyhow!("QuestTable1: quest {} not found", quest_id))?;
|
||||
|
||||
// Step 2: Mark quest complete in DB
|
||||
mark_quest_complete(pool, uid, quest_id).await?;
|
||||
|
||||
// Step 3: Update clear info (quest level and max clear)
|
||||
upsert_quest_level_info(pool, uid, quest_id).await?;
|
||||
upsert_quest_max_clear_info(pool, uid, quest_id).await?;
|
||||
|
||||
// Step 4: Roll rewards from quest definition
|
||||
let rewards = extract_rewards(quest)?;
|
||||
|
||||
// Step 5: Insert rewards into inventory
|
||||
let item_db_infos = add_items_to_inventory(pool, uid, &rewards).await?;
|
||||
|
||||
// Step 6: Build RewardDBInfoBundle
|
||||
let reward_bundle = RewardDbInfoBundle {
|
||||
item_info: item_db_infos.clone(),
|
||||
view_item_info: item_db_infos.clone(),
|
||||
original_item_info: item_db_infos.clone(),
|
||||
char_info: vec![],
|
||||
costume_info: vec![],
|
||||
equip_info: vec![],
|
||||
my_room_trophy_info: vec![],
|
||||
item_auto_exchange_info: vec![],
|
||||
item_auto_upgrade_info: vec![],
|
||||
repaid_currency: vec![],
|
||||
};
|
||||
|
||||
// Step 7: Build next quest info
|
||||
let quest_info = quest.next_quest_id.map(|id| QuestDbInfo {
|
||||
id: Some(id),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// Step 8: Build final response
|
||||
Ok(QuestClearResponse {
|
||||
reward_info_bundle: Some(reward_bundle),
|
||||
quest_info,
|
||||
clear_quest_id: Some(quest_id),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
// -------------------- DB Operations --------------------
|
||||
|
||||
async fn mark_quest_complete(pool: &SqlitePool, uid: i64, quest_id: i32) -> Result<()> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
UPDATE UserQuest
|
||||
SET Status = 3, RewardClaimed = 1
|
||||
WHERE Uid = ? AND QuestId = ?
|
||||
"#,
|
||||
)
|
||||
.bind(uid)
|
||||
.bind(quest_id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn upsert_quest_level_info(pool: &SqlitePool, uid: i64, clear_quest: i32) -> Result<()> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
INSERT INTO QuestLevelInfo (Uid, PackId, QuestLevel, ClearQuest, QuestOpt, IsLevelComplete)
|
||||
VALUES (?, 1, 0, ?, 0, 0)
|
||||
ON CONFLICT(Uid, PackId)
|
||||
DO UPDATE SET ClearQuest = excluded.ClearQuest
|
||||
"#,
|
||||
)
|
||||
.bind(uid)
|
||||
.bind(clear_quest)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn upsert_quest_max_clear_info(pool: &SqlitePool, uid: i64, clear_quest: i32) -> Result<()> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
INSERT INTO QuestMaxClearInfo (Uid, PackId, MaxClearId)
|
||||
VALUES (?, 1, ?)
|
||||
ON CONFLICT(Uid, PackId)
|
||||
DO UPDATE SET MaxClearId = excluded.MaxClearId
|
||||
"#,
|
||||
)
|
||||
.bind(uid)
|
||||
.bind(clear_quest)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// -------------------- Reward Extraction --------------------
|
||||
|
||||
fn extract_rewards(quest: &data::exceldb::questtable1::Questtable1) -> Result<Vec<QuestReward>> {
|
||||
let types = quest
|
||||
.reward_type
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("Quest missing reward_type"))?;
|
||||
let ids = quest
|
||||
.reward_id
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("Quest missing reward_id"))?;
|
||||
let counts = quest
|
||||
.reward_count
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("Quest missing reward_count"))?;
|
||||
|
||||
let len = types.len().min(ids.len()).min(counts.len());
|
||||
Ok((0..len)
|
||||
.map(|i| QuestReward {
|
||||
item_id: ids[i],
|
||||
item_type: types[i],
|
||||
count: counts[i],
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
// -------------------- Inventory --------------------
|
||||
|
||||
async fn add_items_to_inventory(
|
||||
pool: &SqlitePool,
|
||||
uid: i64,
|
||||
items: &[QuestReward],
|
||||
) -> Result<Vec<ItemDbInfo>> {
|
||||
use sqlx::{Row, query};
|
||||
|
||||
let now = chrono::Utc::now().timestamp_millis();
|
||||
let row = query("SELECT COALESCE(MAX(InvenIndex), 0) as idx FROM ItemInfo WHERE Uid = ?")
|
||||
.bind(uid)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
let mut idx: i64 = row.get("idx");
|
||||
|
||||
let mut results = Vec::new();
|
||||
|
||||
for item in items {
|
||||
idx += 1;
|
||||
query(
|
||||
"INSERT INTO ItemInfo (Uid, InvenIndex, Id, Type, Count, KeepFlag, TimeValue, SortId, UseCount)
|
||||
VALUES (?, ?, ?, ?, ?, 0, ?, 0, 0)",
|
||||
)
|
||||
.bind(uid)
|
||||
.bind(idx)
|
||||
.bind(item.item_id)
|
||||
.bind(item.item_type)
|
||||
.bind(item.count)
|
||||
.bind(now)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
results.push(ItemDbInfo {
|
||||
inven_index: Some(idx),
|
||||
id: Some(item.item_id),
|
||||
r#type: Some(item.item_type),
|
||||
count: Some(item.count),
|
||||
keep_flag: Some(0),
|
||||
time_value: Some(now),
|
||||
pictorialbook_info: None,
|
||||
expiry_time: None,
|
||||
sort_id: Some(0),
|
||||
use_count: Some(0),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Tests
|
||||
// ============================================================================
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn setup() {
|
||||
use std::sync::Once;
|
||||
static INIT: Once = Once::new();
|
||||
|
||||
INIT.call_once(|| {
|
||||
let data_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("data")
|
||||
.join("tables");
|
||||
|
||||
exceldb::init(data_path.to_str().unwrap()).expect("Failed to initialize game data");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
// gameserver/src/logic/field/reward_object.rs
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use bd2::proto::proto_net::{
|
||||
FieldObjectRewardRequest, FieldObjectRewardResponse, ItemDbInfo, MonsterDbInfo,
|
||||
@@ -8,10 +6,6 @@ use bd2::proto::proto_net::{
|
||||
use data::exceldb;
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
// ============================================================================
|
||||
// Internal Helper Structures
|
||||
// ============================================================================
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
struct ItemDrop {
|
||||
id: i32,
|
||||
@@ -19,10 +13,6 @@ struct ItemDrop {
|
||||
count: i32,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main Handler Function
|
||||
// ============================================================================
|
||||
|
||||
pub async fn collect_field_object(
|
||||
pool: &SqlitePool,
|
||||
user_id: i64,
|
||||
@@ -113,7 +103,7 @@ pub async fn collect_field_object(
|
||||
let response = FieldObjectRewardResponse {
|
||||
reward_info_bundle: Some(reward_bundle),
|
||||
monster_info: Some(MonsterDbInfo {
|
||||
active_flag: Some(true), // ← Hardcoded like C#
|
||||
active_flag: Some(true), // ← Hardcoded for now
|
||||
..Default::default()
|
||||
}),
|
||||
field_buff_info: vec![],
|
||||
@@ -123,10 +113,6 @@ pub async fn collect_field_object(
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Helper Functions
|
||||
// ============================================================================
|
||||
|
||||
fn roll_rewards(
|
||||
reward_group: &data::exceldb::rewardgrouptable::Rewardgrouptable,
|
||||
) -> Result<Vec<ItemDrop>> {
|
||||
|
||||
@@ -25,7 +25,7 @@ pub async fn get_or_create_user(
|
||||
uid: i64,
|
||||
) -> Result<(Account, UserInfo), LoginError> {
|
||||
// Use the database layer's get_or_create_user which handles the mapping
|
||||
let (account, user_info) = db::user::get_or_create_user(pool, uid).await?;
|
||||
let (account, user_info) = db::user::user::get_or_create_user(pool, uid).await?;
|
||||
|
||||
info!("User logged in: {}", account.user_name);
|
||||
Ok((account, user_info))
|
||||
@@ -34,7 +34,7 @@ pub async fn get_or_create_user(
|
||||
/// Update user's return status timestamp
|
||||
pub async fn update_login_timestamp(pool: &SqlitePool, uid: i64) -> Result<(), LoginError> {
|
||||
let now_ms = chrono::Utc::now().timestamp_millis();
|
||||
db::user::update_return_status(pool, uid, now_ms).await?;
|
||||
db::user::user::update_return_status(pool, uid, now_ms).await?;
|
||||
info!("Updated return status for UID {} to {}", uid, now_ms);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
File renamed without changes.
+1
-1
@@ -4,7 +4,7 @@ use bd2::proto::proto_net::{
|
||||
};
|
||||
use common::packet_code::PacketCodeType;
|
||||
use crypto::network::GameResponse;
|
||||
use database::db::achievement_info::get_achievement_info;
|
||||
use database::db::achievement::achievement_info::get_achievement_info;
|
||||
use sqlx::SqlitePool;
|
||||
use tracing::info;
|
||||
|
||||
File renamed without changes.
@@ -0,0 +1,3 @@
|
||||
pub mod achievement_clear;
|
||||
pub mod achievement_info;
|
||||
pub mod achievement_update;
|
||||
+20
-9
@@ -2,21 +2,32 @@ use bd2::prost::Message;
|
||||
use bd2::proto::proto_net::{ActiveMapRequest, ActiveMapResponse, Notify};
|
||||
use common::packet_code::PacketCodeType;
|
||||
use crypto::network::GameResponse;
|
||||
use database::db::map::map_active_info::add_map_active_info;
|
||||
use database::models::game::map_active_info::MapActiveInfo;
|
||||
use serde_json::to_string;
|
||||
use sqlx::SqlitePool;
|
||||
use tracing::info;
|
||||
|
||||
pub async fn handle(_pool: &SqlitePool, _uid: i64, req: ActiveMapRequest) -> GameResponse {
|
||||
pub async fn handle(pool: &SqlitePool, uid: i64, req: ActiveMapRequest) -> GameResponse {
|
||||
info!("Handling ActiveMapRequest: {:?}", req);
|
||||
|
||||
// TODO: Fetch data from database
|
||||
// Example:
|
||||
// let data = get_something(pool, uid).await.unwrap_or_default();
|
||||
let active_info_json = to_string(&req.active_info).unwrap_or_else(|_| "[]".to_string());
|
||||
|
||||
// TODO: Transform to proto
|
||||
// Example:
|
||||
// let proto_data = data.into_iter()
|
||||
// .map(|item| mapper::to_proto(item, pool).await)
|
||||
// .collect();
|
||||
if let Some(id) = req.map_id {
|
||||
let record = MapActiveInfo {
|
||||
index: 0, // autoincrement
|
||||
uid,
|
||||
map_id: Some(id),
|
||||
active_info: active_info_json,
|
||||
};
|
||||
|
||||
if let Err(e) = add_map_active_info(pool, &record).await {
|
||||
eprintln!(
|
||||
"Failed to insert active_info {} for uid {}: {:?}",
|
||||
id, uid, e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let response = ActiveMapResponse {
|
||||
// TODO: Fill in response fields
|
||||
@@ -0,0 +1 @@
|
||||
pub mod active_map;
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,2 @@
|
||||
pub mod alchemy;
|
||||
pub mod alchemy_batch;
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
pub mod all_char_refresh;
|
||||
@@ -5,8 +5,8 @@ use bd2::proto::proto_net::{
|
||||
};
|
||||
use common::packet_code::PacketCodeType;
|
||||
use crypto::network::GameResponse;
|
||||
use database::db::attendance_always_info::get_attendance_always_info;
|
||||
use database::db::attendance_event_reward_obtain_info::get_attendance_event_reward_obtain_info;
|
||||
use database::db::attendance::attendance_always_info::get_attendance_always_info;
|
||||
use database::db::attendance::attendance_event_reward_obtain_info::get_attendance_event_reward_obtain_info;
|
||||
use sqlx::SqlitePool;
|
||||
use tracing::info;
|
||||
|
||||
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
pub mod balance_version_check;
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
pub mod batch_request;
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,9 @@
|
||||
pub mod battle_end;
|
||||
pub mod battle_end_test;
|
||||
pub mod battle_enter;
|
||||
pub mod battle_exit;
|
||||
pub mod battle_give_up;
|
||||
pub mod battle_retry;
|
||||
pub mod battle_retry_previous_turn;
|
||||
pub mod battle_start;
|
||||
pub mod battle_verify_state;
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,16 @@
|
||||
pub mod cafeteria_cumulative_reward;
|
||||
pub mod cafeteria_daily_connection_costume_refresh;
|
||||
pub mod cafeteria_event_npc_interaction_reward;
|
||||
pub mod cafeteria_info;
|
||||
pub mod cafeteria_introduction_story_reward;
|
||||
pub mod cafeteria_level_up;
|
||||
pub mod cafeteria_manage_item_add;
|
||||
pub mod cafeteria_rare_npc_interaction_reward;
|
||||
pub mod cafeteria_regular_costume_interaction_all_reward;
|
||||
pub mod cafeteria_regular_costume_interaction_reward;
|
||||
pub mod cafeteria_regular_costume_note_all_reward;
|
||||
pub mod cafeteria_regular_costume_note_info;
|
||||
pub mod cafeteria_regular_costume_note_reward;
|
||||
pub mod cafeteria_reward_receipt_time_update_using_cheat;
|
||||
pub mod cafeteria_spawn_reset;
|
||||
pub mod cafeteria_spawn_reset_cheat;
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
pub mod cancel_leave_user;
|
||||
File renamed without changes.
File renamed without changes.
+4
-3
@@ -13,9 +13,10 @@ pub async fn handle(
|
||||
info!("Handling CashShopInfoRequest");
|
||||
|
||||
// Load the JSON file from starter data
|
||||
let data: Value =
|
||||
serde_json::from_str(include_str!("../../../../data/starter/cash_shop_info.json"))
|
||||
.expect("Failed to parse cash_shop_info.json");
|
||||
let data: Value = serde_json::from_str(include_str!(
|
||||
"../../../../../data/starter/cash_shop_info.json"
|
||||
))
|
||||
.expect("Failed to parse cash_shop_info.json");
|
||||
|
||||
let products = data
|
||||
.get("productInfo")
|
||||
File renamed without changes.
@@ -0,0 +1,4 @@
|
||||
pub mod cash_mail_info;
|
||||
pub mod cash_shop_buy;
|
||||
pub mod cash_shop_info;
|
||||
pub mod cash_shop_purchase_count_info;
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ use bd2::prost::Message;
|
||||
use bd2::proto::proto_net::{CharDbInfo, CharInfoRequest, CharInfoResponse, Notify};
|
||||
use common::packet_code::PacketCodeType;
|
||||
use crypto::network::GameResponse;
|
||||
use database::db::char_info::get_char_info;
|
||||
use database::db::char::char_info::get_char_info;
|
||||
use sqlx::SqlitePool;
|
||||
use tracing::info;
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,18 @@
|
||||
pub mod char_all_revival;
|
||||
pub mod char_auto_revive_set;
|
||||
pub mod char_awake_active;
|
||||
pub mod char_awake_info;
|
||||
pub mod char_class_up;
|
||||
pub mod char_expiry;
|
||||
pub mod char_growth;
|
||||
pub mod char_healing;
|
||||
pub mod char_immortal;
|
||||
pub mod char_imprint_level_up;
|
||||
pub mod char_info;
|
||||
pub mod char_level_up;
|
||||
pub mod char_partner_info;
|
||||
pub mod char_partner_reward;
|
||||
pub mod char_partner_story_reward;
|
||||
pub mod char_scout_info;
|
||||
pub mod char_special_scout_buy;
|
||||
pub mod char_special_scout_reset;
|
||||
+1
-1
@@ -4,7 +4,7 @@ use bd2::proto::proto_net::{
|
||||
};
|
||||
use common::packet_code::PacketCodeType;
|
||||
use crypto::network::GameResponse;
|
||||
use database::db::charge_cost_event_schedule_info::get_charge_cost_event_schedule_info;
|
||||
use database::db::charge::charge_cost_event_schedule_info::get_charge_cost_event_schedule_info;
|
||||
use database::models::game::charge_cost_event_schedule_info::ChargeCostEventScheduleInfo;
|
||||
use prost::Message;
|
||||
use sqlx::SqlitePool;
|
||||
@@ -0,0 +1 @@
|
||||
pub mod charge_cost_info;
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
pub mod clear_package_reward;
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
pub mod client_custom_log;
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,2 @@
|
||||
pub mod community_reward;
|
||||
pub mod community_reward_info;
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,2 @@
|
||||
pub mod cooking;
|
||||
pub mod cooking_research;
|
||||
File renamed without changes.
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ use bd2::prost::Message;
|
||||
use bd2::proto::proto_net::{CostumeDbInfo, CostumeInfoRequest, CostumeInfoResponse, Notify};
|
||||
use common::packet_code::PacketCodeType;
|
||||
use crypto::network::GameResponse;
|
||||
use database::db::costume_info::get_costume_info;
|
||||
use database::db::costume::costume_info::get_costume_info;
|
||||
use serde_json;
|
||||
use sqlx::SqlitePool;
|
||||
use tracing::info;
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,7 @@
|
||||
pub mod costume_all_rounder_upgrade;
|
||||
pub mod costume_clear;
|
||||
pub mod costume_info;
|
||||
pub mod costume_node_activation;
|
||||
pub mod costume_potential_connect;
|
||||
pub mod costume_upgrade;
|
||||
pub mod costume_use;
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,3 @@
|
||||
pub mod dating_episode_clear;
|
||||
pub mod dating_info;
|
||||
pub mod dating_message_update;
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 1568 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user