mirror of
https://github.com/yoncodes/BD2PS.git
synced 2026-08-05 06:12:14 +02:00
changed file section
This commit is contained in:
@@ -1 +1,2 @@
|
||||
pub mod quest_clear;
|
||||
pub mod reward_object;
|
||||
|
||||
216
gameserver/src/logic/field/quest_clear.rs
Normal file
216
gameserver/src/logic/field/quest_clear.rs
Normal file
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
3
gameserver/src/logic/game/achievement/mod.rs
Normal file
3
gameserver/src/logic/game/achievement/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod achievement_clear;
|
||||
pub mod achievement_info;
|
||||
pub mod achievement_update;
|
||||
@@ -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
|
||||
1
gameserver/src/logic/game/active/mod.rs
Normal file
1
gameserver/src/logic/game/active/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod active_map;
|
||||
2
gameserver/src/logic/game/alchemy/mod.rs
Normal file
2
gameserver/src/logic/game/alchemy/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod alchemy;
|
||||
pub mod alchemy_batch;
|
||||
1
gameserver/src/logic/game/all/mod.rs
Normal file
1
gameserver/src/logic/game/all/mod.rs
Normal file
@@ -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;
|
||||
|
||||
|
||||
1
gameserver/src/logic/game/balance/mod.rs
Normal file
1
gameserver/src/logic/game/balance/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod balance_version_check;
|
||||
1
gameserver/src/logic/game/batch/mod.rs
Normal file
1
gameserver/src/logic/game/batch/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod batch_request;
|
||||
9
gameserver/src/logic/game/battle/mod.rs
Normal file
9
gameserver/src/logic/game/battle/mod.rs
Normal file
@@ -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;
|
||||
16
gameserver/src/logic/game/cafeteria/mod.rs
Normal file
16
gameserver/src/logic/game/cafeteria/mod.rs
Normal file
@@ -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;
|
||||
1
gameserver/src/logic/game/cancel/mod.rs
Normal file
1
gameserver/src/logic/game/cancel/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod cancel_leave_user;
|
||||
@@ -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")
|
||||
4
gameserver/src/logic/game/cash/mod.rs
Normal file
4
gameserver/src/logic/game/cash/mod.rs
Normal file
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
18
gameserver/src/logic/game/char/mod.rs
Normal file
18
gameserver/src/logic/game/char/mod.rs
Normal file
@@ -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;
|
||||
@@ -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;
|
||||
1
gameserver/src/logic/game/charge/mod.rs
Normal file
1
gameserver/src/logic/game/charge/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod charge_cost_info;
|
||||
1
gameserver/src/logic/game/clear/mod.rs
Normal file
1
gameserver/src/logic/game/clear/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod clear_package_reward;
|
||||
1
gameserver/src/logic/game/client/mod.rs
Normal file
1
gameserver/src/logic/game/client/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod client_custom_log;
|
||||
2
gameserver/src/logic/game/community/mod.rs
Normal file
2
gameserver/src/logic/game/community/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod community_reward;
|
||||
pub mod community_reward_info;
|
||||
2
gameserver/src/logic/game/cooking/mod.rs
Normal file
2
gameserver/src/logic/game/cooking/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod cooking;
|
||||
pub mod cooking_research;
|
||||
@@ -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;
|
||||
7
gameserver/src/logic/game/costume/mod.rs
Normal file
7
gameserver/src/logic/game/costume/mod.rs
Normal file
@@ -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;
|
||||
3
gameserver/src/logic/game/dating/mod.rs
Normal file
3
gameserver/src/logic/game/dating/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod dating_episode_clear;
|
||||
pub mod dating_info;
|
||||
pub mod dating_message_update;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user