2023-05-05 00:50:02 +03:00
|
|
|
<template>
|
2024-07-26 21:43:06 +03:00
|
|
|
<v-list density="compact">
|
|
|
|
|
<div v-if="isConnected() && sceneLoadingAvailable && appConfig !== null">
|
|
|
|
|
<v-list-subheader>
|
|
|
|
|
<v-icon class="mr-1" color="primary">mdi-folder</v-icon>
|
|
|
|
|
Load
|
|
|
|
|
</v-list-subheader>
|
|
|
|
|
<v-card variant="text">
|
|
|
|
|
<v-card-text>
|
|
|
|
|
<v-autocomplete :disabled="loading" v-model="sceneInput" :items="scenes"
|
|
|
|
|
label="Search scenes" outlined @update:search="updateSearchInput" item-title="label" item-value="path" :loading="sceneSearchLoading" messages="Load previously saved scenes.">
|
|
|
|
|
</v-autocomplete>
|
|
|
|
|
<v-btn class="mt-2" variant="tonal" block :disabled="loading" @click="loadScene('path')" append-icon="mdi-folder" color="primary">Load</v-btn>
|
|
|
|
|
</v-card-text>
|
|
|
|
|
</v-card>
|
|
|
|
|
<v-divider class="mt-3 mb-3"></v-divider>
|
|
|
|
|
<v-list-subheader>
|
|
|
|
|
<v-icon class="mr-1" color="primary">mdi-upload</v-icon>
|
|
|
|
|
Upload
|
|
|
|
|
</v-list-subheader>
|
|
|
|
|
<v-card variant="text">
|
|
|
|
|
<v-card-text>
|
2023-05-05 00:50:02 +03:00
|
|
|
<!-- File input for file upload -->
|
2024-07-26 21:43:06 +03:00
|
|
|
<div class="fixed-file-input-size">
|
|
|
|
|
|
|
|
|
|
<v-file-input
|
|
|
|
|
:disabled="loading"
|
|
|
|
|
prepend-icon=""
|
|
|
|
|
v-model="sceneFile"
|
2025-06-03 12:26:12 +03:00
|
|
|
@update:modelValue="loadScene('file')"
|
2024-07-26 21:43:06 +03:00
|
|
|
label="Drag and Drop file."
|
|
|
|
|
outlined accept="image/*"
|
|
|
|
|
variant="solo-filled"
|
|
|
|
|
messages="Upload a talemate scene or a character card"
|
|
|
|
|
></v-file-input>
|
|
|
|
|
|
2023-05-05 00:50:02 +03:00
|
|
|
</div>
|
2024-07-26 21:43:06 +03:00
|
|
|
</v-card-text>
|
|
|
|
|
</v-card>
|
|
|
|
|
<v-divider class="mt-3 mb-3"></v-divider>
|
|
|
|
|
<!-- create new scene -->
|
|
|
|
|
<v-list-subheader>
|
|
|
|
|
<v-icon class="mr-1" color="primary">mdi-plus</v-icon>
|
|
|
|
|
Create new scene
|
|
|
|
|
</v-list-subheader>
|
|
|
|
|
<v-card variant="text">
|
|
|
|
|
<v-card-text>
|
|
|
|
|
<v-btn class="mt-2" variant="tonal" block :disabled="loading" @click="loadCreative" append-icon="mdi-plus" color="primary">Create</v-btn>
|
|
|
|
|
</v-card-text>
|
|
|
|
|
</v-card>
|
2023-05-05 00:50:02 +03:00
|
|
|
</div>
|
2023-12-02 00:40:14 +02:00
|
|
|
<DefaultCharacter ref="defaultCharacterModal" @save="loadScene" @cancel="loadCanceled"></DefaultCharacter>
|
2024-07-26 21:43:06 +03:00
|
|
|
</v-list>
|
2023-05-05 00:50:02 +03:00
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
2023-12-02 00:40:14 +02:00
|
|
|
import DefaultCharacter from './DefaultCharacter.vue';
|
|
|
|
|
|
2023-05-05 00:50:02 +03:00
|
|
|
export default {
|
|
|
|
|
name: 'LoadScene',
|
2023-12-02 00:40:14 +02:00
|
|
|
components: {
|
|
|
|
|
DefaultCharacter,
|
|
|
|
|
},
|
2024-02-16 13:57:45 +02:00
|
|
|
props: {
|
|
|
|
|
sceneLoadingAvailable: Boolean
|
|
|
|
|
},
|
2024-07-26 21:43:06 +03:00
|
|
|
computed: {
|
|
|
|
|
cols () {
|
|
|
|
|
const { lg, sm } = this.$vuetify.display
|
|
|
|
|
return lg ? [2, 2]
|
|
|
|
|
: sm ? [4, 4]
|
|
|
|
|
: [6, 6]
|
|
|
|
|
},
|
|
|
|
|
},
|
2023-05-05 00:50:02 +03:00
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
loading: false,
|
|
|
|
|
inputMethod: 'path',
|
|
|
|
|
sceneFile: [],
|
|
|
|
|
sceneInput: '',
|
|
|
|
|
scenes: [],
|
|
|
|
|
sceneSearchInput: null,
|
|
|
|
|
sceneSearchLoading: false,
|
2023-11-10 22:45:50 +02:00
|
|
|
sceneSaved: null,
|
2023-05-05 00:50:02 +03:00
|
|
|
expanded: true,
|
2023-12-02 00:40:14 +02:00
|
|
|
appConfig: null, // Store the app configuration
|
2023-05-05 00:50:02 +03:00
|
|
|
}
|
|
|
|
|
},
|
2023-12-08 22:57:44 +02:00
|
|
|
emits: {
|
|
|
|
|
loading: null,
|
|
|
|
|
},
|
2024-02-16 13:57:45 +02:00
|
|
|
inject: ['getWebsocket', 'registerMessageHandler', 'isConnected'],
|
2023-05-05 00:50:02 +03:00
|
|
|
methods: {
|
2023-12-02 00:40:14 +02:00
|
|
|
// Method to show the DefaultCharacter modal
|
|
|
|
|
showDefaultCharacterModal() {
|
|
|
|
|
this.$refs.defaultCharacterModal.open();
|
|
|
|
|
},
|
|
|
|
|
|
2023-05-05 00:50:02 +03:00
|
|
|
toggle() {
|
|
|
|
|
this.expanded = !this.expanded;
|
|
|
|
|
},
|
|
|
|
|
updateSearchInput(val) {
|
|
|
|
|
this.sceneSearchInput = val;
|
|
|
|
|
clearTimeout(this.searchTimeout); // Clear the previous timeout
|
|
|
|
|
this.searchTimeout = setTimeout(this.fetchScenes, 300); // Start a new timeout
|
|
|
|
|
},
|
|
|
|
|
fetchScenes() {
|
|
|
|
|
if (!this.sceneSearchInput)
|
|
|
|
|
return
|
|
|
|
|
this.sceneSearchLoading = true;
|
|
|
|
|
this.getWebsocket().send(JSON.stringify({ type: 'request_scenes_list', query: this.sceneSearchInput }));
|
|
|
|
|
},
|
|
|
|
|
loadCreative() {
|
2023-11-24 22:08:13 +02:00
|
|
|
if(this.sceneSaved === false) {
|
|
|
|
|
if(!confirm("The current scene is not saved. Are you sure you want to load a new scene?")) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-05 00:50:02 +03:00
|
|
|
this.loading = true;
|
2024-07-26 21:43:06 +03:00
|
|
|
this.getWebsocket().send(JSON.stringify({ type: 'load_scene', file_path: "$NEW_SCENE$" }));
|
2023-05-05 00:50:02 +03:00
|
|
|
},
|
2023-12-02 00:40:14 +02:00
|
|
|
loadCanceled() {
|
|
|
|
|
console.log("Load canceled");
|
|
|
|
|
this.loading = false;
|
|
|
|
|
this.sceneFile = [];
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-26 21:43:06 +03:00
|
|
|
loadScene(inputMethod) {
|
2023-11-10 22:45:50 +02:00
|
|
|
if(this.sceneSaved === false) {
|
|
|
|
|
if(!confirm("The current scene is not saved. Are you sure you want to load a new scene?")) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-26 21:43:06 +03:00
|
|
|
if(inputMethod) {
|
|
|
|
|
this.inputMethod = inputMethod;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-02 00:40:14 +02:00
|
|
|
this.sceneSaved = null;
|
|
|
|
|
|
2024-07-26 21:43:06 +03:00
|
|
|
console.log("Loading scene", this.inputMethod, this.sceneFile, this.sceneInput)
|
|
|
|
|
|
2025-06-03 12:26:12 +03:00
|
|
|
if (this.inputMethod === 'file' && this.sceneFile) { // Just check if sceneFile exists
|
|
|
|
|
// File is now a direct File object, not an array
|
|
|
|
|
const file = this.sceneFile;
|
|
|
|
|
|
2023-12-02 00:40:14 +02:00
|
|
|
// if file is image check if default character is set
|
2025-06-03 12:26:12 +03:00
|
|
|
if(file.type.startsWith("image/")) {
|
2023-12-02 00:40:14 +02:00
|
|
|
if(!this.appConfig.game.default_player_character.name) {
|
|
|
|
|
this.showDefaultCharacterModal();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.loading = true;
|
2025-06-03 12:26:12 +03:00
|
|
|
|
2023-05-05 00:50:02 +03:00
|
|
|
// Convert the uploaded file to base64
|
|
|
|
|
const reader = new FileReader();
|
2025-06-03 12:26:12 +03:00
|
|
|
reader.readAsDataURL(file);
|
2024-07-26 21:43:06 +03:00
|
|
|
|
|
|
|
|
console.log("Loading scene from file")
|
|
|
|
|
|
2023-05-05 00:50:02 +03:00
|
|
|
reader.onload = () => {
|
2023-12-02 00:40:14 +02:00
|
|
|
this.$emit("loading", true)
|
2023-05-05 00:50:02 +03:00
|
|
|
this.getWebsocket().send(JSON.stringify({
|
|
|
|
|
type: 'load_scene',
|
|
|
|
|
scene_data: reader.result,
|
2025-06-03 12:26:12 +03:00
|
|
|
filename: file.name,
|
2023-05-05 00:50:02 +03:00
|
|
|
}));
|
2025-06-03 12:26:12 +03:00
|
|
|
this.sceneFile = null; // Reset with null instead of empty array
|
2023-05-05 00:50:02 +03:00
|
|
|
};
|
2025-06-03 12:26:12 +03:00
|
|
|
} else if (this.inputMethod === 'path' && this.sceneInput) {
|
2023-12-02 00:40:14 +02:00
|
|
|
// if path ends with .png/jpg/webp check if default character is set
|
|
|
|
|
if(this.sceneInput.endsWith(".png") || this.sceneInput.endsWith(".jpg") || this.sceneInput.endsWith(".webp")) {
|
|
|
|
|
if(!this.appConfig.game.default_player_character.name) {
|
|
|
|
|
this.showDefaultCharacterModal();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.loading = true;
|
|
|
|
|
this.$emit("loading", true)
|
2023-05-05 00:50:02 +03:00
|
|
|
this.getWebsocket().send(JSON.stringify({ type: 'load_scene', file_path: this.sceneInput }));
|
|
|
|
|
this.sceneInput = '';
|
|
|
|
|
}
|
|
|
|
|
},
|
2024-01-26 12:42:21 +02:00
|
|
|
|
|
|
|
|
loadJsonSceneFromPath(path) {
|
|
|
|
|
this.loading = true;
|
|
|
|
|
this.$emit("loading", true)
|
|
|
|
|
this.getWebsocket().send(JSON.stringify({ type: 'load_scene', file_path: path }));
|
|
|
|
|
},
|
|
|
|
|
|
2023-05-05 00:50:02 +03:00
|
|
|
handleMessage(data) {
|
2023-12-02 00:40:14 +02:00
|
|
|
// Handle app configuration
|
|
|
|
|
if (data.type === 'app_config') {
|
|
|
|
|
this.appConfig = data.data;
|
|
|
|
|
console.log("App config", this.appConfig);
|
|
|
|
|
}
|
2023-05-05 00:50:02 +03:00
|
|
|
|
|
|
|
|
// Scene loaded
|
|
|
|
|
if (data.type === "system") {
|
|
|
|
|
if (data.id === 'scene.loaded') {
|
|
|
|
|
this.loading = false;
|
|
|
|
|
this.expanded = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle scenes_list message type
|
|
|
|
|
if (data.type === 'scenes_list') {
|
|
|
|
|
this.scenes = data.data;
|
|
|
|
|
this.sceneSearchLoading = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-10 22:45:50 +02:00
|
|
|
// Handle scene status
|
|
|
|
|
if (data.type == "scene_status") {
|
|
|
|
|
this.sceneSaved = data.data.saved;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-02 00:40:14 +02:00
|
|
|
},
|
2023-05-05 00:50:02 +03:00
|
|
|
},
|
|
|
|
|
created() {
|
|
|
|
|
this.registerMessageHandler(this.handleMessage);
|
|
|
|
|
},
|
|
|
|
|
mounted() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
2024-07-26 21:43:06 +03:00
|
|
|
<style>
|
|
|
|
|
.fixed-file-input-size div.v-input__details {
|
|
|
|
|
align-items: flex-start !important;
|
|
|
|
|
}
|
2023-05-05 00:50:02 +03:00
|
|
|
</style>
|