Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.2.0 #62

Merged
merged 13 commits into from
Jun 4, 2024
Merged
10 changes: 7 additions & 3 deletions lib/arc/arc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,16 @@ class Arc {
continue;
}

log('File name: $fileName');
if (fileName != null && fileName != '(signature)' && fileName != '(listfile)' && fileName != '(attributes)') {
if (fileName != '(signature)' && fileName != '(listfile)' && fileName != '(attributes)') {
files.add(fileName);
if(onFile != null) {
final file = mpqArchive.openFileEx(fileName, 0);
await onFile(fileName, file.read(file.size()));
try {
final size = file.size();
await onFile(fileName, file.read(size));
} catch (e) {
log('Skipping file $fileName: $e');
}
}
}
} on StormLibException catch (e) {
Expand Down
7 changes: 7 additions & 0 deletions lib/context.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class RetroContext {
static const String versionName = '0.2.0';
static const int versionCode = 0;
static const String branch = 'main';
static const String commitHash = '66e4c03';
KiritoDv marked this conversation as resolved.
Show resolved Hide resolved
static const String commitDate = '2024-06-03';
}
137 changes: 75 additions & 62 deletions lib/features/create/create_custom/create_custom_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,72 +26,85 @@ class _CreateCustomScreenState extends State<CreateCustomScreen> {
Widget build(BuildContext context) {
final theme = Theme.of(context);
final textTheme = theme.textTheme;
final viewModel =
Provider.of<CreateCustomViewModel>(context);
final finishViewModel =
Provider.of<CreateFinishViewModel>(context);
final viewModel = Provider.of<CreateCustomViewModel>(context);
final finishViewModel = Provider.of<CreateFinishViewModel>(context);
final i18n = AppLocalizations.of(context)!;

return CustomScaffold(
title: i18n.createCustomScreen_title,
subtitle: i18n.createCustomScreen_subtitle,
onBackButtonPressed: () {
viewModel.reset();
Navigator.of(context).pop();
},
content: Expanded(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: OutlinedButton(
onPressed: viewModel.onSelectFiles,
style: ElevatedButton.styleFrom(
minimumSize: const Size(200, 50),),
child:
Text(i18n.createCustomScreen_selectButton),),
),
Text(viewModel.path),
],
),
Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
'${i18n.createCustomScreen_fileToInsert}${viewModel.files.length}',
style: textTheme.titleMedium,
),
title: i18n.createCustomScreen_title,
subtitle: i18n.createCustomScreen_subtitle,
onBackButtonPressed: () {
viewModel.reset();
Navigator.of(context).pop();
},
content: Expanded(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: OutlinedButton(
onPressed: viewModel.onSelectFiles,
style: ElevatedButton.styleFrom(
minimumSize: const Size(200, 50),
),
child: Text(i18n.createCustomScreen_selectButton),
),
Expanded(
child: ListView.builder(
itemCount: viewModel.files.length,
itemBuilder: (context, index) {
return Text(p.relative(
viewModel.files[index].path,
from: viewModel.path,),);
},),),
ElevatedButton(
onPressed: viewModel.files.isNotEmpty &&
viewModel.path.isNotEmpty
? () {
finishViewModel.onAddCustomStageEntries(
viewModel.files, viewModel.path,);
viewModel.reset();
Navigator.of(context).popUntil(
ModalRoute.withName('/create_selection'),);
}
: null,
style: ElevatedButton.styleFrom(
minimumSize: Size(
MediaQuery.of(context).size.width * 0.5, 50,),),
child: Text(i18n.createCustomScreen_stageFiles),),
],
),),),);
),
Text(viewModel.path),
],
),
Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
'${i18n.createCustomScreen_fileToInsert}${viewModel.files.length}',
style: textTheme.titleMedium,
),
),
),
Expanded(
child: ListView.builder(
itemCount: viewModel.files.length,
itemBuilder: (context, index) {
return Text(
p.relative(
viewModel.files[index].path,
from: viewModel.path,
),
);
},
),
),
ElevatedButton(
onPressed: viewModel.files.isNotEmpty && viewModel.path.isNotEmpty
? () {
finishViewModel.onAddCustomStageEntries(
viewModel.files,
viewModel.path,
);
viewModel.reset();
Navigator.of(context).popUntil(
ModalRoute.withName('/create_selection'),
);
}
: null,
style: ElevatedButton.styleFrom(
minimumSize: Size(
MediaQuery.of(context).size.width * 0.5,
50,
),
),
child: Text(i18n.createCustomScreen_stageFiles),
),
],
),
),
),
);
}
}
17 changes: 12 additions & 5 deletions lib/features/create/create_finish/create_finish_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,13 @@ class CreateFinishViewModel with ChangeNotifier {
notifyListeners();
}

