Skip to content

Commit 3055378

Browse files
committed
Merge AssetEntry and ArtifactEntry documentation
1 parent b12f72c commit 3055378

File tree

6 files changed

+136
-59
lines changed

6 files changed

+136
-59
lines changed

documentation/docs/develop/02-extensions/04-entries/static/artifact.mdx

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
11
import CodeSnippet from "@site/src/components/CodeSnippet";
22

3-
# AssetEntry
4-
The AssetEntry is a specialized interface that extends the `StaticEntry`.
5-
It is primarily used for handling static assets within the game.
6-
Assets can include various types of files such as images, sounds, or other external resources that are crucial to enhancing the game environment and player experience.
7-
The key attribute of AssetEntry is the path, which specifies the location of the asset.
3+
# Asset & Artifact Entries
4+
Assets and artifacts are both handled through similar interfaces that extend `StaticEntry`. Assets are static files like images, sounds, or other external resources, while artifacts are assets that are generated by the server at runtime.
5+
6+
## AssetEntry
7+
The `AssetEntry` is primarily used for handling static assets. Assets can include various types of files such as images, data, or other external resources that can be used by an extension.
8+
9+
## ArtifactEntry
10+
The `ArtifactEntry` is a specialized interface derived from `AssetEntry`. Its primary purpose is to handle artifacts, which are assets generated by the extensions. Unlike standard assets, artifacts are usually dynamic and created during runtime and stored between restarts. This makes them particularly useful for storing data arbitrary configuration data. As artifacts loaded in on reload, they are not suitable for storing real-time data.
811

912
## Usage
10-
Here's a generic example of creating and using an `AssetEntry`:
1113

1214
### Defining an AssetEntry
1315
<CodeSnippet tag="asset_entry" json={require("../../../snippets.json")} />
1416

15-
### Accessing the Artifact's Content
17+
### Defining an ArtifactEntry
18+
<CodeSnippet tag="artifact_entry" json={require("../../../snippets.json")} />
19+
20+
## Accessing Asset & Artifact Content
1621

17-
To get the asset from the entry, you can use the following code:
22+
### Using AssetManager (Traditional Approach)
1823

24+
#### String Content
1925
<CodeSnippet tag="asset_access" json={require("../../../snippets.json")} />
26+
27+
#### Binary Content
28+
<CodeSnippet tag="asset_binary_access" json={require("../../../snippets.json")} />
29+
30+
### Using Helper Methods (Recommended Approach)
31+
32+
Both `AssetEntry` and `ArtifactEntry` also provide convenient helper methods for accessing and storing data:
33+
34+
<CodeSnippet tag="asset_helper_methods" json={require("../../../snippets.json")} />
35+
36+
The same helper methods work for artifacts:
37+
38+
<CodeSnippet tag="artifact_helper_methods" json={require("../../../snippets.json")} />

