@@ -6,15 +6,25 @@ globalThis.Underline = config.globalObjects;
66const Discord = require ( "discord.js" ) ;
77const chillout = require ( "chillout" ) ;
88const path = require ( "path" ) ;
9+ const fs = require ( "fs" ) ;
910const readdirRecursive = require ( "recursive-readdir" ) ;
1011const { makeSureFolderExists } = require ( "stuffs" ) ;
1112const client = new Discord . Client ( config . clientOptions ) ;
1213const interactions = new Discord . Collection ( ) ;
1314const events = new Discord . Collection ( ) ;
1415const locales = new Discord . Collection ( ) ;
16+ const { quickMap, quickForEach } = require ( "async-and-quick" ) ;
1517let interactionFiles ;
1618let eventFiles ;
1719let localeFiles ;
20+ let pluginFiles ;
21+ let onFunctions = {
22+ onInteractionBeforeChecks : [ config . onInteractionBeforeChecks ] ,
23+ onInteraction : [ config . onInteraction ] ,
24+ onAfterInteraction : [ config . onAfterInteraction ] ,
25+ onEvent : [ config . onEvent ] ,
26+ onAfterEvent : [ config . onAfterEvent ]
27+ } ;
1828globalThis . Underline = {
1929 ...config . globalObjects ,
2030 config,
@@ -24,6 +34,7 @@ globalThis.Underline = {
2434 events,
2535 locales,
2636 utils,
37+ plugins : { } ,
2738 _references : new Discord . Collection ( ) ,
2839 Interaction : require ( './types/Interaction' ) ,
2940 Event : require ( './types/Event' ) ,
@@ -35,6 +46,36 @@ globalThis.Underline = {
3546 Locale : require ( "./types/Locale" ) ,
3647}
3748
49+ const extractZip = require ( "extract-zip" ) ;
50+
51+ async function getPluginFilePaths ( ) {
52+ let pluginsPath = path . resolve ( "./plugins" ) ;
53+ await makeSureFolderExists ( pluginsPath ) ;
54+ let folderOrZips = await fs . promises . readdir ( pluginsPath , { withFileTypes : true } ) ;
55+ let result = [ ] ;
56+ for ( let i = 0 ; i < folderOrZips . length ; i ++ ) {
57+ const folderOrZip = folderOrZips [ i ] ;
58+ if ( folderOrZip . isDirectory ( ) ) {
59+ if ( folderOrZip . name . startsWith ( "-" ) ) continue ;
60+ result . push ( path . resolve ( pluginsPath , folderOrZip . name , "index.js" ) ) ;
61+ } else if ( folderOrZip . name . endsWith ( ".up.js" ) ) {
62+ if ( folderOrZip . name . startsWith ( "-" ) ) continue ;
63+ result . push ( path . resolve ( pluginsPath , folderOrZip . name ) ) ;
64+ } else if ( folderOrZip . name . endsWith ( ".up.zip" ) ) {
65+ let folderPath = path . resolve ( pluginsPath , folderOrZip . name . replace ( ".up.zip" , ".up" ) ) ;
66+ let zipPath = path . resolve ( pluginsPath , folderOrZip . name ) ;
67+
68+ await fs . promises . rmdir ( folderPath , { recursive : true } ) . catch ( ( ) => { } ) ;
69+ await makeSureFolderExists ( folderPath ) ;
70+ await extractZip ( zipPath , { dir : folderPath } ) ;
71+ fs . promises . unlink ( zipPath ) . catch ( ( ) => null ) ;
72+ if ( folderOrZip . name . startsWith ( "-" ) ) continue ;
73+ result . push ( path . resolve ( folderPath , "index.js" ) ) ;
74+ }
75+ }
76+ return result ;
77+ }
78+
3879async function getEventFilePaths ( ) {
3980 let eventsPath = path . resolve ( "./events" ) ;
4081 await makeSureFolderExists ( eventsPath ) ;
@@ -72,6 +113,15 @@ async function getLocaleFilePaths() {
72113let eventListeners = [ ] ;
73114
74115async function load ( ) {
116+
117+ onFunctions = {
118+ onInteractionBeforeChecks : [ config . onInteractionBeforeChecks ] ,
119+ onInteraction : [ config . onInteraction ] ,
120+ onAfterInteraction : [ config . onAfterInteraction ] ,
121+ onEvent : [ config . onEvent ] ,
122+ onAfterEvent : [ config . onAfterEvent ]
123+ } ;
124+
75125 let loadStart = Date . now ( ) ;
76126 console . debug ( `[HATA AYIKLAMA] Yüklemeye başlandı!` ) ;
77127
@@ -93,6 +143,56 @@ async function load() {
93143 console . info ( `[BİLGİ] "${ locale . locale } " dili yüklendi. (${ Date . now ( ) - start } ms sürdü.)` ) ;
94144 } )
95145
146+ pluginFiles = await getPluginFilePaths ( ) ;
147+ await chillout . forEach ( pluginFiles , ( pluginFile ) => {
148+ let start = Date . now ( ) ;
149+ let rltPath = path . relative ( __dirname , pluginFile ) ;
150+ console . info ( `[BİLGİ] "${ rltPath } " konumundaki plugin yükleniyor..` )
151+ /** @type {import("./types/Plugin") } */
152+ let plugin = require ( pluginFile ) ;
153+ let isReady = false ;
154+
155+ if ( plugin . _type != "plugin" )
156+ return console . warn ( `[UYARI] "${ rltPath } " plugin dosyası boş. Atlanıyor..` ) ;
157+
158+ if ( Underline . plugins [ plugin . namespace ] )
159+ return console . warn ( `[UYARI] ${ plugin . name } plugini zaten yüklenmiş. Atlanıyor..` ) ;
160+
161+ const pluginApi = { } ;
162+
163+ pluginApi . ready = async ( ) => {
164+ if ( isReady ) throw new Error ( "Plugin already ready!" )
165+ isReady = true ;
166+ }
167+
168+ Underline . plugins [ plugin . namespace ] = { } ;
169+
170+ pluginApi . define = ( name , value ) => {
171+ Underline . plugins [ plugin . namespace ] [ name ] = value ;
172+ }
173+
174+ pluginApi . emit = ( name , ...args ) => {
175+ client . emit ( `${ plugin . namespace } :${ name } ` , ...args ) ;
176+ }
177+
178+ pluginApi . onInteractionBeforeChecks = onFunctions . onInteractionBeforeChecks . push ;
179+ pluginApi . onInteraction = onFunctions . onInteraction . push ;
180+ pluginApi . onAfterInteraction = onFunctions . onAfterInteraction . push ;
181+
182+ pluginApi . onEvent = onFunctions . onEvent . push ;
183+ pluginApi . onAfterEvent = onFunctions . onAfterEvent . push ;
184+
185+ pluginApi . client = client ;
186+
187+ plugin . onLoad ( pluginApi ) ;
188+ await chillout . waitUntil ( ( ) => {
189+ if ( isReady ) return chillout . StopIteration ;
190+ } )
191+
192+ console . info ( `[BİLGİ] "${ plugin . name } " plugini yüklendi. (${ Date . now ( ) - start } ms sürdü.)` ) ;
193+ } )
194+
195+
96196
97197 interactionFiles = await getInteractionFilePaths ( ) ;
98198 await chillout . forEach ( interactionFiles , ( interactionFile ) => {
@@ -239,16 +339,16 @@ async function load() {
239339
240340 let other = { } ;
241341
242- let before = await Underline . config . onEvent ( eventName , args , other ) ;
243- if ( ! before ) return ;
342+ let before = ( await quickMap ( onFunctions . onEvent , async ( func ) => { return await func ( eventName , args , other ) ; } ) ) . findIndex ( v => v === false ) ;
343+ if ( before != - 1 ) return ;
244344 args . push ( other ) ;
245345 chillout . forEach ( events ,
246346 /** @param {import("./types/Event") } event */
247347 ( event ) => {
248348 if ( ! event . disabled ) {
249349 try {
250350 event . onEvent ( ...args ) ;
251- Underline . config . onAfterEvent ( eventName , args , other ) ;
351+ quickForEach ( onFunctions . onAfterEvent , async ( func ) => { func ( ... args ) ; } ) ;
252352 } catch ( err ) {
253353 if ( Underline . config . debugLevel >= 1 ) {
254354 console . error ( `[HATA] "${ event . id } " idli ve "${ eventName } " isimli olayda bir hata oluştu!` ) ;
@@ -290,6 +390,9 @@ async function unload() {
290390 console . debug ( `[HATA AYIKLAMA] Önbellek temizle işlemi başladı.` ) ;
291391 let unloadStart = Date . now ( ) ;
292392
393+ console . info ( `[BILGI] Plugin listesi temizleniyor..` ) ;
394+ Underline . plugins = { } ;
395+
293396 console . info ( `[BILGI] İnteraksiyon listesi temizleniyor..` ) ;
294397 Underline . interactions . clear ( ) ;
295398
@@ -305,7 +408,7 @@ async function unload() {
305408 console . info ( `[BILGI] Dil listesi temizleniyor..` ) ;
306409 Underline . locales . clear ( ) ;
307410
308- let pathsToUnload = [ ...interactionFiles , ...eventFiles , ...localeFiles ] ;
411+ let pathsToUnload = [ ...interactionFiles , ...eventFiles , ...localeFiles , ... pluginFiles ] ;
309412
310413 await chillout . forEach ( pathsToUnload , async ( pathToUnload ) => {
311414 console . info ( `[BILGI] Modül "${ path . relative ( __dirname , pathToUnload ) } " önbellekten kaldırılıyor!` ) ;
@@ -421,8 +524,8 @@ client.on("interactionCreate", async (interaction) => {
421524 }
422525
423526 {
424- let shouldRun1 = await config . onInteractionBeforeChecks ( uInter , interaction , other ) ;
425- if ( ! shouldRun1 ) return ;
527+ let shouldRun1 = ( await quickMap ( onFunctions . onInteractionBeforeChecks , async ( func ) => { return await func ( uInter , interaction , other ) ; } ) ) . findIndex ( v => v === false ) ;
528+ if ( shouldRun1 != - 1 ) return ;
426529 }
427530
428531 if ( uInter . disabled ) {
@@ -483,6 +586,7 @@ client.on("interactionCreate", async (interaction) => {
483586 await interaction . update ( ) . catch ( Underline . config . debugLevel >= 2 ? console . error : ( ) => { } ) ;
484587 // await utils.nullDefer(interaction);
485588 interaction . deferReply = newDefer ;
589+ let key = converter [ k ] ;
486590 interaction . reply = interaction . editReply = interaction . followUp = ( ) => {
487591 if ( Underline . config . debugLevel >= 1 ) console . warn ( `[UYARI] "${ uInter . name [ 0 ] } " adlı interaksiyon için "reply" umursanmadı, interaksiyona zaten otomatik olarak boş cevap verilmiş.` ) ;
488592 } ;
@@ -508,7 +612,6 @@ client.on("interactionCreate", async (interaction) => {
508612 let now = Date . now ( ) ;
509613
510614 for ( let k in converter ) {
511- let key = converter [ k ] ;
512615 let keyCooldown = uInter . coolDowns . get ( key ) ;
513616 if ( now < keyCooldown ) {
514617 config . userErrors . coolDown ( interaction , uInter , keyCooldown - now , k , other ) ;
@@ -540,15 +643,14 @@ client.on("interactionCreate", async (interaction) => {
540643 ( async ( ) => {
541644
542645 {
543- let shouldRun2 = await config . onInteraction ( uInter , interaction , other ) ;
544- if ( ! shouldRun2 ) return ;
646+ let shouldRun2 = ( await quickMap ( onFunctions . onInteraction , async ( func ) => { try { return await func ( uInter , interaction , other ) ; } catch ( e ) { onfig . debugLevel > 2 ? console . error ( e ) : null ; } } ) ) . findIndex ( v => v === false ) ;
647+ if ( shouldRun2 != - 1 ) return ;
545648 }
546649
547650 try {
548651
549652 await uInter . onInteraction ( interaction , other ) ;
550-
551- await config . onAfterInteraction ( uInter , interaction , other ) ;
653+ quickForEach ( onFunctions . onAfterInteraction , async ( func ) => { try { func ( uInter , interaction , other ) ?. catch ( config . debugLevel > 2 ? console . error : ( ) => null ) ; } catch ( err ) { ( config . debugLevel > 2 ? console . error : ( ) => null ) ( err ) } } )
552654
553655 } catch ( err ) {
554656 if ( Underline . config . debugLevel >= 1 ) {
0 commit comments