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:
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!
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:
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
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
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.