2025-05-05 22:28:45 -04:00
|
|
|
use mlua::{FromLua, Lua, LuaSerdeExt, UserData, UserDataFields, UserDataMethods, Value};
|
2025-03-28 00:26:31 -04:00
|
|
|
|
|
|
|
use crate::{
|
2025-06-18 19:38:00 -04:00
|
|
|
common::{
|
|
|
|
ObjectId, ObjectTypeId, Position, timestamp_secs, workdefinitions::RemakeMode,
|
|
|
|
write_quantized_rotation,
|
|
|
|
},
|
2025-06-21 12:16:27 -04:00
|
|
|
config::get_config,
|
2025-05-02 00:47:11 -04:00
|
|
|
ipc::zone::{
|
2025-06-19 16:01:16 -04:00
|
|
|
ActionEffect, ActorControlCategory, ActorControlSelf, DamageElement, DamageKind,
|
|
|
|
DamageType, EffectKind, EventScene, ServerZoneIpcData, ServerZoneIpcSegment, Warp,
|
2025-03-30 10:01:41 -04:00
|
|
|
},
|
2025-05-02 00:47:11 -04:00
|
|
|
opcodes::ServerZoneIpcType,
|
|
|
|
packet::{PacketSegment, SegmentData, SegmentType},
|
2025-06-21 12:16:27 -04:00
|
|
|
world::ExtraLuaState,
|
2025-03-28 00:26:31 -04:00
|
|
|
};
|
|
|
|
|
2025-05-11 10:12:02 -04:00
|
|
|
use super::{PlayerData, StatusEffects, Zone, connection::TeleportQuery};
|
2025-05-02 00:47:11 -04:00
|
|
|
|
2025-05-02 15:36:22 -04:00
|
|
|
pub enum Task {
|
|
|
|
ChangeTerritory { zone_id: u16 },
|
|
|
|
SetRemakeMode(RemakeMode),
|
2025-05-05 22:04:39 -04:00
|
|
|
Warp { warp_id: u32 },
|
2025-05-05 23:04:53 -04:00
|
|
|
BeginLogOut,
|
|
|
|
FinishEvent { handler_id: u32 },
|
2025-05-06 22:03:31 -04:00
|
|
|
SetClassJob { classjob_id: u8 },
|
2025-05-11 10:12:02 -04:00
|
|
|
WarpAetheryte { aetheryte_id: u32 },
|
2025-06-21 12:16:27 -04:00
|
|
|
ReloadScripts,
|
2025-06-21 13:30:52 -04:00
|
|
|
ToggleInvisibility { invisible: bool },
|
2025-06-27 23:01:00 -04:00
|
|
|
Unlock { id: u32 },
|
2025-06-27 23:24:30 -04:00
|
|
|
UnlockAetheryte { id: u32, on: bool },
|
2025-03-28 23:43:27 -04:00
|
|
|
}
|
|
|
|
|
2025-03-28 00:26:31 -04:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct LuaPlayer {
|
|
|
|
pub player_data: PlayerData,
|
|
|
|
pub status_effects: StatusEffects,
|
|
|
|
pub queued_segments: Vec<PacketSegment<ServerZoneIpcSegment>>,
|
2025-05-02 15:36:22 -04:00
|
|
|
pub queued_tasks: Vec<Task>,
|
2025-03-28 00:26:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl LuaPlayer {
|
|
|
|
fn queue_segment(&mut self, segment: PacketSegment<ServerZoneIpcSegment>) {
|
|
|
|
self.queued_segments.push(segment);
|
|
|
|
}
|
|
|
|
|
2025-06-19 16:01:16 -04:00
|
|
|
fn create_segment_target(
|
|
|
|
&mut self,
|
|
|
|
op_code: ServerZoneIpcType,
|
|
|
|
data: ServerZoneIpcData,
|
|
|
|
source_actor: u32,
|
|
|
|
target_actor: u32,
|
|
|
|
) {
|
2025-03-28 00:26:31 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
2025-06-19 07:19:28 -04:00
|
|
|
op_code,
|
2025-03-28 00:26:31 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-06-19 07:19:28 -04:00
|
|
|
data,
|
2025-03-28 00:26:31 -04:00
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
self.queue_segment(PacketSegment {
|
2025-06-19 07:19:28 -04:00
|
|
|
source_actor,
|
|
|
|
target_actor,
|
2025-05-02 00:03:36 -04:00
|
|
|
segment_type: SegmentType::Ipc,
|
|
|
|
data: SegmentData::Ipc { data: ipc },
|
2025-03-28 00:26:31 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2025-06-19 07:19:28 -04:00
|
|
|
fn create_segment_self(&mut self, op_code: ServerZoneIpcType, data: ServerZoneIpcData) {
|
2025-06-19 16:01:16 -04:00
|
|
|
self.create_segment_target(
|
|
|
|
op_code,
|
|
|
|
data,
|
|
|
|
self.player_data.actor_id,
|
|
|
|
self.player_data.actor_id,
|
|
|
|
);
|
2025-06-19 07:19:28 -04:00
|
|
|
}
|
|
|
|
|
2025-06-25 10:05:34 -04:00
|
|
|
fn send_message(&mut self, message: &str, param: u8) {
|
2025-06-19 07:19:28 -04:00
|
|
|
let op_code = ServerZoneIpcType::ServerChatMessage;
|
|
|
|
let data = ServerZoneIpcData::ServerChatMessage {
|
|
|
|
message: message.to_string(),
|
2025-06-25 10:05:34 -04:00
|
|
|
param,
|
2025-06-19 07:19:28 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
self.create_segment_self(op_code, data);
|
|
|
|
}
|
|
|
|
|
2025-03-28 00:26:31 -04:00
|
|
|
fn give_status_effect(&mut self, effect_id: u16, duration: f32) {
|
|
|
|
self.status_effects.add(effect_id, duration);
|
|
|
|
}
|
2025-03-28 21:28:30 -04:00
|
|
|
|
2025-05-05 20:51:49 -04:00
|
|
|
fn play_scene(
|
|
|
|
&mut self,
|
2025-05-05 21:15:03 -04:00
|
|
|
target: ObjectTypeId,
|
2025-05-05 20:51:49 -04:00
|
|
|
event_id: u32,
|
|
|
|
scene: u16,
|
|
|
|
scene_flags: u32,
|
2025-06-27 20:42:23 -04:00
|
|
|
params_count: u8,
|
|
|
|
params: [u32; 2],
|
2025-05-05 20:51:49 -04:00
|
|
|
) {
|
2025-06-19 07:19:28 -04:00
|
|
|
let op_code = ServerZoneIpcType::EventScene;
|
|
|
|
let data = ServerZoneIpcData::EventScene(EventScene {
|
|
|
|
actor_id: target,
|
|
|
|
event_id,
|
|
|
|
scene,
|
|
|
|
scene_flags,
|
2025-06-27 20:42:23 -04:00
|
|
|
params_count,
|
|
|
|
params,
|
2025-05-02 23:38:44 -04:00
|
|
|
..Default::default()
|
2025-03-28 21:28:30 -04:00
|
|
|
});
|
2025-06-19 07:19:28 -04:00
|
|
|
|
|
|
|
self.create_segment_self(op_code, data);
|
2025-03-28 21:28:30 -04:00
|
|
|
}
|
2025-03-28 22:34:34 -04:00
|
|
|
|
2025-06-18 10:35:11 -04:00
|
|
|
fn set_position(&mut self, position: Position, rotation: f32) {
|
2025-06-19 07:19:28 -04:00
|
|
|
let op_code = ServerZoneIpcType::Warp;
|
|
|
|
let data = ServerZoneIpcData::Warp(Warp {
|
|
|
|
dir: write_quantized_rotation(&rotation),
|
|
|
|
position,
|
2025-03-28 22:34:34 -04:00
|
|
|
..Default::default()
|
|
|
|
});
|
2025-06-19 07:19:28 -04:00
|
|
|
|
|
|
|
self.create_segment_self(op_code, data);
|
2025-03-28 22:34:34 -04:00
|
|
|
}
|
2025-03-28 23:43:27 -04:00
|
|
|
|
2025-06-19 12:29:10 -04:00
|
|
|
fn set_festival(&mut self, festival1: u32, festival2: u32, festival3: u32, festival4: u32) {
|
|
|
|
let op_code = ServerZoneIpcType::ActorControlSelf;
|
|
|
|
let data = ServerZoneIpcData::ActorControlSelf(ActorControlSelf {
|
|
|
|
category: ActorControlCategory::SetFestival {
|
|
|
|
festival1,
|
|
|
|
festival2,
|
|
|
|
festival3,
|
2025-06-19 16:01:16 -04:00
|
|
|
festival4,
|
2025-06-19 12:29:10 -04:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
self.create_segment_self(op_code, data);
|
|
|
|
}
|
|
|
|
|
2025-06-27 23:01:00 -04:00
|
|
|
fn unlock(&mut self, id: u32) {
|
|
|
|
self.queued_tasks.push(Task::Unlock { id });
|
2025-06-21 13:30:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_speed(&mut self, speed: u16) {
|
|
|
|
let op_code = ServerZoneIpcType::ActorControlSelf;
|
|
|
|
let data = ServerZoneIpcData::ActorControlSelf(ActorControlSelf {
|
|
|
|
category: ActorControlCategory::Flee { speed },
|
|
|
|
});
|
|
|
|
|
|
|
|
self.create_segment_self(op_code, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn toggle_wireframe(&mut self) {
|
|
|
|
let op_code = ServerZoneIpcType::ActorControlSelf;
|
|
|
|
let data = ServerZoneIpcData::ActorControlSelf(ActorControlSelf {
|
|
|
|
category: ActorControlCategory::ToggleWireframeRendering(),
|
|
|
|
});
|
|
|
|
|
|
|
|
self.create_segment_self(op_code, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn unlock_aetheryte(&mut self, unlocked: u32, id: u32) {
|
2025-06-27 23:24:30 -04:00
|
|
|
self.queued_tasks.push(Task::UnlockAetheryte {
|
|
|
|
id,
|
|
|
|
on: unlocked == 1,
|
|
|
|
});
|
2025-06-21 13:30:52 -04:00
|
|
|
}
|
|
|
|
|
2025-03-28 23:43:27 -04:00
|
|
|
fn change_territory(&mut self, zone_id: u16) {
|
2025-05-02 15:36:22 -04:00
|
|
|
self.queued_tasks.push(Task::ChangeTerritory { zone_id });
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_remake_mode(&mut self, mode: RemakeMode) {
|
|
|
|
self.queued_tasks.push(Task::SetRemakeMode(mode));
|
2025-03-28 23:43:27 -04:00
|
|
|
}
|
2025-05-05 22:04:39 -04:00
|
|
|
|
|
|
|
fn warp(&mut self, warp_id: u32) {
|
|
|
|
self.queued_tasks.push(Task::Warp { warp_id });
|
|
|
|
}
|
2025-05-05 23:04:53 -04:00
|
|
|
|
|
|
|
fn begin_log_out(&mut self) {
|
|
|
|
self.queued_tasks.push(Task::BeginLogOut);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn finish_event(&mut self, handler_id: u32) {
|
|
|
|
self.queued_tasks.push(Task::FinishEvent { handler_id });
|
|
|
|
}
|
2025-05-06 22:03:31 -04:00
|
|
|
|
|
|
|
fn set_classjob(&mut self, classjob_id: u8) {
|
|
|
|
self.queued_tasks.push(Task::SetClassJob { classjob_id });
|
|
|
|
}
|
2025-05-11 10:12:02 -04:00
|
|
|
|
|
|
|
fn warp_aetheryte(&mut self, aetheryte_id: u32) {
|
|
|
|
self.queued_tasks.push(Task::WarpAetheryte { aetheryte_id });
|
|
|
|
}
|
2025-06-21 12:16:27 -04:00
|
|
|
|
|
|
|
fn reload_scripts(&mut self) {
|
|
|
|
self.queued_tasks.push(Task::ReloadScripts);
|
|
|
|
}
|
2025-06-21 13:30:52 -04:00
|
|
|
fn toggle_invisiblity(&mut self) {
|
|
|
|
self.queued_tasks.push(Task::ToggleInvisibility {
|
|
|
|
invisible: !self.player_data.gm_invisible,
|
|
|
|
});
|
|
|
|
}
|
2025-03-28 00:26:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl UserData for LuaPlayer {
|
|
|
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
2025-06-25 17:02:19 -04:00
|
|
|
methods.add_method_mut(
|
|
|
|
"send_message",
|
|
|
|
|lua, this, (message, param): (String, Value)| {
|
|
|
|
let param: u8 = lua.from_value(param).unwrap_or(0);
|
|
|
|
this.send_message(&message, param);
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
);
|
2025-03-28 00:26:31 -04:00
|
|
|
methods.add_method_mut(
|
|
|
|
"give_status_effect",
|
|
|
|
|_, this, (effect_id, duration): (u16, f32)| {
|
|
|
|
this.give_status_effect(effect_id, duration);
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
);
|
2025-03-28 21:28:30 -04:00
|
|
|
methods.add_method_mut(
|
|
|
|
"play_scene",
|
2025-06-27 20:42:23 -04:00
|
|
|
|_,
|
|
|
|
this,
|
|
|
|
(target, event_id, scene, scene_flags, params): (
|
|
|
|
ObjectTypeId,
|
|
|
|
u32,
|
|
|
|
u16,
|
|
|
|
u32,
|
|
|
|
Vec<u32>,
|
|
|
|
)| {
|
|
|
|
let params_arr: [u32; 2];
|
|
|
|
if params.len() == 2 {
|
|
|
|
params_arr = [params[0], params[1]];
|
|
|
|
} else if params.len() == 1 {
|
|
|
|
params_arr = [params[0], 0];
|
|
|
|
} else {
|
|
|
|
this.finish_event(event_id);
|
|
|
|
let message = "Script params are invalid, it contains either more than 2 parameters or no parameters at all!";
|
|
|
|
tracing::error!(message);
|
|
|
|
this.send_message(message, 0);
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
this.play_scene(target, event_id, scene, scene_flags, params.len() as u8, params_arr);
|
|
|
|
return Ok(());
|
2025-03-28 21:28:30 -04:00
|
|
|
},
|
|
|
|
);
|
2025-06-18 19:38:00 -04:00
|
|
|
methods.add_method_mut(
|
|
|
|
"set_position",
|
|
|
|
|lua, this, (position, rotation): (Value, Value)| {
|
|
|
|
let position: Position = lua.from_value(position).unwrap();
|
|
|
|
let rotation: f32 = lua.from_value(rotation).unwrap();
|
|
|
|
this.set_position(position, rotation);
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
);
|
2025-06-19 12:29:10 -04:00
|
|
|
methods.add_method_mut(
|
|
|
|
"set_festival",
|
|
|
|
|_, this, (festival1, festival2, festival3, festival4): (u32, u32, u32, u32)| {
|
|
|
|
this.set_festival(festival1, festival2, festival3, festival4);
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
);
|
2025-06-21 13:30:52 -04:00
|
|
|
methods.add_method_mut("unlock_aetheryte", |_, this, (unlock, id): (u32, u32)| {
|
|
|
|
this.unlock_aetheryte(unlock, id);
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-06-27 23:01:00 -04:00
|
|
|
methods.add_method_mut("unlock", |_, this, action_id: u32| {
|
|
|
|
this.unlock(action_id);
|
2025-06-21 13:30:52 -04:00
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
methods.add_method_mut("set_speed", |_, this, speed: u16| {
|
|
|
|
this.set_speed(speed);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
methods.add_method_mut("toggle_wireframe", |_, this, _: Value| {
|
|
|
|
this.toggle_wireframe();
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
methods.add_method_mut("toggle_invisibility", |_, this, _: Value| {
|
|
|
|
this.toggle_invisiblity();
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-03-28 23:43:27 -04:00
|
|
|
methods.add_method_mut("change_territory", |_, this, zone_id: u16| {
|
|
|
|
this.change_territory(zone_id);
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-05-02 15:36:22 -04:00
|
|
|
methods.add_method_mut("set_remake_mode", |lua, this, mode: Value| {
|
|
|
|
let mode: RemakeMode = lua.from_value(mode).unwrap();
|
|
|
|
this.set_remake_mode(mode);
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-05-05 22:04:39 -04:00
|
|
|
methods.add_method_mut("warp", |_, this, warp_id: u32| {
|
|
|
|
this.warp(warp_id);
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-05-05 23:04:53 -04:00
|
|
|
methods.add_method_mut("begin_log_out", |_, this, _: ()| {
|
|
|
|
this.begin_log_out();
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
methods.add_method_mut("finish_event", |_, this, handler_id: u32| {
|
|
|
|
this.finish_event(handler_id);
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-05-06 22:03:31 -04:00
|
|
|
methods.add_method_mut("set_classjob", |_, this, classjob_id: u8| {
|
|
|
|
this.set_classjob(classjob_id);
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-05-11 10:12:02 -04:00
|
|
|
methods.add_method_mut("warp_aetheryte", |_, this, aetheryte_id: u32| {
|
|
|
|
this.warp_aetheryte(aetheryte_id);
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-06-21 12:16:27 -04:00
|
|
|
methods.add_method_mut("reload_scripts", |_, this, _: ()| {
|
|
|
|
this.reload_scripts();
|
|
|
|
Ok(())
|
|
|
|
});
|
2025-03-28 22:34:34 -04:00
|
|
|
}
|
2025-05-05 22:28:45 -04:00
|
|
|
|
|
|
|
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
|
|
|
fields.add_field_method_get("id", |_, this| {
|
|
|
|
Ok(ObjectTypeId {
|
|
|
|
object_id: ObjectId(this.player_data.actor_id),
|
|
|
|
object_type: 0,
|
|
|
|
})
|
|
|
|
});
|
2025-05-11 10:12:02 -04:00
|
|
|
|
|
|
|
fields.add_field_method_get("teleport_query", |_, this| {
|
|
|
|
Ok(this.player_data.teleport_query.clone())
|
|
|
|
});
|
2025-06-18 19:38:00 -04:00
|
|
|
fields.add_field_method_get("rotation", |_, this| Ok(this.player_data.rotation));
|
|
|
|
fields.add_field_method_get("position", |_, this| Ok(this.player_data.position));
|
2025-05-11 10:12:02 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UserData for TeleportQuery {
|
|
|
|
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
|
|
|
fields.add_field_method_get("aetheryte_id", |_, this| Ok(this.aetheryte_id));
|
2025-05-05 22:28:45 -04:00
|
|
|
}
|
2025-03-28 22:34:34 -04:00
|
|
|
}
|
|
|
|
|
2025-06-18 10:35:11 -04:00
|
|
|
impl UserData for Position {
|
|
|
|
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
|
|
|
fields.add_field_method_get("x", |_, this| Ok(this.x));
|
|
|
|
fields.add_field_method_get("y", |_, this| Ok(this.y));
|
|
|
|
fields.add_field_method_get("z", |_, this| Ok(this.z));
|
|
|
|
}
|
|
|
|
}
|
2025-03-28 22:34:34 -04:00
|
|
|
|
2025-05-05 21:15:03 -04:00
|
|
|
impl UserData for ObjectTypeId {}
|
|
|
|
|
|
|
|
impl FromLua for ObjectTypeId {
|
|
|
|
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
2025-03-28 22:34:34 -04:00
|
|
|
match value {
|
|
|
|
Value::UserData(ud) => Ok(*ud.borrow::<Self>()?),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UserData for Zone {
|
|
|
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
|
|
|
methods.add_method(
|
|
|
|
"get_pop_range",
|
2025-03-29 08:34:55 -04:00
|
|
|
|lua: &Lua, this, id: u32| -> mlua::Result<mlua::Value> {
|
2025-03-28 22:34:34 -04:00
|
|
|
if let Some(pop_range) = this.find_pop_range(id) {
|
|
|
|
let trans = pop_range.0.transform.translation;
|
2025-03-29 08:34:55 -04:00
|
|
|
return lua.pack(Position {
|
2025-03-28 22:34:34 -04:00
|
|
|
x: trans[0],
|
|
|
|
y: trans[1],
|
|
|
|
z: trans[2],
|
|
|
|
});
|
2025-05-12 16:32:55 -04:00
|
|
|
} else {
|
|
|
|
tracing::warn!("Failed to find pop range for {id}!");
|
2025-03-28 22:34:34 -04:00
|
|
|
}
|
2025-03-29 08:34:55 -04:00
|
|
|
Ok(mlua::Nil)
|
2025-03-28 22:34:34 -04:00
|
|
|
},
|
|
|
|
);
|
2025-03-28 00:26:31 -04:00
|
|
|
}
|
|
|
|
}
|
2025-03-30 09:29:36 -04:00
|
|
|
|
|
|
|
#[derive(Clone, Debug, Default)]
|
|
|
|
pub struct EffectsBuilder {
|
|
|
|
pub effects: Vec<ActionEffect>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UserData for EffectsBuilder {
|
|
|
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
2025-04-18 14:32:39 -04:00
|
|
|
methods.add_method_mut("damage", |lua, this, (damage_kind, damage_type, damage_element, amount): (Value, Value, Value, u16)| {
|
|
|
|
let damage_kind: DamageKind = lua.from_value(damage_kind).unwrap();
|
|
|
|
let damage_type: DamageType = lua.from_value(damage_type).unwrap();
|
|
|
|
let damage_element: DamageElement = lua.from_value(damage_element).unwrap();
|
|
|
|
|
2025-03-30 09:29:36 -04:00
|
|
|
this.effects.push(ActionEffect {
|
2025-04-18 13:11:29 -04:00
|
|
|
kind: EffectKind::Damage {
|
2025-04-18 14:32:39 -04:00
|
|
|
damage_kind,
|
|
|
|
damage_type,
|
|
|
|
damage_element,
|
2025-04-18 13:11:29 -04:00
|
|
|
bonus_percent: 0,
|
|
|
|
unk3: 0,
|
|
|
|
unk4: 0,
|
|
|
|
amount,
|
|
|
|
},
|
2025-03-30 09:29:36 -04:00
|
|
|
});
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromLua for EffectsBuilder {
|
|
|
|
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
|
|
|
match value {
|
|
|
|
Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2025-06-21 12:16:27 -04:00
|
|
|
|
2025-06-25 13:25:48 -04:00
|
|
|
/// Loads `Init.lua`
|
|
|
|
pub fn load_init_script(lua: &mut Lua) -> mlua::Result<()> {
|
2025-06-22 08:19:42 -04:00
|
|
|
let register_action_func =
|
|
|
|
lua.create_function(|lua, (action_id, action_script): (u32, String)| {
|
2025-06-21 12:16:27 -04:00
|
|
|
let mut state = lua.app_data_mut::<ExtraLuaState>().unwrap();
|
|
|
|
let _ = state.action_scripts.insert(action_id, action_script);
|
|
|
|
Ok(())
|
2025-06-22 08:19:42 -04:00
|
|
|
})?;
|
2025-06-21 12:16:27 -04:00
|
|
|
|
2025-06-22 08:19:42 -04:00
|
|
|
let register_event_func =
|
|
|
|
lua.create_function(|lua, (event_id, event_script): (u32, String)| {
|
2025-06-21 12:16:27 -04:00
|
|
|
let mut state = lua.app_data_mut::<ExtraLuaState>().unwrap();
|
|
|
|
let _ = state.event_scripts.insert(event_id, event_script);
|
|
|
|
Ok(())
|
2025-06-22 08:19:42 -04:00
|
|
|
})?;
|
2025-06-21 12:16:27 -04:00
|
|
|
|
2025-06-22 08:19:42 -04:00
|
|
|
let register_command_func =
|
|
|
|
lua.create_function(|lua, (command_name, command_script): (String, String)| {
|
2025-06-21 12:16:27 -04:00
|
|
|
let mut state = lua.app_data_mut::<ExtraLuaState>().unwrap();
|
|
|
|
let _ = state.command_scripts.insert(command_name, command_script);
|
|
|
|
Ok(())
|
2025-06-22 08:19:42 -04:00
|
|
|
})?;
|
2025-06-21 12:16:27 -04:00
|
|
|
|
|
|
|
lua.set_app_data(ExtraLuaState::default());
|
2025-06-22 08:19:42 -04:00
|
|
|
lua.globals().set("registerAction", register_action_func)?;
|
|
|
|
lua.globals().set("registerEvent", register_event_func)?;
|
2025-06-21 12:16:27 -04:00
|
|
|
lua.globals()
|
2025-06-22 08:19:42 -04:00
|
|
|
.set("registerCommand", register_command_func)?;
|
2025-06-21 12:16:27 -04:00
|
|
|
|
2025-06-22 08:19:42 -04:00
|
|
|
let effectsbuilder_constructor = lua.create_function(|_, ()| Ok(EffectsBuilder::default()))?;
|
2025-06-21 12:16:27 -04:00
|
|
|
lua.globals()
|
2025-06-22 08:19:42 -04:00
|
|
|
.set("EffectsBuilder", effectsbuilder_constructor)?;
|
2025-06-21 12:16:27 -04:00
|
|
|
|
|
|
|
let config = get_config();
|
2025-06-25 13:25:48 -04:00
|
|
|
let file_name = format!("{}/Init.lua", &config.world.scripts_location);
|
2025-06-21 12:16:27 -04:00
|
|
|
lua.load(std::fs::read(&file_name).expect("Failed to locate scripts directory!"))
|
|
|
|
.set_name("@".to_string() + &file_name)
|
2025-06-22 08:19:42 -04:00
|
|
|
.exec()?;
|
|
|
|
|
|
|
|
Ok(())
|
2025-06-21 12:16:27 -04:00
|
|
|
}
|