mirror of
https://github.com/redstrate/Kawari.git
synced 2025-06-30 11:47:45 +00:00
Load the actual weather rates for zones instead of using Sunny
This doesn't match up with retail yet (I don't know why.) But this fixes the appearance of lots of dungeons and other instanced content that have their own special weather.
This commit is contained in:
parent
4146261c40
commit
53a3d5d6a4
3 changed files with 73 additions and 2 deletions
|
@ -104,4 +104,4 @@ rkon = { version = "0.1" }
|
|||
tower-http = { version = "0.6", features = ["fs", "cors"] }
|
||||
|
||||
# excel sheet data
|
||||
icarus = { git = "https://github.com/redstrate/Icarus", branch = "ver/2025.04.16.0000.0000", features = ["Warp", "Tribe", "ClassJob", "World", "TerritoryType", "Race", "Aetheryte", "EquipSlotCategory", "Action"], default-features = false }
|
||||
icarus = { git = "https://github.com/redstrate/Icarus", branch = "ver/2025.04.16.0000.0000", features = ["Warp", "Tribe", "ClassJob", "World", "TerritoryType", "Race", "Aetheryte", "EquipSlotCategory", "Action", "WeatherRate"], default-features = false }
|
||||
|
|
|
@ -2,6 +2,8 @@ use icarus::Action::ActionSheet;
|
|||
use icarus::Aetheryte::AetheryteSheet;
|
||||
use icarus::ClassJob::ClassJobSheet;
|
||||
use icarus::EquipSlotCategory::EquipSlotCategorySheet;
|
||||
use icarus::TerritoryType::TerritoryTypeSheet;
|
||||
use icarus::WeatherRate::WeatherRateSheet;
|
||||
use icarus::World::WorldSheet;
|
||||
use icarus::{Tribe::TribeSheet, Warp::WarpSheet};
|
||||
use physis::common::{Language, Platform};
|
||||
|
@ -10,6 +12,8 @@ use physis::exh::EXH;
|
|||
|
||||
use crate::{common::Attributes, config::get_config};
|
||||
|
||||
use super::timestamp_secs;
|
||||
|
||||
/// Convenient methods built on top of Physis to access data relevant to the server
|
||||
pub struct GameData {
|
||||
pub game_data: physis::gamedata::GameData,
|
||||
|
@ -227,4 +231,63 @@ impl GameData {
|
|||
|
||||
row.Cast100ms().into_u16().copied()
|
||||
}
|
||||
|
||||
/// Calculates the current weather at the current time
|
||||
// TODO: instead allow targetting a specific time to calculate forcecasts
|
||||
pub fn get_weather_rate(&mut self, weather_rate_id: u32) -> Option<i32> {
|
||||
let sheet = WeatherRateSheet::read_from(&mut self.game_data, Language::None)?;
|
||||
let row = sheet.get_row(weather_rate_id)?;
|
||||
|
||||
let target = Self::calculate_target();
|
||||
let weather_and_rates: Vec<(i32, i32)> = row
|
||||
.Weather()
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip(row.Rate().clone())
|
||||
.map(|(x, y)| (*x.into_i32().unwrap(), *y.into_u8().unwrap() as i32))
|
||||
.collect();
|
||||
|
||||
Some(
|
||||
weather_and_rates
|
||||
.iter()
|
||||
.filter(|(_, rate)| target < *rate)
|
||||
.take(1)
|
||||
.collect::<Vec<&(i32, i32)>>()
|
||||
.first()?
|
||||
.0,
|
||||
)
|
||||
}
|
||||
|
||||
/// Calculate target window for weather calculations
|
||||
fn calculate_target() -> i32 {
|
||||
// Based off of https://github.com/Rogueadyn/SaintCoinach/blob/master/SaintCoinach/Xiv/WeatherRate.cs
|
||||
// TODO: this isn't correct still and doesn't seem to match up with the retail server
|
||||
|
||||
let real_to_eorzean_factor = (60.0 * 24.0) / 70.0;
|
||||
let unix = (timestamp_secs() as f32 / real_to_eorzean_factor) as u64;
|
||||
// Get Eorzea hour for weather start
|
||||
let bell = unix / 175;
|
||||
// Do the magic 'cause for calculations 16:00 is 0, 00:00 is 8 and 08:00 is 16
|
||||
let increment = ((bell + 8 - (bell % 8)) as u32) % 24;
|
||||
|
||||
// Take Eorzea days since unix epoch
|
||||
let total_days = (unix / 4200) as u32;
|
||||
|
||||
let calc_base = (total_days * 0x64) + increment;
|
||||
|
||||
let step1 = (calc_base << 0xB) ^ calc_base;
|
||||
let step2 = (step1 >> 8) ^ step1;
|
||||
|
||||
(step2 % 0x64) as i32
|
||||
}
|
||||
|
||||
/// Gets the current weather for the given zone id
|
||||
pub fn get_weather(&mut self, zone_id: u32) -> Option<i32> {
|
||||
let sheet = TerritoryTypeSheet::read_from(&mut self.game_data, Language::None)?;
|
||||
let row = sheet.get_row(zone_id)?;
|
||||
|
||||
let weather_rate_id = row.WeatherRate().into_u8()?;
|
||||
|
||||
self.get_weather_rate(*weather_rate_id as u32)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -346,12 +346,20 @@ impl ZoneConnection {
|
|||
{
|
||||
let config = get_config();
|
||||
|
||||
let weather_id;
|
||||
{
|
||||
let mut game_data = self.gamedata.lock().unwrap();
|
||||
weather_id = game_data
|
||||
.get_weather(self.zone.as_ref().unwrap().id.into())
|
||||
.unwrap_or(1) as u16;
|
||||
}
|
||||
|
||||
let ipc = ServerZoneIpcSegment {
|
||||
op_code: ServerZoneIpcType::InitZone,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::InitZone(InitZone {
|
||||
territory_type: self.zone.as_ref().unwrap().id,
|
||||
weather_id: 1,
|
||||
weather_id,
|
||||
obsfucation_mode: if config.world.enable_packet_obsfucation {
|
||||
OBFUSCATION_ENABLED_MODE
|
||||
} else {
|
||||
|
|
Loading…
Add table
Reference in a new issue