Update draft
All checks were successful
Deploy / Deploy Website (push) Successful in 33s

This commit is contained in:
Joshua Goins 2025-05-10 09:44:46 -04:00
parent 7d74d4f46d
commit 3ac9bd7d32

View file

@ -1,53 +1,175 @@
---
title: "Kawari Progress Report 10 - Polish"
date: 2025-05-06
date: 2025-05-10
draft: true
tags:
- FFXIV
- Reverse Engineering
series:
- Kawari Progress Report
summary: "meh"
summary: "This update is all about polish and making Kawari easier to setup/use. What's the point of an alternative server that's difficult to setup?"
---
Today's progress report is all about polish! We still have a lot of rough edges, on a UX level but also technically.
Since this is the tenth progress report for Kawari, I think it's time for a re-introduction - in case you missed what this is about. [Kawari] is my alternative server for FFXIV. I
This update is all about polish and making Kawari easier to setup/use. What's the point of an alternative server that's difficult to setup?
# Better Artifacts
I have redone the structure of the artifact ZIP, for example by putting the server binaries in the top-level directory. The original web template files are now included, so they can be freely changed like the game scripts:
I have redone the structure of the artifacts, which was mostly putting the binaries in the top-level directory. The original web template files are now included, so they can be freely changed without recompiling:
[screenshot]
Additionally, there are now working run scripts for Windows and Linux to start all of the Kawari services at once. (Previously you had to manually run each and every executable.) Note that I have _no_ clue how to write Batch scripts, so it ends up doing stupid things like spawning a dozen console windows. If you're a Windows expert and know how to make that better, I would appreciate some help!
Additionally, there are now run scripts (that work!) for Windows and Linux to start all of Kawari's services. I have _no_ clue how to write Batch scripts, so it ends up doing funny things like spawning a dozen console windows. If you're a Windows expert and know how to make that better, I would appreciate some help!
# Better Web
## Better Web
I redone the web interface and slapped on Bootstrap styling until I'm not lazy to do some custom CSS. It looks somewhat nice now:
I redone the web interface and slapped on Bootstrap styling since I'm too lazy to come up with my own CSS. It actually looks decently nice now:
[screenshot]
[screenshot]
# New Config Flags
There are a couple of new config flags, including:
* Turn off outgoing packet compression, useful if your capture tool doesn't support Oodle decompression (and you don't care about what the client sends?)
Thanks to [sfss] for bug testing, and some minor issues with the Web/Launcher pages are now fixed.
# Official Launcher
Kawari can now be used with the official launcher, making it super easy to use. For Windows, this only consists of dragging files and Linux isn't much harder. The setup instructions are located on the internal website:
Kawari can now be used with the official launcher, making it super easy to use. For Windows, this only consists of dragging files into a folder - and Linux isn't that much harder. The setup instructions are located on the internal website:
[screenshot]
Here's how it looks like in the launcher:
And here's how it looks like in the launcher:
[screenshot]
Breaking apart SqEx's launcher honestly has been the most fun in RE I've had in a while...
# Scripting
I have expanded the breadth of things you can script, and I have it working on a variety of things now - such as:
* Inns
* Warps (including ferries, lifts, and exit doors.)
* Beds
* Commands
* Items
Additionally, events used to be hard-coded but can now be added dynamically through Lua:
```lua
registerEvent(721028, "tosort/UnendingJourney.lua")
registerEvent(721044, "tosort/CrystalBell.lua")
```
Note that the event IDs are declared when you register the function, so you can reuse the same script across multiple IDs:
```lua
--- all of these are simple, so they can be handled by the same script!
registerEvent(131082, "common/GenericWarp.lua")
registerEvent(131083, "common/GenericWarp.lua")
registerEvent(131084, "common/GenericWarp.lua")
```
The event ID is injected into the event script as `EVENT_ID`, so scripts can be more generic:
```lua
player:play_scene(target, EVENT_ID, 00000, 8192, 0)
```
And of course a breadth of new, interesting player API to make these events functional:
```lua
--- go to the pre-defined warp (and switch the zone if nessecary)
player:warp(2)
--- stop this event and give control back to the player
player:finish_event(EVENT_ID)
--- set the player's class/job
player:set_classjob(1)
--- set the player's position
player:set_position({ x = 1, y = 2, z = 3 })
--- set the player's remake flag
player:set_remake_mode("EditAppearance")
```
To register new commands, define a new Lua script:
```lua
function onCommand(args, player)
local parts = split(args)
player:set_position({ x = tonumber(parts[1]), y = tonumber(parts[2]), z = tonumber(parts[3]) })
end
```
And then register it in `Global.lua`:
```lua
registerCommand("setpos", "commands/debug/SetPos.lua")
```
I also want to give a reminder that the entire Lua interface is still a big WIP. At some point when it's more complete, I'll give it a complete redo. I didn't want to prematurely design an API that ended up being too limiting, so I'm bolting on new things instead.
# Better Multiplayer
As seen in a previous update, multiplayer "worked" but it was bad. It pretty much only shown the other player's position and their initial appearance. I have greatly improved it, including propagating model id changes, emotes, poses, targeting and more:
I struggled with sending player rotations for a while because they changed the packet used to update actor positions in Endwalker(?) After fixing that, everything fell into place.
s
What's curious is that this means rotations are actually _more_ accurate between clients, and I wondered if that's actually noticeable. So I tested it, "emulating" the old 255-value system and did a comparison:
I also implemented _very basic_ zone isolation, so people won't phase-shift into your view despite being in a totally different place:
s
# Fantasia
Everyone's favorite item/coping mechanism (yes, I really did use the same joke from the commit description) is now implemented, just for funsies. It doesn't remove the Fantasia from your inventory because we lack the Lua API for it:
# Excel Data
This is just a technical tidbit, hence why it's at the end here. Kawari has to read more and more Excel data, and the code usually looks like this:
```rust
/// 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 ExcelRowKind::SingleRow(row) = &exd.get_row(warp_id).unwrap() else {
panic!("Expected a single row!")
};
let physis::exd::ColumnData::UInt32(pop_range_id) = &row.columns[0] else {
panic!("Unexpected type!");
};
let physis::exd::ColumnData::UInt16(zone_id) = &row.columns[1] else {
panic!("Unexpected type!");
};
(*pop_range_id, *zone_id)
}
```
🤢 Yeah, that's bad! We are associating columns with their indexes, and these tend to change over time. We also don't have that great error handling here, so I spent some time cleaning this up. Now it looks like this:
```rust
/// Returns the pop range object id that's associated with the warp id
pub fn get_warp(&mut self, warp_id: u32) -> Option<(u32, u16)> {
let sheet = WarpSheet::read_from(&mut self.game_data, Language::English)?;
let row = sheet.get_row(warp_id)?;
let pop_range_id = row.PopRange().into_u32()?;
let zone_id = row.TerritoryType().into_u16()?;
Some((*pop_range_id, *zone_id))
}
```
Some of this was fixed by improving the signature of the function itself (with `Option`!) Another part of it is introducing a higher-level API for grabbing Excel data. I auto-generate a library called [Icarus](https://github.com/redstrate/Icarus) based on the great schema in [EXDSchema](https://github.com/xivdev/EXDSchema), with [EXDGen](https://github.com/redstrate/EXDGen). While it only supports a small portion of the schema, it's more than enough for Kawari.