documentation/plugins/code-snippets/snippets.json

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
},
9494
"dialogue_triggers": {
9595
"file": "src/main/kotlin/com/typewritermc/example/TriggerExample.kt",
96-
"content": " // Next dialogue should be triggered or the current dialogue should complete its typing animation.\n DialogueTrigger.NEXT_OR_COMPLETE.triggerFor(player, context())\n\n // Forces the next dialogue to be triggered, even if the animation hasn't finished.\n DialogueTrigger.FORCE_NEXT.triggerFor(player, context())"
96+
"content": " // Next dialogue should be triggered or the current dialogue should complete its typing animation.\n DialogueTrigger.NEXT_OR_SKIP_ANIMATION.triggerFor(player, context())\n\n // Forces the next dialogue to be triggered, even if the animation hasn't finished.\n DialogueTrigger.FORCE_NEXT.triggerFor(player, context())"
9797
},
9898
"temporal_triggers": {
9999
"file": "src/main/kotlin/com/typewritermc/example/TriggerExample.kt",
@@ -137,11 +137,11 @@
137137
},
138138
"basic_interaction": {
139139
"file": "src/main/kotlin/com/typewritermc/example/entries/interaction/ExampleInteraction.kt",
140-
"content": "class ExampleInteraction(\n val player: Player,\n override val context: InteractionContext,\n override val priority: Int,\n val eventTriggers: List<EventTrigger>\n) : Interaction {\n override suspend fun initialize(): Result<Unit> {\n if (Random.nextBoolean()) {\n // Failing during initialization makes it so that the interaction will be stopped.\n return failure(\"Failed to initialize\")\n }\n\n // Setup your interaction state\n player.sendMessage(\"Starting interaction!\")\n\n return ok(Unit)\n }\n\n override suspend fun tick(deltaTime: Duration) {\n // Update your interaction state\n if (shouldEnd()) {\n // Trigger the stop event when done\n ExampleStopTrigger.triggerFor(player, context)\n }\n }\n\n override suspend fun teardown(force: Boolean) {\n // Cleanup your interaction state\n player.sendMessage(\"Ending interaction!\")\n }\n\n private fun shouldEnd(): Boolean = false // Your end condition\n}"
140+
"content": "class ExampleInteraction(\n val player: Player,\n override val context: InteractionContext,\n override val priority: Int,\n val eventTriggers: List<EventTrigger>\n) : Interaction {\n override suspend fun initialize(): Result<Unit> {\n if (Random.nextBoolean()) {\n // Failing during initialization makes it so that the interaction will be stopped.\n return failure(\"Failed to initialize\")\n }\n\n // Setup your interaction state\n player.sendMessage(\"Starting interaction!\")\n\n return ok(Unit)\n }\n\n override suspend fun tick(deltaTime: Duration) {\n // Update your interaction state\n if (shouldEnd()) {\n // Trigger the stop event when done\n ExampleStopTrigger.triggerFor(player, context)\n }\n }\n\n override suspend fun teardown() {\n // Cleanup your interaction state\n player.sendMessage(\"Ending interaction!\")\n }\n\n private fun shouldEnd(): Boolean = false // Your end condition\n}"
141141
},
142142
"interaction_trigger_handler": {
143143
"file": "src/main/kotlin/com/typewritermc/example/entries/interaction/ExampleInteraction.kt",
144-
"content": "@Singleton // This registers the handler to Typewriter\nclass ExampleTriggerHandler : TriggerHandler {\n override suspend fun trigger(event: Event, currentInteraction: Interaction?): TriggerContinuation {\n // Handle stopping the interaction\n if (ExampleStopTrigger in event && currentInteraction is ExampleInteraction) {\n return TriggerContinuation.Multi(\n TriggerContinuation.EndInteraction,\n TriggerContinuation.Append(Event(event.player, currentInteraction.context, currentInteraction.eventTriggers)),\n )\n }\n\n // Handle starting the interaction\n return tryStartExampleInteraction(event)\n }\n\n private fun tryStartExampleInteraction(\n event: Event\n ): TriggerContinuation {\n // Find all start triggers in the event\n val triggers = event.triggers\n .filterIsInstance<ExampleStartTrigger>()\n\n if (triggers.isEmpty()) return TriggerContinuation.Nothing\n\n // Use the highest priority trigger\n val trigger = triggers.maxBy { it.priority }\n\n // Start the interaction\n return TriggerContinuation.StartInteraction(\n ExampleInteraction(\n event.player,\n event.context,\n trigger.priority,\n trigger.eventTriggers\n )\n )\n }\n}"
144+
"content": "@Singleton // This registers the handler to Typewriter\nclass ExampleTriggerHandler : TriggerHandler {\n override suspend fun trigger(event: Event, currentInteraction: Interaction?): TriggerContinuation {\n // Handle stopping the interaction\n if (ExampleStopTrigger in event && currentInteraction is ExampleInteraction) {\n return TriggerContinuation.Multi(\n TriggerContinuation.EndInteraction,\n TriggerContinuation.Append(\n Event(\n event.player,\n currentInteraction.context,\n currentInteraction.eventTriggers\n )\n ),\n )\n }\n\n // Handle starting the interaction\n return tryStartExampleInteraction(event)\n }\n\n private fun tryStartExampleInteraction(\n event: Event\n ): TriggerContinuation {\n // Find all start triggers in the event\n val triggers = event.triggers\n .filterIsInstance<ExampleStartTrigger>()\n\n if (triggers.isEmpty()) return TriggerContinuation.Nothing\n\n // Use the highest priority trigger\n val trigger = triggers.maxBy { it.priority }\n\n // Start the interaction\n return TriggerContinuation.StartInteraction(\n ExampleInteraction(\n event.player,\n event.context,\n trigger.priority,\n trigger.eventTriggers\n )\n )\n }\n}"
145145
},
146146
"interaction_entry": {
147147
"file": "src/main/kotlin/com/typewritermc/example/entries/interaction/ExampleInteraction.kt",
@@ -225,15 +225,31 @@
225225
},
226226
"artifact_access": {
227227
"file": "src/main/kotlin/com/typewritermc/example/entries/static/ExampleArtifactEntry.kt",
228-
"content": "suspend fun accessArtifactData(ref: Ref<out ArtifactEntry>) {\n val assetManager = KoinJavaComponent.get<AssetManager>(AssetManager::class.java)\n val entry = ref.get() ?: return\n val content: String? = assetManager.fetchAsset(entry)\n // Do something with the content\n}"
228+
"content": "suspend fun accessArtifactData(ref: Ref<out ArtifactEntry>) {\n val assetManager = KoinJavaComponent.get<AssetManager>(AssetManager::class.java)\n val entry = ref.get() ?: return\n val stringContent: String? = assetManager.fetchStringAsset(entry)\n // Do something with the string content\n}"
229+
},
230+
"artifact_binary_access": {
231+
"file": "src/main/kotlin/com/typewritermc/example/entries/static/ExampleArtifactEntry.kt",
232+
"content": "suspend fun accessBinaryArtifactData(ref: Ref<out ArtifactEntry>) {\n val assetManager = KoinJavaComponent.get<AssetManager>(AssetManager::class.java)\n val entry = ref.get() ?: return\n val binaryContent: ByteArray? = assetManager.fetchBinaryAsset(entry)\n // Do something with the binary content\n}"
233+
},
234+
"artifact_helper_methods": {
235+
"file": "src/main/kotlin/com/typewritermc/example/entries/static/ExampleArtifactEntry.kt",
236+
"content": "suspend fun accessArtifactDataUsingHelpers(ref: Ref<out ArtifactEntry>) {\n val entry = ref.get() ?: return\n \n // Check if artifact has data\n if (entry.hasData()) {\n // Access string data using helper method\n val stringContent: String? = entry.stringData()\n \n // Access binary data using helper method\n val binaryContent: ByteArray? = entry.binaryData()\n \n // Store string data\n entry.stringData(\"Updated artifact content\")\n \n // Store binary data\n entry.binaryData(byteArrayOf(1, 2, 3, 4, 5))\n }\n}"
229237
},
230238
"asset_entry": {
231239
"file": "src/main/kotlin/com/typewritermc/example/entries/static/ExampleAssetEntry.kt",
232240
"content": "@Entry(\"example_asset\", \"An example asset entry.\", Colors.BLUE, \"material-symbols:home-storage-rounded\")\nclass ExampleAssetEntry(\n override val id: String = \"\",\n override val name: String = \"\",\n override val path: String = \"\",\n) : AssetEntry"
233241
},
234242
"asset_access": {
235243
"file": "src/main/kotlin/com/typewritermc/example/entries/static/ExampleAssetEntry.kt",
236-
"content": "suspend fun accessAssetData(ref: Ref<out AssetEntry>) {\n val assetManager = KoinJavaComponent.get<AssetManager>(AssetManager::class.java)\n val entry = ref.get() ?: return\n val content: String? = assetManager.fetchAsset(entry)\n // Do something with the content\n}"
244+
"content": "suspend fun accessAssetData(ref: Ref<out AssetEntry>) {\n val assetManager = KoinJavaComponent.get<AssetManager>(AssetManager::class.java)\n val entry = ref.get() ?: return\n val stringContent: String? = assetManager.fetchStringAsset(entry)\n // Do something with the string content\n}"
245+
},
246+
"asset_binary_access": {
247+
"file": "src/main/kotlin/com/typewritermc/example/entries/static/ExampleAssetEntry.kt",
248+
"content": "suspend fun accessBinaryAssetData(ref: Ref<out AssetEntry>) {\n val assetManager = KoinJavaComponent.get<AssetManager>(AssetManager::class.java)\n val entry = ref.get() ?: return\n val binaryContent: ByteArray? = assetManager.fetchBinaryAsset(entry)\n // Do something with the binary content\n}"
249+
},
250+
"asset_helper_methods": {
251+
"file": "src/main/kotlin/com/typewritermc/example/entries/static/ExampleAssetEntry.kt",
252+
"content": "suspend fun accessAssetDataUsingHelpers(ref: Ref<out AssetEntry>) {\n val entry = ref.get() ?: return\n \n // Check if asset has data\n if (entry.hasData()) {\n // Access string data using helper method\n val stringContent: String? = entry.stringData()\n \n // Access binary data using helper method\n val binaryContent: ByteArray? = entry.binaryData()\n \n // Store string data\n entry.stringData(\"Updated content\")\n \n // Store binary data\n entry.binaryData(byteArrayOf(1, 2, 3, 4, 5))\n }\n}"
237253
},
238254
"sound_id_entry": {
239255
"file": "src/main/kotlin/com/typewritermc/example/entries/static/ExampleSoundIdEntry.kt",
@@ -245,7 +261,7 @@
245261
},
246262
"speaker_entry": {
247263
"file": "src/main/kotlin/com/typewritermc/example/entries/static/ExampleSpeakerEntry.kt",
248-
"content": "@Entry(\"example_speaker\", \"An example speaker entry.\", Colors.BLUE, \"ic:round-spatial-audio-off\")\nclass ExampleSpeakerEntry(\n override val id: String = \"\",\n override val name: String = \"\",\n override val displayName: Var<String> = ConstVar(\"\"),\n override val sound: Sound = Sound.EMPTY,\n) : SpeakerEntry"
264+
"content": "@Entry(\"example_speaker\", \"An example speaker entry.\", Colors.BLUE, \"ic:round-spatial-audio-off\")\nclass ExampleSpeakerEntry(\n override val id: String = \"\",\n override val name: String = \"\",\n override val displayName: Var<String> = ConstVar(\"\"),\n override val sound: Var<Sound> = ConstVar(Sound.EMPTY),\n) : SpeakerEntry"
249265
},
250266
"variable_entry": {
251267
"file": "src/main/kotlin/com/typewritermc/example/entries/static/ExampleVariableEntry.kt",
@@ -297,6 +313,14 @@
297313
},
298314
"event_entry_with_context_keys": {
299315
"file": "src/main/kotlin/com/typewritermc/example/entries/trigger/ExampleEventEntry.kt",
300-
"content": "@Entry(\"example_event_with_context_keys\", \"An example event entry with context keys.\", Colors.YELLOW, \"material-symbols:bigtop-updates\")\n// This tells Typewriter that this entry exposes some context\n// highlight-next-line\n@ContextKeys(ExampleContextKeys::class)\nclass ExampleEventEntryWithContextKeys(\n override val id: String = \"\",\n override val name: String = \"\",\n override val triggers: List<Ref<TriggerableEntry>> = emptyList(),\n) : EventEntry\n\n// highlight-start\nenum class ExampleContextKeys(override val klass: KClass<*>) : EntryContextKey {\n // The two `String::class` have to be the same.\n // The @KeyType is for the panel to know\n @KeyType(String::class)\n // The type here is for casting during runtime\n TEXT(String::class),\n\n @KeyType(Int::class)\n NUMBER(Int::class),\n\n // More complex types are also allowed.\n @KeyType(Position::class)\n POSITION(Position::class)\n}\n// highlight-end\n\n@EntryListener(ExampleEventEntryWithContextKeys::class)\nfun onEventAddContext(event: SomeBukkitEvent, query: Query<ExampleEventEntryWithContextKeys>) {\n val entries = query.find()\n // highlight-start\n entries.triggerAllFor(event.player) {\n // Make sure these values are drawn from the event.\n // You MUST supply all the context keys.\n ExampleContextKeys.TEXT withValue \"Hello World\"\n ExampleContextKeys.NUMBER withValue 42\n ExampleContextKeys.POSITION withValue Position.ORIGIN\n }\n // highlight-end\n}"
316+
"content": "@Entry(\n \"example_event_with_context_keys\",\n \"An example event entry with context keys.\",\n Colors.YELLOW,\n \"material-symbols:bigtop-updates\"\n)\n// This tells Typewriter that this entry exposes some context\n// highlight-next-line\n@ContextKeys(ExampleContextKeys::class)\nclass ExampleEventEntryWithContextKeys(\n override val id: String = \"\",\n override val name: String = \"\",\n override val triggers: List<Ref<TriggerableEntry>> = emptyList(),\n) : EventEntry\n\n// highlight-start\nenum class ExampleContextKeys(override val klass: KClass<*>) : EntryContextKey {\n // The two `String::class` have to be the same.\n // The @KeyType is for the panel to know\n @KeyType(String::class)\n // The type here is for casting during runtime\n TEXT(String::class),\n\n @KeyType(Int::class)\n NUMBER(Int::class),\n\n // More complex types are also allowed.\n @KeyType(Position::class)\n POSITION(Position::class)\n}\n// highlight-end\n\n@EntryListener(ExampleEventEntryWithContextKeys::class)\nfun onEventAddContext(event: SomeBukkitEvent, query: Query<ExampleEventEntryWithContextKeys>) {\n val entries = query.find()\n // highlight-start\n entries.triggerAllFor(event.player) {\n // Make sure these values are drawn from the event.\n // You MUST supply all the context keys.\n ExampleContextKeys.TEXT withValue \"Hello World\"\n ExampleContextKeys.NUMBER withValue 42\n ExampleContextKeys.POSITION withValue Position.ORIGIN\n }\n // highlight-end\n}"
317+
},
318+
"cancelable_event_entry": {
319+
"file": "src/main/kotlin/com/typewritermc/example/entries/trigger/ExampleEventEntry.kt",
320+
"content": "@Entry(\"example_cancelable_event\", \"An example cancelable event.\", Colors.YELLOW, \"material-symbols:block\")\nclass ExampleCancelableEventEntry(\n override val id: String = \"\",\n override val name: String = \"\",\n override val triggers: List<Ref<TriggerableEntry>> = emptyList(),\n // highlight-start\n override val cancel: Var<Boolean> = ConstVar(false),\n) : CancelableEventEntry\n// highlight-end"
321+
},
322+
"cancelable_event_listener": {
323+
"file": "src/main/kotlin/com/typewritermc/example/entries/trigger/ExampleEventEntry.kt",
324+
"content": "@EntryListener(ExampleCancelableEventEntry::class)\nfun onCancelableEvent(event: SomeBukkitEvent, query: Query<ExampleCancelableEventEntry>) {\n val entries = query.find().toList()\n entries.triggerAllFor(event.player, context())\n\n // highlight-start\n if (entries.shouldCancel(event.player)) {\n event.isCancelled = true\n }\n // highlight-end\n}"
301325
}
302326
}

0 commit comments

Comments
 (0)