From 17f18ea78d2de2811467680d4f9826439a62dcf1 Mon Sep 17 00:00:00 2001 From: Gabber235 Date: Sun, 10 Sep 2023 17:17:00 +0200 Subject: [PATCH] First version of the new Item type --- .../entries/action/GiveItemActionEntry.kt | 36 +-- .../cinematic/CinematicConsoleCommandEntry.kt | 3 +- app/lib/app_router.dart | 12 +- app/lib/models/adapter.dart | 28 ++- app/lib/pages/page_editor.g.dart | 2 +- app/lib/utils/extensions.dart | 16 +- .../components/app/cinematic_view.g.dart | 6 +- .../widgets/components/general/error_box.dart | 26 ++ app/lib/widgets/inspector/editors.dart | 2 + app/lib/widgets/inspector/editors.g.dart | 2 +- app/lib/widgets/inspector/editors/field.dart | 13 +- app/lib/widgets/inspector/editors/item.dart | 225 ++++++++++++++++++ .../widgets/inspector/editors/material.dart | 27 ++- .../widgets/inspector/editors/material.g.dart | 2 +- app/lib/widgets/inspector/editors/number.dart | 6 +- app/lib/widgets/inspector/header.dart | 1 - app/pubspec.lock | 160 ++++++------- app/pubspec.yaml | 2 +- plugin/build.gradle.kts | 4 +- .../typewriter/adapters/CustomEditors.kt | 2 + .../typewriter/adapters/FieldModifiers.kt | 7 + .../typewriter/adapters/editors/ItemEditor.kt | 41 ++++ .../typewriter/adapters/modifiers/Icon.kt | 16 ++ .../me/gabber235/typewriter/utils/Item.kt | 109 +++++++++ .../typewriter/utils/MiniMessages.kt | 2 + 25 files changed, 587 insertions(+), 163 deletions(-) create mode 100644 app/lib/widgets/components/general/error_box.dart create mode 100644 app/lib/widgets/inspector/editors/item.dart create mode 100644 plugin/src/main/kotlin/me/gabber235/typewriter/adapters/editors/ItemEditor.kt create mode 100644 plugin/src/main/kotlin/me/gabber235/typewriter/adapters/modifiers/Icon.kt create mode 100644 plugin/src/main/kotlin/me/gabber235/typewriter/utils/Item.kt diff --git a/adapters/BasicAdapter/src/main/kotlin/me/gabber235/typewriter/entries/action/GiveItemActionEntry.kt b/adapters/BasicAdapter/src/main/kotlin/me/gabber235/typewriter/entries/action/GiveItemActionEntry.kt index c9da0f4ec7..9c39853125 100644 --- a/adapters/BasicAdapter/src/main/kotlin/me/gabber235/typewriter/entries/action/GiveItemActionEntry.kt +++ b/adapters/BasicAdapter/src/main/kotlin/me/gabber235/typewriter/entries/action/GiveItemActionEntry.kt @@ -1,21 +1,14 @@ package me.gabber235.typewriter.entries.action -import lirand.api.extensions.inventory.meta import me.gabber235.typewriter.adapters.Colors import me.gabber235.typewriter.adapters.Entry -import me.gabber235.typewriter.adapters.modifiers.Colored import me.gabber235.typewriter.adapters.modifiers.Help -import me.gabber235.typewriter.adapters.modifiers.MultiLine -import me.gabber235.typewriter.adapters.modifiers.Placeholder import me.gabber235.typewriter.entry.Criteria import me.gabber235.typewriter.entry.Modifier import me.gabber235.typewriter.entry.entries.ActionEntry import me.gabber235.typewriter.utils.Icons -import me.gabber235.typewriter.utils.asMini -import org.bukkit.Material +import me.gabber235.typewriter.utils.Item import org.bukkit.entity.Player -import org.bukkit.inventory.ItemStack -import org.bukkit.inventory.meta.ItemMeta @Entry("give_item", "Give an item to the player", Colors.RED, Icons.WAND_SPARKLES) /** @@ -32,34 +25,11 @@ class GiveItemActionEntry( override val modifiers: List, override val triggers: List = emptyList(), @Help("The item to give.") - // The Minecraft material of the item to give. - private val material: Material = Material.AIR, - @Help("The amount of items to give.") - private val amount: Int = 1, - @Colored - @Placeholder - @Help("The display name of the item. (Defaults to the item's display name)") - // The display name of the item to give. If not specified, the item will have it's default display name. - private val displayName: String = "", - @MultiLine - @Colored - @Placeholder - @Help("The lore of the item. (Defaults to the item's lore)") - // The lore of the item to give. If not specified, the item will have it's default lore. - private val lore: String, + val item: Item = Item.Empty, ) : ActionEntry { override fun execute(player: Player) { super.execute(player) - val item = ItemStack(material, amount).meta { - if (this@GiveItemActionEntry.displayName.isNotBlank()) displayName(this@GiveItemActionEntry.displayName.asMini()) - if (this@GiveItemActionEntry.lore.isNotBlank()) { - lore( - this@GiveItemActionEntry.lore.split("\n").map { "$it".asMini() }) - - } - } - - player.inventory.addItem(item) + player.inventory.addItem(item.build(player)) } } \ No newline at end of file diff --git a/adapters/BasicAdapter/src/main/kotlin/me/gabber235/typewriter/entries/cinematic/CinematicConsoleCommandEntry.kt b/adapters/BasicAdapter/src/main/kotlin/me/gabber235/typewriter/entries/cinematic/CinematicConsoleCommandEntry.kt index bf46726096..d4f50ce07f 100644 --- a/adapters/BasicAdapter/src/main/kotlin/me/gabber235/typewriter/entries/cinematic/CinematicConsoleCommandEntry.kt +++ b/adapters/BasicAdapter/src/main/kotlin/me/gabber235/typewriter/entries/cinematic/CinematicConsoleCommandEntry.kt @@ -32,7 +32,6 @@ class CinematicConsoleCommandEntry( override val name: String, override val criteria: List, @Segments(Colors.YELLOW, Icons.TERMINAL) - @Placeholder @InnerMax(Max(1)) // Run commands on different segments override val segments: List, @@ -60,7 +59,6 @@ class CinematicPlayerCommandEntry( override val name: String, override val criteria: List, @Segments(Colors.YELLOW, Icons.TERMINAL) - @Placeholder @InnerMax(Max(1)) // Run commands on different segments override val segments: List, @@ -79,6 +77,7 @@ data class CommandSegment( override val startFrame: Int, override val endFrame: Int, @Help("The command to run") + @Placeholder val command: String, ) : Segment diff --git a/app/lib/app_router.dart b/app/lib/app_router.dart index 77995ff573..797622e82e 100644 --- a/app/lib/app_router.dart +++ b/app/lib/app_router.dart @@ -28,7 +28,8 @@ class AppRouter extends _$AppRouter { final PassingRef ref; @override - RouteType get defaultRouteType => const RouteType.custom(transitionsBuilder: TransitionsBuilders.noTransition); + RouteType get defaultRouteType => const RouteType.custom( + transitionsBuilder: TransitionsBuilders.noTransition); @override List get routes => [ @@ -79,7 +80,8 @@ extension AppRouterX on AppRouter { Future navigateToEntry(PassingRef ref, String entryId) async { final currentPage = ref.read(currentPageProvider); - if (currentPage != null && currentPage.entries.none((e) => e.id == entryId)) { + if (currentPage != null && + currentPage.entries.none((e) => e.id == entryId)) { final entryPage = ref.read(globalEntryWithPageProvider(entryId))?.key; if (entryPage != null) { await navigateToPage(ref, entryPage); @@ -93,9 +95,9 @@ extension AppRouterX on AppRouter { final currentPage = ref.read(currentPageProvider); if (currentPage?.name != pageId) { - await ref - .read(appRouter) - .push(PageEditorRoute(id: pageId), onFailure: (e) => debugPrint("Failed to navigate to page $pageId: $e")); + await ref.read(appRouter).push(PageEditorRoute(id: pageId), + onFailure: (e) => + debugPrint("Failed to navigate to page $pageId: $e")); } } } diff --git a/app/lib/models/adapter.dart b/app/lib/models/adapter.dart index f41dd21d5e..afeff2c6dc 100644 --- a/app/lib/models/adapter.dart +++ b/app/lib/models/adapter.dart @@ -34,7 +34,10 @@ List entryTags(EntryTagsRef ref, String name) => /// Gets all the modifiers with a given name. @riverpod Map fieldModifiers( - FieldModifiersRef ref, String blueprint, String name,) { + FieldModifiersRef ref, + String blueprint, + String name, +) { return ref .watch(entryBlueprintProvider(blueprint)) ?.fieldsWithModifier(name) ?? @@ -44,7 +47,10 @@ Map fieldModifiers( /// Gets all the paths from fields with a given modifier. @riverpod List modifierPaths( - ModifierPathsRef ref, String blueprint, String name,) { + ModifierPathsRef ref, + String blueprint, + String name, +) { return ref.watch(fieldModifiersProvider(blueprint, name)).keys.toList(); } @@ -153,7 +159,10 @@ extension EntryBlueprintExt on EntryBlueprint { /// Parse through the fields of this entry and return a list of all the fields that have the given modifier with [name]. Map _fieldsWithModifier( - String name, String path, FieldInfo info,) { + String name, + String path, + FieldInfo info, + ) { final fields = { if (info.hasModifier(name)) path: info.getModifier(name)!, }; @@ -161,8 +170,13 @@ extension EntryBlueprintExt on EntryBlueprint { final separator = path.isEmpty ? "" : "."; if (info is ObjectField) { for (final field in info.fields.entries) { - fields.addAll(_fieldsWithModifier( - name, "$path$separator${field.key}", field.value,),); + fields.addAll( + _fieldsWithModifier( + name, + "$path$separator${field.key}", + field.value, + ), + ); } } else if (info is ListField) { fields.addAll(_fieldsWithModifier(name, "$path$separator*", info.type)); @@ -215,6 +229,8 @@ extension EntryBlueprintExt on EntryBlueprint { } } +final _customEditorCustomLayout = ["optional", "item"]; + /// Since freezed does not support methods on data models, we have to create a separate extension class. extension FieldTypeExtension on FieldInfo { /// Get the default value for this field type. @@ -243,7 +259,7 @@ extension FieldTypeExtension on FieldInfo { bool get hasCustomLayout { if (this is CustomField) { final editor = (this as CustomField).editor; - if (editor == "optional") { + if (_customEditorCustomLayout.contains(editor)) { return true; } } diff --git a/app/lib/pages/page_editor.g.dart b/app/lib/pages/page_editor.g.dart index f66b1265c9..3f7805080f 100644 --- a/app/lib/pages/page_editor.g.dart +++ b/app/lib/pages/page_editor.g.dart @@ -65,7 +65,7 @@ final currentPageTypeProvider = AutoDisposeProvider.internal( ); typedef CurrentPageTypeRef = AutoDisposeProviderRef; -String _$writersHash() => r'90aabc0610038faeb596c5fce4ab05f1db644033'; +String _$writersHash() => r'9c6cafb1a013526500fb7518776c0d1e7a93f479'; /// See also [_writers]. @ProviderFor(_writers) diff --git a/app/lib/utils/extensions.dart b/app/lib/utils/extensions.dart index 4de46d1581..df08c9ab1c 100644 --- a/app/lib/utils/extensions.dart +++ b/app/lib/utils/extensions.dart @@ -102,16 +102,22 @@ extension ObjectExtension on Object? { T? cast() => this is T ? this as T : null; } -extension ListExtensions on List { +extension ListExtensions on List { List get indices => List.generate(length, (index) => index); + + List difference(List other) { + return where((element) => !other.contains(element)).toList() + ..addAll(other.where((element) => !contains(element)).toSet()); + } } TextInputFormatter snakeCaseFormatter() => TextInputFormatter.withFunction( (oldValue, newValue) => newValue.copyWith( - text: newValue.text - .toLowerCase() - .replaceAll(" ", "_") - .replaceAll("-", "_"),), + text: newValue.text + .toLowerCase() + .replaceAll(" ", "_") + .replaceAll("-", "_"), + ), ); extension RandomColor on String { diff --git a/app/lib/widgets/components/app/cinematic_view.g.dart b/app/lib/widgets/components/app/cinematic_view.g.dart index 7289cd48f7..a183669aa1 100644 --- a/app/lib/widgets/components/app/cinematic_view.g.dart +++ b/app/lib/widgets/components/app/cinematic_view.g.dart @@ -125,7 +125,7 @@ class _SegmentPathsProvider extends AutoDisposeProvider> { } } -String _$segmentsHash() => r'62448598c38a97d97a3386f8e198dff9a6c50620'; +String _$segmentsHash() => r'9a50f061be29058473384d5e95184ca25b3fc3de'; typedef _SegmentsRef = AutoDisposeProviderRef>; /// See also [_segments]. @@ -1079,7 +1079,7 @@ String _$segmentFieldsHash() => r'50de8ece747eb6fbdd3c504f30873d7546d54b50'; /// See also [_segmentFields]. @ProviderFor(_segmentFields) -final _segmentFieldsProvider = AutoDisposeProvider.internal( +final _segmentFieldsProvider = AutoDisposeProvider.internal( _segmentFields, name: r'_segmentFieldsProvider', debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') @@ -1089,6 +1089,6 @@ final _segmentFieldsProvider = AutoDisposeProvider.internal( allTransitiveDependencies: null, ); -typedef _SegmentFieldsRef = AutoDisposeProviderRef; +typedef _SegmentFieldsRef = AutoDisposeProviderRef; // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/app/lib/widgets/components/general/error_box.dart b/app/lib/widgets/components/general/error_box.dart new file mode 100644 index 0000000000..86b16b9bb4 --- /dev/null +++ b/app/lib/widgets/components/general/error_box.dart @@ -0,0 +1,26 @@ +import "package:flutter/material.dart"; +import "package:flutter_hooks/flutter_hooks.dart"; + +class ErrorBox extends HookWidget { + const ErrorBox({ + required this.message, + super.key, + }); + + final String message; + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.redAccent, + borderRadius: BorderRadius.circular(4), + ), + child: Text( + message, + style: Theme.of(context).textTheme.bodySmall, + ), + ); + } +} diff --git a/app/lib/widgets/inspector/editors.dart b/app/lib/widgets/inspector/editors.dart index 2e961e310d..b1d5f0caac 100644 --- a/app/lib/widgets/inspector/editors.dart +++ b/app/lib/widgets/inspector/editors.dart @@ -7,6 +7,7 @@ import "package:typewriter/widgets/inspector/editors/cron.dart"; import "package:typewriter/widgets/inspector/editors/duration.dart"; import "package:typewriter/widgets/inspector/editors/entry_selector.dart"; import "package:typewriter/widgets/inspector/editors/enum.dart"; +import "package:typewriter/widgets/inspector/editors/item.dart"; import "package:typewriter/widgets/inspector/editors/list.dart"; import "package:typewriter/widgets/inspector/editors/location.dart"; import "package:typewriter/widgets/inspector/editors/map.dart"; @@ -42,6 +43,7 @@ List editorFilters(EditorFiltersRef ref) => [ DurationEditorFilter(), CronEditorFilter(), PotionEffectEditorFilter(), + ItemEditorFilter(), // Default filters StringEditorFilter(), diff --git a/app/lib/widgets/inspector/editors.g.dart b/app/lib/widgets/inspector/editors.g.dart index 82aa1fef17..aee58d86aa 100644 --- a/app/lib/widgets/inspector/editors.g.dart +++ b/app/lib/widgets/inspector/editors.g.dart @@ -119,7 +119,7 @@ class FieldValueProvider extends AutoDisposeProvider { } } -String _$editorFiltersHash() => r'7a9a87432cb4d5032c078bd9d45ab3a4340fbbcf'; +String _$editorFiltersHash() => r'82881dad4fc36c0d7950c7bee132cd91a6e0314a'; /// See also [editorFilters]. @ProviderFor(editorFilters) diff --git a/app/lib/widgets/inspector/editors/field.dart b/app/lib/widgets/inspector/editors/field.dart index 0e54bb0f7f..29566f7856 100644 --- a/app/lib/widgets/inspector/editors/field.dart +++ b/app/lib/widgets/inspector/editors/field.dart @@ -2,6 +2,7 @@ import "package:collection/collection.dart"; import "package:flutter/material.dart"; import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:typewriter/models/adapter.dart"; +import "package:typewriter/widgets/components/general/error_box.dart"; import "package:typewriter/widgets/inspector/editors.dart"; class FieldEditor extends HookConsumerWidget { @@ -34,16 +35,6 @@ class _NoEditorFound extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.redAccent, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - "Could not find a editor for $path", - style: Theme.of(context).textTheme.bodySmall, - ), - ); + return ErrorBox(message: "Could not find a editor for $path"); } } diff --git a/app/lib/widgets/inspector/editors/item.dart b/app/lib/widgets/inspector/editors/item.dart new file mode 100644 index 0000000000..973e27d27a --- /dev/null +++ b/app/lib/widgets/inspector/editors/item.dart @@ -0,0 +1,225 @@ +import "package:flutter/material.dart"; +import "package:flutter_animate/flutter_animate.dart"; +import "package:flutter_hooks/flutter_hooks.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:hooks_riverpod/hooks_riverpod.dart"; +import "package:typewriter/models/adapter.dart"; +import "package:typewriter/models/icons.dart"; +import "package:typewriter/utils/extensions.dart"; +import "package:typewriter/utils/passing_reference.dart"; +import "package:typewriter/widgets/components/general/error_box.dart"; +import "package:typewriter/widgets/inspector/editors.dart"; +import "package:typewriter/widgets/inspector/editors/field.dart"; +import "package:typewriter/widgets/inspector/header.dart"; +import "package:typewriter/widgets/inspector/inspector.dart"; + +class ItemEditorFilter extends EditorFilter { + @override + bool canEdit(FieldInfo info) => info is CustomField && info.editor == "item"; + @override + Widget build(String path, FieldInfo info) => + ItemEditor(path: path, info: info as CustomField); +} + +class ItemEditor extends HookConsumerWidget { + const ItemEditor({ + required this.path, + required this.info, + super.key, + }); + + final String path; + final CustomField info; + + @override + Widget build(BuildContext context, WidgetRef ref) { + // final value = ref.watch(fieldValueProvider(path)); + final objectField = + info.fieldInfo is ObjectField ? info.fieldInfo as ObjectField? : null; + if (objectField == null) { + return ErrorBox( + message: "Could not find subfields for item field: $path", + ); + } + return FieldHeader( + path: path, + field: info, + canExpand: true, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 8), + _FieldSelector(path: path, objectField: objectField), + _ItemEditors(path: path, objectField: objectField), + // Text("Item: $value"), + // Text("Info: ${info.fieldInfo}"), + ], + ), + ); + } +} + +class _FieldSelector extends HookConsumerWidget { + const _FieldSelector({ + required this.path, + required this.objectField, + }); + + final String path; + final ObjectField objectField; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final hovering = useState(false); + final selected = objectField.fields.keys + .where( + (id) => + ref.watch(fieldValueProvider("$path.$id.enabled", false)) == true, + ) + .toList(); + + final showAll = hovering.value || selected.isEmpty; + + return MouseRegion( + onEnter: (_) => hovering.value = true, + onExit: (_) => hovering.value = false, + child: SizedBox( + width: double.infinity, + child: AnimatedSize( + duration: 1200.ms, + curve: Curves.elasticOut, + alignment: Alignment.topCenter, + clipBehavior: Clip.none, + child: Wrap( + spacing: 6, + runSpacing: 6, + children: [ + for (final MapEntry(key: id, value: info) + in objectField.fields.entries) + if (showAll || selected.contains(id)) + _ItemChip( + key: ValueKey(id), + path: "$path.$id", + id: id, + info: info, + ), + ].animate(interval: 40.ms).fadeIn(duration: 250.ms).scaleXY( + begin: 0.6, + end: 1.0, + duration: 800.ms, + curve: Curves.elasticOut, + ), + ), + ), + ), + ); + } +} + +class _ItemChip extends HookConsumerWidget { + const _ItemChip({ + required this.path, + required this.id, + required this.info, + super.key, + }); + + final String path; + final String id; + final FieldInfo info; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final enabled = ref.watch(fieldValueProvider("$path.enabled", false)); + + final foregroundColor = enabled + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface.withOpacity(0.7); + + return InputChip( + label: Text(id.capitalize, style: TextStyle(color: foregroundColor)), + avatar: FaIcon( + icons[info.get("icon") ?? "check"] ?? FontAwesomeIcons.check, + size: 14, + color: foregroundColor, + ), + backgroundColor: Theme.of(context).colorScheme.onSurface.withOpacity(0.1), + selectedColor: Theme.of(context).colorScheme.primary.withOpacity(0.1), + side: BorderSide.none, + showCheckmark: false, + selected: enabled, + onSelected: (value) { + ref + .read(inspectingEntryDefinitionProvider) + ?.updateField(ref.passing, "$path.enabled", value); + }, + ); + } +} + +class _ItemEditors extends HookConsumerWidget { + const _ItemEditors({ + required this.path, + required this.objectField, + }); + + final String path; + final ObjectField objectField; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return AnimatedSize( + duration: 200.ms, + curve: Curves.easeOutCubic, + alignment: Alignment.topCenter, + clipBehavior: Clip.none, + child: Column( + children: [ + for (final MapEntry(key: id, value: info) + in objectField.fields.entries) + _ItemEditor( + key: ValueKey(id), + path: "$path.$id", + field: info, + ), + ], + ), + ); + } +} + +class _ItemEditor extends HookConsumerWidget { + const _ItemEditor({ + required this.path, + required this.field, + super.key, + }); + + final String path; + final FieldInfo field; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final enabled = ref.watch(fieldValueProvider("$path.enabled", false)); + + if (!enabled) { + return const SizedBox(); + } + + return Column( + children: [ + const SizedBox(height: 8), + FieldHeader( + field: field, + path: path, + child: FieldEditor(path: "$path.value", type: field), + ), + ], + ).animate().fadeIn(duration: 250.ms).moveY( + begin: 20, + end: 0, + duration: 500.ms, + curve: Curves.easeOutCubic, + ); + } +} diff --git a/app/lib/widgets/inspector/editors/material.dart b/app/lib/widgets/inspector/editors/material.dart index e1b3e39bea..4bcfa8f532 100644 --- a/app/lib/widgets/inspector/editors/material.dart +++ b/app/lib/widgets/inspector/editors/material.dart @@ -19,11 +19,17 @@ typedef CombinedMaterial = MapEntry; @riverpod List materialProperties( - MaterialPropertiesRef ref, String meta,) { + MaterialPropertiesRef ref, + String meta, +) { return meta .split(";") - .map((property) => MaterialProperty.values - .firstWhere((element) => element.name.toLowerCase() == property),) + .map( + (property) => MaterialProperty.values.firstWhere( + (element) => element.name.toLowerCase() == property, + orElse: () => throw Exception("Unknown material property: $property"), + ), + ) .toList(); } @@ -234,13 +240,18 @@ class MaterialEditor extends HookConsumerWidget { children: [ if (hasMaterial) Expanded( - child: _MaterialItem( - id: currentValue, material: currentMaterial,),) + child: _MaterialItem( + id: currentValue, + material: currentMaterial, + ), + ) else Expanded( - child: Text("Select a material", - style: - Theme.of(context).inputDecorationTheme.hintStyle,),), + child: Text( + "Select a material", + style: Theme.of(context).inputDecorationTheme.hintStyle, + ), + ), const SizedBox(width: 12), FaIcon( FontAwesomeIcons.caretDown, diff --git a/app/lib/widgets/inspector/editors/material.g.dart b/app/lib/widgets/inspector/editors/material.g.dart index a20e1173f0..56231eb446 100644 --- a/app/lib/widgets/inspector/editors/material.g.dart +++ b/app/lib/widgets/inspector/editors/material.g.dart @@ -7,7 +7,7 @@ part of 'material.dart'; // ************************************************************************** String _$materialPropertiesHash() => - r'2537760a0cb4dc55f7fb40e4e045184959705bc2'; + r'ec0ce652cc3458c9e2ee4d54c4fa1f496a45f1db'; /// Copied from Dart SDK class _SystemHash { diff --git a/app/lib/widgets/inspector/editors/number.dart b/app/lib/widgets/inspector/editors/number.dart index 1f9ccee1ea..7003b46410 100644 --- a/app/lib/widgets/inspector/editors/number.dart +++ b/app/lib/widgets/inspector/editors/number.dart @@ -21,11 +21,11 @@ class NumberEditorFilter extends EditorFilter { @override Widget build(String path, FieldInfo info) => - IntegerEditor(path: path, field: info as PrimitiveField); + NumberEditor(path: path, field: info as PrimitiveField); } -class IntegerEditor extends HookConsumerWidget { - const IntegerEditor({ +class NumberEditor extends HookConsumerWidget { + const NumberEditor({ required this.path, required this.field, super.key, diff --git a/app/lib/widgets/inspector/header.dart b/app/lib/widgets/inspector/header.dart index fbcd4ca92a..d42d882f69 100644 --- a/app/lib/widgets/inspector/header.dart +++ b/app/lib/widgets/inspector/header.dart @@ -105,7 +105,6 @@ class FieldHeader extends HookConsumerWidget { Collapsible( collapsed: !expanded.value, axis: CollapsibleAxis.vertical, - clipBehavior: Clip.none, child: Padding( padding: const EdgeInsets.only(left: 8), child: child, diff --git a/app/pubspec.lock b/app/pubspec.lock index 5b46bc97f9..15e9d0f099 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -29,10 +29,10 @@ packages: dependency: transitive description: name: archive - sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" + sha256: "49b1fad315e57ab0bbc15bcbb874e83116a1d78f77ebd500a4af6c9407d6b28e" url: "https://pub.dev" source: hosted - version: "3.3.7" + version: "3.3.8" args: dependency: transitive description: @@ -109,10 +109,10 @@ packages: dependency: "direct main" description: name: auto_route - sha256: afa2e3a038efdd9b70478c597161e4c6549a73cd2f5957077d4b311f71104671 + sha256: "72f21e8b6cbbe25f02ea69183e024996530bf495cc1b077a49e0ec6726f0c271" url: "https://pub.dev" source: hosted - version: "7.8.0" + version: "7.8.3" auto_route_generator: dependency: "direct dev" description: @@ -165,10 +165,10 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20" + sha256: d912852cce27c9e80a93603db721c267716894462e7033165178b91138587972 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.2" build_runner: dependency: "direct dev" description: @@ -197,10 +197,10 @@ packages: dependency: transitive description: name: built_value - sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166" + sha256: ff627b645b28fb8bdb69e645f910c2458fd6b65f6585c3a53e0626024897dedf url: "https://pub.dev" source: hosted - version: "8.6.1" + version: "8.6.2" characters: dependency: transitive description: @@ -253,10 +253,10 @@ packages: dependency: transitive description: name: code_builder - sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189" + sha256: "315a598c7fbe77f22de1c9da7cfd6fd21816312f16ffa124453b4fc679e540f1" url: "https://pub.dev" source: hosted - version: "4.5.0" + version: "4.6.0" collapsible: dependency: "direct main" description: @@ -309,34 +309,34 @@ packages: dependency: "direct main" description: name: cupertino_icons - sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.6" custom_lint: dependency: "direct dev" description: name: custom_lint - sha256: ae3cf0f83a155bdfc50315d4a11c7b358ea1e201a57ab0bb2b397f1a9a2a9b80 + sha256: "837821e4619c167fd5a547b03bb2fc6be7e65b800ec75528848429705c31ceba" url: "https://pub.dev" source: hosted - version: "0.5.2" + version: "0.5.3" custom_lint_builder: dependency: transitive description: name: custom_lint_builder - sha256: fe5ba0dabc29d71d52fa372012fabada14af50e4cdf75e4928b1db400cf6afe1 + sha256: "3537d50202568994a6f42b1f2953aed6292fc5ecf83e45237af73f64aff2be72" url: "https://pub.dev" source: hosted - version: "0.5.2" + version: "0.5.3" custom_lint_core: dependency: transitive description: name: custom_lint_core - sha256: a420aa57121a22b2a42e7e1dbbcaf7b91ef73b90adce07149419c16cf67d6fcc + sha256: "3bdebdd52a42b4d6e5be9cd833ad1ecfbbc23e1020ca537060e54085497aea9c" url: "https://pub.dev" source: hosted - version: "0.5.2" + version: "0.5.3" dart_style: dependency: transitive description: @@ -410,26 +410,26 @@ packages: dependency: "direct main" description: name: flutter_hooks - sha256: "9eab8fd7aa752c3c1c0a364f9825851d410eb935243411682f4b1b0a4c569d71" + sha256: "6ae13b1145c589112cbd5c4fda6c65908993a9cb18d4f82042e9c28dd9fbf611" url: "https://pub.dev" source: hosted - version: "0.20.0" + version: "0.20.1" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.0.3" flutter_riverpod: dependency: transitive description: name: flutter_riverpod - sha256: b6cb0041c6c11cefb2dcb97ef436eba43c6d41287ac6d8ca93e02a497f53a4f3 + sha256: "1bd39b04f1bcd217a969589777ca6bd642d116e3e5de65c3e6a8e8bdd8b178ec" url: "https://pub.dev" source: hosted - version: "2.3.7" + version: "2.4.0" flutter_svg: dependency: "direct main" description: @@ -516,10 +516,10 @@ packages: dependency: "direct main" description: name: hooks_riverpod - sha256: "2bb8ae6a729e1334f71f1ef68dd5f0400dca8f01de8cbdcde062584a68017b18" + sha256: ad7b877c3687e38764633d221a1f65491bc7a540e724101e9a404a84db2a4276 url: "https://pub.dev" source: hosted - version: "2.3.8" + version: "2.4.0" hotreloader: dependency: transitive description: @@ -700,58 +700,58 @@ packages: dependency: transitive description: name: path_provider - sha256: "909b84830485dbcd0308edf6f7368bc8fd76afa26a270420f34cabea2a6467a0" + sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "5d44fc3314d969b84816b569070d7ace0f1dea04bd94a83f74c4829615d22ad8" + sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.2.0" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "1b744d3d774e5a879bb76d6cd1ecee2ba2c6960c03b1020cd35212f6aa267ac5" + sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.1" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ba2b77f0c52a33db09fc8caf85b12df691bf28d983e84cf87ff6d693cfa007b3 + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: bced5679c7df11190e1ddc35f3222c858f328fff85c3942e46e7f5589bf9eb84 + sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: ee0e0d164516b90ae1f970bdf29f726f1aa730d7cfc449ecc74c495378b705da + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.1" petitparser: dependency: transitive description: name: petitparser - sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + sha256: eeb2d1428ee7f4170e2bd498827296a18d4e7fc462b71727d111c0ac7707cfa6 url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "6.0.1" pigment: dependency: transitive description: @@ -764,18 +764,18 @@ packages: dependency: transitive description: name: platform - sha256: "57c07bf82207aee366dfaa3867b3164e4f03a238a461a11b0e8a3a510d51203d" + sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" + sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.1.6" pointycastle: dependency: transitive description: @@ -812,26 +812,26 @@ packages: dependency: "direct main" description: name: rive - sha256: b7780ebdc56320da1f02a39a18f050a6079cad60c0cb92003c0801cc4eec6673 + sha256: "5fbb92f9f880cddbb9181342dc24099eee323ca43339e2c8e1ae6fad85df915e" url: "https://pub.dev" source: hosted - version: "0.11.14" + version: "0.11.16" rive_common: dependency: transitive description: name: rive_common - sha256: "1431b99c9f361234cc6fa9aee7987b20030622df25ff64343a4010f9446b275e" + sha256: e41f12917cb58e0c9376836490ebaa431e12744da0c67e19dad8d4bee9fedd46 url: "https://pub.dev" source: hosted - version: "0.2.6" + version: "0.2.7" riverpod: dependency: transitive description: name: riverpod - sha256: b0657b5b30c81a3184bdaab353045f0a403ebd60bb381591a8b7ad77dcade793 + sha256: a600120d6f213a9922860eea1abc32597436edd5b2c4e73b91410f8c2af67d22 url: "https://pub.dev" source: hosted - version: "2.3.7" + version: "2.4.0" riverpod_analyzer_utils: dependency: transitive description: @@ -844,10 +844,10 @@ packages: dependency: "direct main" description: name: riverpod_annotation - sha256: "8b3f7a54ddd5d53d6ea04bfb4ff77ee1b0816a1b563c0d9d43e73ce94bf2016d" + sha256: "6294fe7e7d1875f32bdf04c8fce7620e718070273703097847df8f3bf16995ea" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.5" riverpod_generator: dependency: "direct dev" description: @@ -860,10 +860,10 @@ packages: dependency: "direct dev" description: name: riverpod_lint - sha256: c9a16d8cb89667696b031d66f43c12ac8d663d773093425e6ff6af7e682973b1 + sha256: "74123a5f0a8e809ab80078dbc02061ecf02e09647a2c3231c87b7342bcf8d399" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.4" rxdart: dependency: transitive description: @@ -1049,66 +1049,66 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e" + sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27" url: "https://pub.dev" source: hosted - version: "6.1.12" + version: "6.1.14" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "3dd2388cc0c42912eee04434531a26a82512b9cb1827e0214430c9bcbddfe025" + sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330 url: "https://pub.dev" source: hosted - version: "6.0.38" + version: "6.1.0" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" + sha256: "7c65021d5dee51813d652357bc65b8dd4a6177082a9966bc8ba6ee477baa795f" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "6.1.5" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" + sha256: b651aad005e0cb06a01dbd84b428a301916dc75f0e7ea6165f80057fee2d8e8e url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.6" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1" + sha256: b55486791f666e62e0e8ff825e58a023fd6b1f71c49926483f1128d3bbd8fe88 url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.0.7" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea + sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.5" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 + sha256: "2942294a500b4fa0b918685aff406773ba0a4cd34b7f42198742a94083020ce5" url: "https://pub.dev" source: hosted - version: "2.0.18" + version: "2.0.20" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" + sha256: "95fef3129dc7cfaba2bc3d5ba2e16063bb561fc6d78e63eee16162bc70029069" url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "3.0.8" uuid: dependency: "direct main" description: @@ -1153,10 +1153,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "0fae432c85c4ea880b33b497d32824b97795b04cdaa74d270219572a1f50268d" + sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 url: "https://pub.dev" source: hosted - version: "11.9.0" + version: "11.10.0" watcher: dependency: transitive description: @@ -1185,26 +1185,26 @@ packages: dependency: transitive description: name: win32 - sha256: f2add6fa510d3ae152903412227bda57d0d5a8da61d2c39c1fb022c9429a41c0 + sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa" url: "https://pub.dev" source: hosted - version: "5.0.6" + version: "5.0.7" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: f0c26453a2d47aa4c2570c6a033246a3fc62da2fe23c7ffdd0a7495086dc0247 + sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.3" xml: dependency: transitive description: name: xml - sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + sha256: af5e77e9b83f2f4adc5d3f0a4ece1c7f45a2467b695c2540381bac793e34e556 url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.4.2" yaml: dependency: transitive description: @@ -1214,5 +1214,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" - flutter: ">=3.10.0" + dart: ">=3.1.0 <4.0.0" + flutter: ">=3.13.0" diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 788ed180b9..395b23f892 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -51,7 +51,7 @@ dev_dependencies: json_serializable: ^6.7.1 icons_launcher: ^2.1.3 auto_route_generator: ^7.2.0 - riverpod_generator: ^2.2.6 + riverpod_generator: 2.2.6 custom_lint: riverpod_lint: ^2.0.1 diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index df1b5f3a8a..c10b0e5412 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -39,8 +39,8 @@ dependencies { implementation("com.github.dyam0:LirandAPI:96cc59d4fb") // Doesn't want to load properly using the spigot api. - implementation("io.ktor:ktor-server-core:2.3.0") - implementation("io.ktor:ktor-server-netty:2.3.0") + implementation("io.ktor:ktor-server-core-jvm:2.3.4") + implementation("io.ktor:ktor-server-netty-jvm:2.3.4") implementation("io.insert-koin:koin-core:3.4.0") compileOnly("com.github.shynixn.mccoroutine:mccoroutine-bukkit-api:2.11.0") diff --git a/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/CustomEditors.kt b/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/CustomEditors.kt index dbb1d041de..6aa3d1c7a4 100644 --- a/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/CustomEditors.kt +++ b/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/CustomEditors.kt @@ -5,6 +5,7 @@ import com.google.gson.reflect.TypeToken import me.gabber235.typewriter.adapters.editors.* import me.gabber235.typewriter.adapters.modifiers.StaticModifierComputer import me.gabber235.typewriter.utils.CronExpression +import me.gabber235.typewriter.utils.Item import org.bukkit.Location import org.bukkit.Material import org.bukkit.potion.PotionEffectType @@ -204,6 +205,7 @@ internal val customEditors by lazy { ObjectEditor::duration, ObjectEditor::cron, ObjectEditor::potionEffectType, + ObjectEditor::item, ) .mapNotNull(::objectEditorFromFunction) .associateBy { it.klass } diff --git a/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/FieldModifiers.kt b/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/FieldModifiers.kt index ea3bbcd33a..fdb2e7b7b1 100644 --- a/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/FieldModifiers.kt +++ b/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/FieldModifiers.kt @@ -146,9 +146,16 @@ private val computers: List by lazy { PlaceholderModifierComputer, ColoredModifierComputer, RegexModifierComputer, + IconModifierComputer, ) } + +/** + * If a field has a modifier for the ui. E.g. it is a trigger or fact or something else. + * We add a bit of extra information to the field. This is used by the UI to + * display the field differently. + */ fun computeFieldModifiers(field: Field, info: FieldInfo) { computers.mapNotNull { it.compute(field, info) }.forEach { it.appendModifier(info) } } \ No newline at end of file diff --git a/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/editors/ItemEditor.kt b/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/editors/ItemEditor.kt new file mode 100644 index 0000000000..7fd351c1ec --- /dev/null +++ b/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/editors/ItemEditor.kt @@ -0,0 +1,41 @@ +package me.gabber235.typewriter.adapters.editors + +import com.google.gson.JsonObject +import com.google.gson.reflect.TypeToken +import me.gabber235.typewriter.adapters.* +import me.gabber235.typewriter.utils.Item +import java.lang.reflect.Modifier + +@CustomEditor(Item::class) +fun ObjectEditor.item() = reference { + default { token -> + val obj = JsonObject() + + token.rawType.declaredFields.filter { !Modifier.isStatic(it.modifiers) }.forEach { field -> + val name = field.name + val info = FieldInfo.fromTypeToken(TypeToken.get(field.genericType)) + val default = info.default() + obj.add(name, default) + } + + obj + } + + fieldInfo { token -> + val fields = token.rawType.declaredFields.filter { !Modifier.isStatic(it.modifiers) }.associate { field -> + val name = field.name + // Check if the type is `Optional` + val type = if (field.type.name == "java.util.Optional") { + val type = field.genericType as java.lang.reflect.ParameterizedType + type.actualTypeArguments[0] + } else { + field.genericType + } + val info = FieldInfo.fromTypeToken(TypeToken.get(type)) + computeFieldModifiers(field, info) + name to info + } + + ObjectField(fields) + } +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/modifiers/Icon.kt b/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/modifiers/Icon.kt new file mode 100644 index 0000000000..b050833daf --- /dev/null +++ b/plugin/src/main/kotlin/me/gabber235/typewriter/adapters/modifiers/Icon.kt @@ -0,0 +1,16 @@ +package me.gabber235.typewriter.adapters.modifiers + +import me.gabber235.typewriter.adapters.FieldInfo +import me.gabber235.typewriter.adapters.FieldModifier +import me.gabber235.typewriter.utils.Icons + +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER) +annotation class Icon(val icon: Icons) + +object IconModifierComputer : StaticModifierComputer { + override val annotationClass: Class = Icon::class.java + + override fun computeModifier(annotation: Icon, info: FieldInfo): FieldModifier { + return FieldModifier.DynamicModifier("icon", annotation.icon.id) + } +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/me/gabber235/typewriter/utils/Item.kt b/plugin/src/main/kotlin/me/gabber235/typewriter/utils/Item.kt new file mode 100644 index 0000000000..8513baf15c --- /dev/null +++ b/plugin/src/main/kotlin/me/gabber235/typewriter/utils/Item.kt @@ -0,0 +1,109 @@ +package me.gabber235.typewriter.utils + +import lirand.api.extensions.inventory.ItemStack +import lirand.api.extensions.inventory.meta +import lirand.api.nbt.NbtData +import lirand.api.nbt.tagNbtData +import me.gabber235.typewriter.adapters.modifiers.* +import me.gabber235.typewriter.extensions.placeholderapi.parsePlaceholders +import me.gabber235.typewriter.utils.Item.Empty.lore +import org.bukkit.Material +import org.bukkit.entity.Player +import org.bukkit.inventory.ItemFlag +import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.ItemMeta +import java.util.* + +open class Item( + @MaterialProperties(MaterialProperty.ITEM) + @Icon(Icons.CUBE) + @Help("The material of the item.") + private val material: Optional = Optional.empty(), + @InnerMin(Min(0)) + @Icon(Icons.HASHTAG) + @Help("The amount of items.") + private val amount: Optional = Optional.empty(), + @Placeholder + @Colored + @Icon(Icons.TAG) + @Help("The display name of the item.") + private val name: Optional = Optional.empty(), + @Placeholder + @Colored + @MultiLine + @Icon(Icons.SOLID_FILE_LINES) + @Help("The lore of the item.") + private val lore: Optional = Optional.empty(), +// private val enchantments: Optional>, + @Icon(Icons.SOLID_FLAG) + @Help("Special flags for the item.") + private val flags: Optional> = Optional.empty(), + @Icon(Icons.CODE) + @Help("The serialized NBT data of the item.") + private val nbt: Optional = Optional.empty(), +) { + + companion object Empty : Item( + Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.empty(), +// Optional.empty(), + Optional.empty(), + Optional.empty(), + ) + + fun build(player: Player?): ItemStack { + val item = ItemStack(material.orElse(Material.STONE), amount.orElse(1)).meta { + if (name.isPresent) { + displayName(name.get().parsePlaceholders(player).asMini()) + } + if (this@Item.lore.isPresent) { + lore(this@Item.lore.get().parsePlaceholders(player).split("\n").map { it.asMini() }) + } +// if (enchantments.isPresent) { +// enchantments.get().forEach { (enchantment, level) -> +// addEnchant(enchantment, level, true) +// } +// } + if (flags.isPresent) { + flags.get().forEach { flag -> + addItemFlags(flag) + } + } + + } + if (nbt.isPresent) { + item.tagNbtData = NbtData(nbt.get()) + } + return item + } + + fun isSameAs(player: Player?, item: ItemStack): Boolean { + if (material.isPresent && item.type != material.get()) return false + if (amount.isPresent && item.amount != amount.get()) return false + if (name.isPresent && item.itemMeta?.displayName() != name.get().parsePlaceholders(player) + .asMini() + ) return false + if (lore.isPresent) { + val lore = lore.get().parsePlaceholders(player).split("\n").map { it.asMini() } + if (item.itemMeta?.lore() != lore) return false + } +// if (enchantments.isPresent && item.itemMeta?.enchants != enchantments.get()) return false + if (flags.isPresent && item.itemMeta?.itemFlags?.toList() != flags.get()) return false + if (nbt.isPresent && item.tagNbtData.toString() != nbt.get()) return false + return true + } +} + +fun ItemStack.toItem(): Item { + return Item( + material = Optional.ofNullable(type), + amount = Optional.ofNullable(amount), + name = Optional.ofNullable(itemMeta?.displayName()?.asMini()), + lore = Optional.ofNullable(itemMeta?.lore()?.joinToString("\n") { it.asMini() }), +// enchantments = Optional.ofNullable(itemMeta?.enchants), + flags = Optional.ofNullable(itemMeta?.itemFlags?.toList()), + nbt = Optional.ofNullable(tagNbtData.toString()), + ) +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/me/gabber235/typewriter/utils/MiniMessages.kt b/plugin/src/main/kotlin/me/gabber235/typewriter/utils/MiniMessages.kt index 2896679928..b85d4724d2 100644 --- a/plugin/src/main/kotlin/me/gabber235/typewriter/utils/MiniMessages.kt +++ b/plugin/src/main/kotlin/me/gabber235/typewriter/utils/MiniMessages.kt @@ -11,6 +11,8 @@ import org.bukkit.command.CommandSender private val mm = MiniMessage.miniMessage() +fun Component.asMini() = mm.serialize(this) + fun String.asMini() = mm.deserialize(this) fun String.asMiniWithResolvers(vararg resolvers: TagResolver) = mm.deserialize(this, *resolvers)