1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-04-26 16:37:46 +00:00

Add basic Event scripting capaibilities

This implements the first event script, going from the first Ul'dah opening
cutscene to the next.
This commit is contained in:
Joshua Goins 2025-03-28 21:28:30 -04:00
parent bcbe62af06
commit c4b9ad060b
8 changed files with 142 additions and 38 deletions

View file

@ -0,0 +1,21 @@
--- TODO: find a way to hardcode it this way
EVENT_ID = 1245187
function Scene00000(player)
player:play_scene(EVENT_ID, 00000, 4959237, 1)
end
function Scene00001(player)
--- todo put player in correct position
player:play_scene(EVENT_ID, 00001, 4959237, 1)
end
function onEnterTerritory(player)
Scene00000(player);
end
function onSceneFinished(player, scene)
if scene == 0 then
Scene00001(player)
end
end

View file

@ -76,6 +76,7 @@ async fn main() {
position: Position::default(), position: Position::default(),
inventory: Inventory::new(), inventory: Inventory::new(),
status_effects: StatusEffects::default(), status_effects: StatusEffects::default(),
event: None,
}; };
let mut lua_player = LuaPlayer::default(); let mut lua_player = LuaPlayer::default();
@ -570,6 +571,7 @@ async fn main() {
ClientZoneIpcData::ChatMessage(chat_message) => { ClientZoneIpcData::ChatMessage(chat_message) => {
ChatHandler::handle_chat_message( ChatHandler::handle_chat_message(
&mut connection, &mut connection,
&mut lua_player,
chat_message, chat_message,
) )
.await .await
@ -754,6 +756,10 @@ async fn main() {
tracing::info!( tracing::info!(
"Recieved EventRelatedUnk! {unk1} {unk2} {unk3} {unk4}" "Recieved EventRelatedUnk! {unk1} {unk2} {unk3} {unk4}"
); );
if let Some(event) = connection.event.as_mut() {
event.scene_finished(&mut lua_player, *unk2);
}
} }
} }
} }

View file

