1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-05-12 14:47:46 +00:00

Make Limsa Inn warp functional

This was surprisingly easy, so now this works. You can't exit the inn
yet, though!
This commit is contained in:
Joshua Goins 2025-05-05 22:04:39 -04:00
parent afbadf85c4
commit fec6665d8d
6 changed files with 96 additions and 9 deletions

View file

@ -8,3 +8,10 @@ function onTalk(target, player)
-- doesn't have inn access -- doesn't have inn access
--player:play_scene(actorId, EVENT_ID, 00002, 8192, 0) --player:play_scene(actorId, EVENT_ID, 00002, 8192, 0)
end end
function onReturn(results, player)
if results[1] == 1 then
-- get warp
player:warp(EVENT_ID)
end
end

View file

@ -135,9 +135,6 @@ async fn client_loop(
let lua = connection.lua.clone(); let lua = connection.lua.clone();
let config = get_config(); let config = get_config();
let mut exit_position = None;
let mut exit_rotation = None;
let mut lua_player = LuaPlayer::default(); let mut lua_player = LuaPlayer::default();
let mut buf = vec![0; RECEIVE_BUFFER_SIZE]; let mut buf = vec![0; RECEIVE_BUFFER_SIZE];
@ -162,8 +159,8 @@ async fn client_loop(
// collect actor data // collect actor data
connection.initialize(actor_id).await; connection.initialize(actor_id).await;
exit_position = Some(connection.player_data.position); connection.exit_position = Some(connection.player_data.position);
exit_rotation = Some(connection.player_data.rotation); connection.exit_rotation = Some(connection.player_data.rotation);
// tell the server we exist, now that we confirmed we are a legitimate connection // tell the server we exist, now that we confirmed we are a legitimate connection
connection.handle.send(ToServer::NewClient(client_handle.clone())).await; connection.handle.send(ToServer::NewClient(client_handle.clone())).await;
@ -318,7 +315,7 @@ async fn client_loop(
// tell the server we loaded into the zone, so it can start sending us acors // tell the server we loaded into the zone, so it can start sending us acors
connection.handle.send(ToServer::ZoneLoaded(connection.id)).await; connection.handle.send(ToServer::ZoneLoaded(connection.id)).await;
let common = connection.get_player_common_spawn(exit_position, exit_rotation); let common = connection.get_player_common_spawn(connection.exit_position, connection.exit_rotation);
// send player spawn // send player spawn
{ {
@ -370,8 +367,8 @@ async fn client_loop(
} }
// wipe any exit position so it isn't accidentally reused // wipe any exit position so it isn't accidentally reused
exit_position = None; connection.exit_position = None;
exit_rotation = None; connection.exit_rotation = None;
// tell the other players we're here // tell the other players we're here
connection.handle.send(ToServer::ActorSpawned(connection.id, Actor { id: ObjectId(connection.player_data.actor_id), hp: 100, spawn_index: 0 }, common)).await; connection.handle.send(ToServer::ActorSpawned(connection.id, Actor { id: ObjectId(connection.player_data.actor_id), hp: 100, spawn_index: 0 }, common)).await;
@ -571,7 +568,7 @@ async fn client_loop(
.unwrap(); .unwrap();
// set the exit position // set the exit position
exit_position = Some(Position { connection.exit_position = Some(Position {
x: destination_object.transform.translation[0], x: destination_object.transform.translation[0],
y: destination_object.transform.translation[1], y: destination_object.transform.translation[1],
z: destination_object.transform.translation[2], z: destination_object.transform.translation[2],
@ -769,6 +766,12 @@ async fn client_loop(
ClientZoneIpcData::EventHandlerReturn { handler_id, scene, error_code, num_results, results } => { ClientZoneIpcData::EventHandlerReturn { handler_id, scene, error_code, num_results, results } => {
tracing::info!("Finishing this event... {handler_id} {scene} {error_code} {num_results} {results:#?}"); tracing::info!("Finishing this event... {handler_id} {scene} {error_code} {num_results} {results:#?}");
connection
.event
.as_mut()
.unwrap()
.finish(results, &mut lua_player);
{ {
// TODO: handle in lua script // TODO: handle in lua script
let ipc = ServerZoneIpcSegment { let ipc = ServerZoneIpcSegment {
@ -969,6 +972,8 @@ async fn main() {
database: database.clone(), database: database.clone(),
lua: lua.clone(), lua: lua.clone(),
gamedata: game_data.clone(), gamedata: game_data.clone(),
exit_position: None,
exit_rotation: None,
}); });
} }
Some((mut socket, _)) = handle_rcon(&rcon_listener) => { Some((mut socket, _)) = handle_rcon(&rcon_listener) => {

View file

@ -122,4 +122,25 @@ impl GameData {
None None
} }
/// Returns the pop range object id that's associated with the warp id
pub fn get_warp(&mut self, warp_id: u32) -> (u32, u16) {
let exh = self.game_data.read_excel_sheet_header("Warp").unwrap();
let exd = self
.game_data
.read_excel_sheet("Warp", &exh, Language::English, 0)
.unwrap();
let row = &exd.read_row(&exh, warp_id).unwrap()[0];
let physis::exd::ColumnData::UInt32(pop_range_id) = &row.data[0] else {
panic!("Unexpected type!");
};
let physis::exd::ColumnData::UInt16(zone_id) = &row.data[1] else {
panic!("Unexpected type!");
};
(*pop_range_id, *zone_id)
}
} }

View file

@ -152,6 +152,9 @@ pub struct ZoneConnection {
pub database: Arc<WorldDatabase>, pub database: Arc<WorldDatabase>,
pub lua: Arc<Mutex<mlua::Lua>>, pub lua: Arc<Mutex<mlua::Lua>>,
pub gamedata: Arc<Mutex<GameData>>, pub gamedata: Arc<Mutex<GameData>>,
pub exit_position: Option<Position>,
pub exit_rotation: Option<f32>,
} }
impl ZoneConnection { impl ZoneConnection {
@ -422,6 +425,31 @@ impl ZoneConnection {
} }
} }
pub async fn warp(&mut self, warp_id: u32) {
let territory_type;
// find the pop range on the other side
{
let mut game_data = self.gamedata.lock().unwrap();
let (pop_range_id, zone_id) = game_data.get_warp(warp_id);
let new_zone = Zone::load(&mut game_data.game_data, zone_id);
// find it on the other side
let (object, _) = new_zone.find_pop_range(pop_range_id).unwrap();
// set the exit position
self.exit_position = Some(Position {
x: object.transform.translation[0],
y: object.transform.translation[1],
z: object.transform.translation[2],
});
territory_type = zone_id;
}
self.change_zone(territory_type as u16).await;
}
pub async fn change_weather(&mut self, new_weather_id: u16) { pub async fn change_weather(&mut self, new_weather_id: u16) {
let ipc = ServerZoneIpcSegment { let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::WeatherId, op_code: ServerZoneIpcType::WeatherId,
@ -569,6 +597,9 @@ impl ZoneConnection {
Task::SetRemakeMode(remake_mode) => self Task::SetRemakeMode(remake_mode) => self
.database .database
.set_remake_mode(player.player_data.content_id, *remake_mode), .set_remake_mode(player.player_data.content_id, *remake_mode),
Task::Warp { warp_id } => {
self.warp(*warp_id).await;
}
} }
} }
player.queued_tasks.clear(); player.queued_tasks.clear();

View file

@ -64,4 +64,18 @@ impl Event {
}) })
.unwrap(); .unwrap();
} }
pub fn finish(&mut self, results: &[u32], player: &mut LuaPlayer) {
self.lua
.scope(|scope| {
let player = scope.create_userdata_ref_mut(player).unwrap();
let func: Function = self.lua.globals().get("onReturn").unwrap();
func.call::<()>((results, player)).unwrap();
Ok(())
})
.unwrap();
}
} }

View file

@ -15,6 +15,7 @@ use super::{PlayerData, StatusEffects, Zone};
pub enum Task { pub enum Task {
ChangeTerritory { zone_id: u16 }, ChangeTerritory { zone_id: u16 },
SetRemakeMode(RemakeMode), SetRemakeMode(RemakeMode),
Warp { warp_id: u32 },
} }
#[derive(Default)] #[derive(Default)]
@ -109,6 +110,10 @@ impl LuaPlayer {
fn set_remake_mode(&mut self, mode: RemakeMode) { fn set_remake_mode(&mut self, mode: RemakeMode) {
self.queued_tasks.push(Task::SetRemakeMode(mode)); self.queued_tasks.push(Task::SetRemakeMode(mode));
} }
fn warp(&mut self, warp_id: u32) {
self.queued_tasks.push(Task::Warp { warp_id });
}
} }
impl UserData for LuaPlayer { impl UserData for LuaPlayer {
@ -144,6 +149,10 @@ impl UserData for LuaPlayer {
this.set_remake_mode(mode); this.set_remake_mode(mode);
Ok(()) Ok(())
}); });
methods.add_method_mut("warp", |_, this, warp_id: u32| {
this.warp(warp_id);
Ok(())
});
} }
} }