Skip to content

Commit

Permalink
Fix pack identifier and downloading of packs
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeDoctorDE committed Nov 19, 2024
1 parent def433c commit 0cb8006
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 73 deletions.
9 changes: 5 additions & 4 deletions api/lib/src/event/process/server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ bool isValidServerEvent(ServerWorldEvent event, WorldState state) =>
sealed class FatalServerEventError {}

final class InvalidPacksError extends FatalServerEventError {
final List<SignatureMetadata> signature;
final List<SignatureMetadata> signature, expected;

InvalidPacksError({required this.signature});
InvalidPacksError({required this.signature, required this.expected});

@override
String toString() =>
'Server requested packs, that are not available on the client (or is empty): $signature';
'Server requested packs, that are not available on the client (or is empty): $signature, expected: $expected';
}

bool isServerSupported(List<SignatureMetadata> mySignature,
Expand Down Expand Up @@ -93,7 +93,8 @@ ServerProcessed processServerEvent(
? true
: isServerSupported(signature, serverSignature);
if (!supported) {
throw InvalidPacksError(signature: serverSignature);
throw InvalidPacksError(
signature: serverSignature, expected: signature);
}
return ServerProcessed(state.copyWith(
table: event.table ?? state.table,
Expand Down
15 changes: 8 additions & 7 deletions api/lib/src/models/data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,16 @@ const kGameTeamPath = 'teams.json';
const kGameNotesPath = 'notes';

class SetonixData extends ArchiveData<SetonixData> {
SetonixData(super.archive, {super.state});
SetonixData.empty() : super.empty();
final String identifier;

SetonixData(super.archive, {super.state, this.identifier = ''});
SetonixData.empty()
: identifier = '',
super.empty();

factory SetonixData.fromData(Uint8List data) {
return SetonixData(ZipDecoder().decodeBytes(data));
return SetonixData(ZipDecoder().decodeBytes(data),
identifier: createPackIdentifier(data));
}

GameTable? getTable([String name = '']) {
Expand Down Expand Up @@ -203,10 +208,6 @@ class SetonixData extends ArchiveData<SetonixData> {
SetonixData updateState(ArchiveState state) =>
SetonixData(archive, state: state);

String createIdentifier() {
return createPackIdentifier(exportAsBytes());
}

TranslationsStore getTranslationsStore(
{required String Function() getLocale}) =>
TranslationsStore(
Expand Down
5 changes: 2 additions & 3 deletions api/lib/src/services/asset.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ abstract class AssetManager {
Map<String, SignatureMetadata> createSignature([Set<String>? packs]) {
final signature = <String, SignatureMetadata>{};
for (final entry in this.packs) {
final name = entry.key == kCorePackId
? kCorePackId
: entry.value.createIdentifier();
final name =
entry.key == kCorePackId ? kCorePackId : entry.value.identifier;
if (!(packs?.contains(name) ?? true)) continue;
signature[entry.key] = SignatureMetadata(
metadata: entry.value.getMetadataOrDefault(),
Expand Down
69 changes: 32 additions & 37 deletions app/lib/pages/game/error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,25 @@ class _PacksGameErrorViewState extends State<_PacksGameErrorView> {
final List<int> _selectedUrls = [];
final List<int> _excludedPacks = [];
bool _currentlyDownloading = false;
late final List<SignatureMetadata> _packs;

@override
void initState() {
super.initState();
_packs = widget.error.signature
.where((e) => !widget.error.expected.any((f) => f.supports(e)))
.toList();
}

@override
Widget build(BuildContext context) {
final packs = widget.error.signature;
return Column(children: [
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: packs.length,
itemCount: _packs.length,
itemBuilder: (context, index) {
final pack = packs[index];
final pack = _packs[index];
final currentDownloadUrl = pack.downloadUrls
.elementAtOrNull(_selectedUrls.elementAtOrNull(index) ?? 0);
return CheckboxListTile(
Expand Down Expand Up @@ -164,7 +172,7 @@ class _PacksGameErrorViewState extends State<_PacksGameErrorView> {
),
Wrap(
children: [
if (packs.any((e) => e.downloadUrls.isNotEmpty))
if (_packs.any((e) => e.downloadUrls.isNotEmpty))
FilledButton(
onPressed: _currentlyDownloading ? null : _download,
child: Text(
Expand All @@ -179,13 +187,12 @@ class _PacksGameErrorViewState extends State<_PacksGameErrorView> {
}

void _download() async {
final packs = widget.error.signature;
final context = this.context;
setState(() {
_currentlyDownloading = true;
});
final fileSystem = context.read<SetonixFileSystem>();
final fetched = packs
final fetched = _packs
.asMap()
.entries
.where((e) =>
Expand Down Expand Up @@ -230,15 +237,12 @@ class _PacksGameErrorViewState extends State<_PacksGameErrorView> {
} else {
// Combine packs with result
final failed = fetched
.where((e) {
final result = results[e.key];
return result != PackDownloadResult.success;
})
.map((e) => (
.mapIndexed((i, e) => (
metadata: e.value.metadata,
id: e.value.id,
result: results[e.key],
result: results[i],
))
.where((e) => e.result != PackDownloadResult.success)
.toList();
showDialog(
context: context,
Expand All @@ -251,37 +255,28 @@ class _PacksGameErrorViewState extends State<_PacksGameErrorView> {
Text(
AppLocalizations.of(context).downloadFailedMessage,
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: failed.length,
itemBuilder: (context, index) {
final details = failed[index];
return ListTile(
title: Text('${details.metadata.name} (${details.id})'),
subtitle: Text(
switch (details.result) {
PackDownloadResult.invalidUri =>
AppLocalizations.of(context).invalidUri,
PackDownloadResult.downloadFailed =>
AppLocalizations.of(context).downloadFailed,
PackDownloadResult.invalidIdentifier =>
AppLocalizations.of(context).invalidIdentifier,
_ => '',
},
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
);
},
)
const SizedBox(height: 8),
for (final details in failed)
ListTile(
title: Text('${details.metadata.name} (${details.id})'),
subtitle: Text(
switch (details.result) {
PackDownloadResult.invalidUri =>
AppLocalizations.of(context).invalidUri,
PackDownloadResult.downloadFailed =>
AppLocalizations.of(context).downloadFailed,
PackDownloadResult.invalidIdentifier =>
AppLocalizations.of(context).invalidIdentifier,
_ => '',
},
),
)
],
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
GoRouter.of(context).go('/');
},
child: Text(AppLocalizations.of(context).close),
),
Expand Down
42 changes: 23 additions & 19 deletions app/lib/services/file_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -121,26 +121,30 @@ class SetonixFileSystem {

Future<PackDownloadResult> downloadPack(String url, String expectedIdentifier,
{bool force = false}) async {
final uri = Uri.tryParse(url);
if (uri == null) return PackDownloadResult.invalidUri;
if (!force && await packSystem.hasKey(expectedIdentifier)) {
return PackDownloadResult.alreadyExists;
try {
final uri = Uri.tryParse(url);
if (uri == null) return PackDownloadResult.invalidUri;
if (!force && await packSystem.hasKey(expectedIdentifier)) {
return PackDownloadResult.alreadyExists;
}
final response = await http.get(uri);
if (response.statusCode != 200) return PackDownloadResult.downloadFailed;
final identifier = createPackIdentifier(response.bodyBytes);
if (identifier != expectedIdentifier) {
return PackDownloadResult.invalidIdentifier;
}
final pack = SetonixData.fromData(response.bodyBytes);
await packSystem.updateFile(expectedIdentifier, pack);
await dataInfoSystem.updateFile(
expectedIdentifier,
DataMetadata(
addedAt: DateTime.now(),
manuallyAdded: false,
));
return PackDownloadResult.success;
} catch (e) {
return PackDownloadResult.downloadFailed;
}
final response = await http.get(uri);
if (response.statusCode != 200) return PackDownloadResult.downloadFailed;
final identifier = createPackIdentifier(response.bodyBytes);
if (identifier != expectedIdentifier) {
return PackDownloadResult.invalidIdentifier;
}
final pack = SetonixData.fromData(response.bodyBytes);
await packSystem.updateFile(expectedIdentifier, pack);
await dataInfoSystem.updateFile(
expectedIdentifier,
DataMetadata(
addedAt: DateTime.now(),
manuallyAdded: false,
));
return PackDownloadResult.success;
}

Future<void> updateServerLastUsed(String packId, String serverAddress) async {
Expand Down
4 changes: 2 additions & 2 deletions server/lib/src/asset.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,6 @@ class ServerAssetManager extends AssetManager {
@override
List<String>? getDownloadUrls(String id) => _metadata[id]?.downloadUrls;

Iterable<String> getPackIds() => _packs.entries.map(
(e) => e.key == kCorePackId ? kCorePackId : e.value.createIdentifier());
Iterable<String> getPackIds() => _packs.entries
.map((e) => e.key == kCorePackId ? kCorePackId : e.value.identifier);
}
2 changes: 1 addition & 1 deletion server/lib/src/programs/packs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class PacksProgram extends ConsoleProgram {
final packs = server.assetManager.packs.toList();
print("Loaded ${packs.length} pack(s).");
for (final pack in packs) {
final checksum = pack.value.createIdentifier();
final checksum = pack.value.identifier;
if (pack.key == kCorePackId) {
print("| Core pack ($checksum)");
} else {
Expand Down

0 comments on commit 0cb8006

Please sign in to comment.