@ -3,14 +3,17 @@ use crate::{
config::get_config, config::get_config,
opcodes::ServerZoneIpcType, opcodes::ServerZoneIpcType,
packet::{PacketSegment, SegmentType}, packet::{PacketSegment, SegmentType},
world::ipc::{ world::{
ActorControl, ActorControlCategory, BattleNpcSubKind, CommonSpawn, DisplayFlag, EventPlay, Event,
EventStart, NpcSpawn, ObjectKind, OnlineStatus, PlayerSpawn, PlayerSubKind, ipc::{
ServerZoneIpcData, ServerZoneIpcSegment, ActorControl, ActorControlCategory, BattleNpcSubKind, CommonSpawn, DisplayFlag,
EventPlay, EventStart, NpcSpawn, ObjectKind, OnlineStatus, PlayerSpawn, PlayerSubKind,
ServerZoneIpcData, ServerZoneIpcSegment,
},
}, },
}; };
use super::{ZoneConnection, ipc::ChatMessage}; use super::{LuaPlayer, ZoneConnection, ipc::ChatMessage};
pub const CUSTOMIZE_DATA: CustomizeData = CustomizeData { pub const CUSTOMIZE_DATA: CustomizeData = CustomizeData {
race: 4, race: 4,
@ -44,7 +47,11 @@ pub const CUSTOMIZE_DATA: CustomizeData = CustomizeData {
pub struct ChatHandler {} pub struct ChatHandler {}
impl ChatHandler { impl ChatHandler {
pub async fn handle_chat_message(connection: &mut ZoneConnection, chat_message: &ChatMessage) { pub async fn handle_chat_message(
connection: &mut ZoneConnection,
lua_player: &mut LuaPlayer,
chat_message: &ChatMessage,
) {
tracing::info!("Client sent chat message: {}!", chat_message.message); tracing::info!("Client sent chat message: {}!", chat_message.message);
let parts: Vec<&str> = chat_message.message.split(' ').collect(); let parts: Vec<&str> = chat_message.message.split(' ').collect();
@ -322,34 +329,12 @@ impl ChatHandler {
.await; .await;
} }
// play the scene, bart connection.event = Some(Event::new("opening/OpeningUldah.lua"));
{ connection
let ipc = ServerZoneIpcSegment { .event
unk1: 20, .as_mut()
unk2: 0, .unwrap()
op_code: ServerZoneIpcType::EventPlay, .enter_territory(lua_player);
server_id: 0,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::EventPlay(EventPlay {
actor_id: ObjectTypeId {
object_id: ObjectId(connection.player_data.actor_id),
object_type: 0,
},
event_id: 0x130003,
scene: 1,
scene_flags: 4959237,
..Default::default()
}),
};
connection
.send_segment(PacketSegment {
source_actor: connection.player_data.actor_id,
target_actor: connection.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
}
} }
_ => tracing::info!("Unrecognized debug command!"), _ => tracing::info!("Unrecognized debug command!"),
} }

View file

@ -10,7 +10,7 @@ use crate::{
}; };
use super::{ use super::{
Inventory, Item, LuaPlayer, Zone, Event, Inventory, Item, LuaPlayer, Zone,
ipc::{ ipc::{
ActorSetPos, ClientZoneIpcSegment, ContainerInfo, ContainerType, InitZone, ItemInfo, ActorSetPos, ClientZoneIpcSegment, ContainerInfo, ContainerType, InitZone, ItemInfo,
ServerZoneIpcData, ServerZoneIpcSegment, StatusEffect, StatusEffectList, UpdateClassInfo, ServerZoneIpcData, ServerZoneIpcSegment, StatusEffect, StatusEffectList, UpdateClassInfo,
@ -69,6 +69,8 @@ pub struct ZoneConnection {
pub position: Position, pub position: Position,
pub inventory: Inventory, pub inventory: Inventory,
pub status_effects: StatusEffects, pub status_effects: StatusEffects,
pub event: Option<Event>,
} }
impl ZoneConnection { impl ZoneConnection {

52
src/world/event.rs Normal file
View file

@ -0,0 +1,52 @@
use mlua::{Function, Lua};
use crate::config::get_config;
use super::LuaPlayer;
pub struct Event {
lua: Lua,
}
impl Event {
pub fn new(path: &str) -> Self {
let lua = Lua::new();
let config = get_config();
let file_name = format!("{}/{}", &config.world.scripts_location, path);
lua.load(std::fs::read(&file_name).expect("Failed to locate scripts directory!"))
.set_name("@".to_string() + &file_name)
.exec()
.unwrap();
Self { lua }
}
pub fn enter_territory(&mut self, player: &mut LuaPlayer) {
self.lua
.scope(|scope| {
let player = scope.create_userdata_ref_mut(player).unwrap();
let func: Function = self.lua.globals().get("onEnterTerritory").unwrap();
func.call::<()>(player).unwrap();
Ok(())
})
.unwrap();
}
pub fn scene_finished(&mut self, player: &mut LuaPlayer, scene: u16) {
self.lua
.scope(|scope| {
let player = scope.create_userdata_ref_mut(player).unwrap();
let func: Function = self.lua.globals().get("onSceneFinished").unwrap();
func.call::<()>((player, scene)).unwrap();
Ok(())
})
.unwrap();
}
}

View file

@ -337,7 +337,8 @@ pub enum ClientZoneIpcData {
#[br(pre_assert(*magic == ClientZoneIpcType::EventRelatedUnk))] #[br(pre_assert(*magic == ClientZoneIpcType::EventRelatedUnk))]
EventRelatedUnk { EventRelatedUnk {
unk1: u32, unk1: u32,
unk2: u32, unk2: u16,
#[brw(pad_before = 2)]
unk3: u32, unk3: u32,
unk4: u32, unk4: u32,
}, },

View file

@ -1,14 +1,14 @@
use mlua::{UserData, UserDataMethods}; use mlua::{UserData, UserDataMethods};
use crate::{ use crate::{
common::timestamp_secs, common::{ObjectId, ObjectTypeId, timestamp_secs},
opcodes::ServerZoneIpcType, opcodes::ServerZoneIpcType,
packet::{PacketSegment, SegmentType}, packet::{PacketSegment, SegmentType},
}; };
use super::{ use super::{
PlayerData, StatusEffects, PlayerData, StatusEffects,
ipc::{ServerZoneIpcData, ServerZoneIpcSegment}, ipc::{EventPlay, ServerZoneIpcData, ServerZoneIpcSegment},
}; };
#[derive(Default)] #[derive(Default)]
@ -44,6 +44,33 @@ impl LuaPlayer {
fn give_status_effect(&mut self, effect_id: u16, duration: f32) { fn give_status_effect(&mut self, effect_id: u16, duration: f32) {
self.status_effects.add(effect_id, duration); self.status_effects.add(effect_id, duration);
} }
fn play_scene(&mut self, event_id: u32, scene: u16, scene_flags: u32, param: u8) {
let ipc = ServerZoneIpcSegment {
unk1: 20,
unk2: 0,
op_code: ServerZoneIpcType::EventPlay,
server_id: 0,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::EventPlay(EventPlay {
actor_id: ObjectTypeId {
object_id: ObjectId(self.player_data.actor_id),
object_type: 0,
},
event_id,
scene,
scene_flags,
unk2: param,
..Default::default()
}),
};
self.queue_segment(PacketSegment {
source_actor: self.player_data.actor_id,
target_actor: self.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
});
}
} }
impl UserData for LuaPlayer { impl UserData for LuaPlayer {
@ -59,5 +86,12 @@ impl UserData for LuaPlayer {
Ok(()) Ok(())
}, },
); );
methods.add_method_mut(
"play_scene",
|_, this, (event_id, scene, scene_flags, param): (u32, u16, u32, u8)| {
this.play_scene(event_id, scene, scene_flags, param);
Ok(())
},
);
} }
} }

View file

@ -17,3 +17,6 @@ pub use inventory::{EquippedContainer, Inventory, Item};
mod lua; mod lua;
pub use lua::LuaPlayer; pub use lua::LuaPlayer;
mod event;
pub use event::Event;