onAddCustomTextureEntry(
void onAddCustomTextureEntry(
HashMap<String, List<Tuple2<File, TextureManifestEntry>>> replacementMap,
) {
for (final entry in replacementMap.entries) {
if (entries.containsKey(entry.key) &&
entries[entry.key] is CustomTexturesEntry) {
(entries[entry.key] as CustomTexturesEntry).pairs.addAll(entry.value);
(entries[entry.key]! as CustomTexturesEntry).pairs.addAll(entry.value);
} else if (entries.containsKey(entry.key)) {
throw Exception('Cannot add custom texture entry to existing entry');
} else {
Expand All @@ -124,18 +124,25 @@ class CreateFinishViewModel with ChangeNotifier {
notifyListeners();
}

void onAddFile(File file, String path) {
entries[path] = CustomStageEntry([file]);
totalFiles++;
currentState = AppState.changesStaged;
notifyListeners();
}

void onRemoveFile(File file, String path) {
if (entries.containsKey(path) && entries[path] is CustomStageEntry) {
(entries[path] as CustomStageEntry).files.remove(file);
(entries[path]! as CustomStageEntry).files.remove(file);
} else if (entries.containsKey(path) &&
entries[path] is CustomSequencesEntry) {
(entries[path] as CustomSequencesEntry).pairs.removeWhere(
(entries[path]! as CustomSequencesEntry).pairs.removeWhere(
(pair) =>
pair.item1.path == file.path || pair.item2.path == file.path,
);
} else if (entries.containsKey(path) &&
entries[path] is CustomTexturesEntry) {
(entries[path] as CustomTexturesEntry)
(entries[path]! as CustomTexturesEntry)
.pairs
.removeWhere((pair) => pair.item1.path == file.path);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import 'package:retro/otr/resource.dart';
import 'package:retro/otr/resource_type.dart';
import 'package:retro/otr/types/background.dart';
import 'package:retro/otr/types/texture.dart';
import 'package:retro/otr/version.dart';
import 'package:retro/utils/log.dart';
import 'package:retro/utils/path.dart' as p;
import 'package:tuple/tuple.dart';
Expand Down Expand Up @@ -170,8 +171,8 @@ Future<HashMap<String, ProcessedFilesInFolder>?> processFolder(
return null;
}

String manifestContents = await manifestFile.readAsString();
Map<String, dynamic> manifest = json.decode(manifestContents) as Map<String, dynamic>;
final manifestContents = await manifestFile.readAsString();
final manifest = json.decode(manifestContents) as Map<String, dynamic>;

// find all images in folder
final supportedExtensions = <String>['.png', '.jpeg', '.jpg'];
Expand All @@ -187,7 +188,7 @@ Future<HashMap<String, ProcessedFilesInFolder>?> processFolder(
p.normalize(texFile.path.split('$folderPath/').last.split('.').first);
if (manifest.containsKey(texPathRelativeToFolder)) {
final manifestEntry =
TextureManifestEntry.fromJson(manifest[texPathRelativeToFolder]);
TextureManifestEntry.fromJson(manifest[texPathRelativeToFolder] as Map<String, dynamic>);
// if it is, check if the file has changed
final texFileBytes = await texFile.readAsBytes();
final texFileHash = sha256.convert(texFileBytes).toString();
Expand Down Expand Up @@ -218,38 +219,32 @@ Future<HashMap<String, ProcessedFilesInFolder>?> processFolder(

Future<HashMap<String, TextureManifestEntry>?> processOTR(
Tuple2<List<String>, String> params) async {
try {
var fileFound = false;
final processedFiles = HashMap<String, TextureManifestEntry>();
final processedFiles = HashMap<String, TextureManifestEntry>();

// just use the first otr in the list for the directory name
final otrNameForOutputDirectory =
params.item1[0].split(Platform.pathSeparator).last.split('.').first;

// if folder we'll export to exists, delete it
final dir = Directory('${params.item2}/$otrNameForOutputDirectory');
if (dir.existsSync()) {
log('Deleting existing folder: ${params.item2}/$otrNameForOutputDirectory');
await dir.delete(recursive: true);
}
// just use the first otr in the list for the directory name
final otrNameForOutputDirectory =
params.item1[0].split(Platform.pathSeparator).last.split('.').first;

for (final otrPath in params.item1) {
log('Processing OTR: $otrPath');
final arcFile = Arc(otrPath);
// if folder we'll export to exists, delete it
final dir = Directory('${params.item2}/$otrNameForOutputDirectory');
if (dir.existsSync()) {
log('Deleting existing folder: ${params.item2}/$otrNameForOutputDirectory');
await dir.delete(recursive: true);
}

await arcFile.listItems(onFile: (String fileName, Uint8List data) async {
await processFile(fileName, data, '${params.item2}/$otrNameForOutputDirectory/$fileName', (TextureManifestEntry entry) {
processedFiles[fileName] = entry;
});
},);
arcFile.close();
}
for (final otrPath in params.item1) {
log('Processing OTR: $otrPath');
final arcFile = Arc(otrPath);

return processedFiles;
} on StormLibException catch (e) {
log('Failed to find next file: ${e.message}');
return null;
await arcFile.listItems(onFile: (String fileName, Uint8List data) async {
await processFile(fileName, data, '${params.item2}/$otrNameForOutputDirectory/$fileName', (TextureManifestEntry entry) {
processedFiles[fileName] = entry;
});
},);
arcFile.close();
}

return processedFiles.isEmpty ? null : processedFiles;
}

Future<bool> processFile(String fileName, Uint8List data, String outputPath, Function onProcessed) async {
Expand All @@ -269,6 +264,10 @@ Future<bool> processFile(String fileName, Uint8List data, String outputPath, Fun
final texture = Texture.empty();
texture.open(data);

if(texture.gameVersion == Version.roy){
KiritoDv marked this conversation as resolved.
Show resolved Hide resolved
break;
}

final pngBytes = texture.toPNGBytes();
final textureFile = File('$outputPath.png');
await textureFile.create(recursive: true);
Expand Down
Loading
Loading