changed file section

This commit is contained in:
yoncodes
2025-10-29 14:13:47 -04:00
parent 1badd8cb4f
commit 397c34bec1
1568 changed files with 3068 additions and 3575 deletions

View File

@@ -1 +1,2 @@
pub mod quest_clear;
pub mod reward_object;

View 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");
});
}
}

View File

@@ -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>> {

View File

@@ -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(())
}

View File

@@ -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;

View File

@@ -0,0 +1,3 @@
pub mod achievement_clear;
pub mod achievement_info;
pub mod achievement_update;

View File

@@ -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

View File

@@ -0,0 +1 @@
pub mod active_map;

View File

@@ -0,0 +1,2 @@
pub mod alchemy;
pub mod alchemy_batch;

View File

@@ -0,0 +1 @@
pub mod all_char_refresh;

View File

@@ -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;

View File

@@ -0,0 +1 @@
pub mod balance_version_check;

View File

@@ -0,0 +1 @@
pub mod batch_request;

View 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;

View 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;

View File

@@ -0,0 +1 @@
pub mod cancel_leave_user;

View File

@@ -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")

View 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;

View File

@@ -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;

View 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;

View File

@@ -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;

View File

@@ -0,0 +1 @@
pub mod charge_cost_info;

View File

@@ -0,0 +1 @@
pub mod clear_package_reward;

View File

@@ -0,0 +1 @@
pub mod client_custom_log;

View File

@@ -0,0 +1,2 @@
pub mod community_reward;
pub mod community_reward_info;

View File

@@ -0,0 +1,2 @@
pub mod cooking;
pub mod cooking_research;

View File

@@ -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;

View 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;

View 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