11// Script example for ScriptAPI
22// Author: Jayly <https://github.com/JaylyDev>
33// Project: https://github.com/JaylyDev/ScriptAPI
4- var _a , _b , _c ;
4+ var _a ;
55// Script example for ScriptAPI
66// Author: Jayly <https://github.com/JaylyDev>
77// Project: https://github.com/JaylyDev/ScriptAPI
@@ -14,138 +14,156 @@ const str = () => ('00000000000000000' + (Math.random() * 0xffffffffffffffff).to
1414 * @beta
1515 */
1616const uuid = ( ) => {
17- const a = str ( ) ;
18- const b = str ( ) ;
19- return a . slice ( 0 , 8 ) + '-' + a . slice ( 8 , 12 ) + '-4' + a . slice ( 13 ) + '-a' + b . slice ( 1 , 4 ) + '-' + b . slice ( 4 ) ;
17+ const [ a , b ] = [ str ( ) , str ( ) ] ;
18+ return `${ a . slice ( 0 , 8 ) } -${ a . slice ( 8 , 12 ) } -4${ a . slice ( 13 ) } -a${ b . slice ( 1 , 4 ) } -${ b . slice ( 4 ) } ` ;
2019} ;
21- /**
22- * an insecure but simple text cipher/decipher utility.
23- */
24- const cipher = {
25- cipher ( salt ) {
26- const textToChars = ( text ) => text . split ( '' ) . map ( c => c . charCodeAt ( 0 ) ) ;
27- const byteHex = ( n ) => ( "0" + Number ( n ) . toString ( 16 ) ) . substr ( - 2 ) ;
28- const applySaltToChar = ( code ) => textToChars ( salt ) . reduce ( ( a , b ) => a ^ b , code ) ;
29- return ( text ) => text . split ( '' )
30- . map ( textToChars )
31- . map ( applySaltToChar )
32- . map ( byteHex )
33- . join ( '' ) ;
34- } ,
35- decipher ( salt ) {
36- const textToChars = ( text ) => text . split ( '' ) . map ( ( c ) => c . charCodeAt ( 0 ) ) ;
37- const applySaltToChar = ( code ) => textToChars ( salt ) . reduce ( ( a , b ) => a ^ b , code ) ;
38- return ( encoded ) => encoded . match ( / .{ 1 , 2 } / g)
39- . map ( hex => parseInt ( hex , 16 ) )
40- . map ( applySaltToChar )
41- . map ( charCode => String . fromCharCode ( charCode ) )
42- . join ( '' ) ;
20+ const allowedTypes = [ "string" , "number" , "boolean" ] ;
21+ function encrypt ( data , salt ) {
22+ const encryptedChars = [ ] ;
23+ for ( let i = 0 ; i < data . length ; i ++ ) {
24+ const charCode = data . charCodeAt ( i ) + salt . charCodeAt ( i % salt . length ) ;
25+ encryptedChars . push ( charCode ) ;
4326 }
44- } ;
27+ return String . fromCharCode ( ...encryptedChars ) ;
28+ }
29+ function decrypt ( encrypted , salt ) {
30+ const decryptedChars = [ ] ;
31+ for ( let i = 0 ; i < encrypted . length ; i ++ ) {
32+ const charCode = encrypted . charCodeAt ( i ) - salt . charCodeAt ( i % salt . length ) ;
33+ decryptedChars . push ( charCode ) ;
34+ }
35+ return String . fromCharCode ( ...decryptedChars ) ;
36+ }
4537/**
4638 * Parse and stringify scoreboard display name
4739 * @beta
4840 */
49- const DisplayName = new ( _b = class DisplayName {
50- constructor ( ) {
51- this [ _a ] = DisplayName . name ;
41+ const DisplayName = {
42+ parse ( text , salt ) {
43+ try {
44+ const a = JSON . parse ( `"${ salt ? decrypt ( text , salt ) : text } "` ) ;
45+ return JSON . parse ( `{${ a } }` ) ;
5246 }
53- parse ( text , salt ) {
54- try {
55- const d = cipher . decipher ( salt ) ;
56- const c = d ( text ) ;
57- const a = JSON . parse ( `"${ c } "` ) ; // "key":"value"
58- const b = JSON . parse ( `{${ a } }` ) ; // {"key":"value"}
59- return b ;
60- }
61- catch ( error ) {
62- console . error ( error ) ;
63- return { } ;
64- }
65- }
66- stringify ( value , salt ) {
67- const d = cipher . cipher ( salt ) ;
68- const rawtext = JSON . stringify ( JSON . stringify ( value ) . slice ( 1 , - 1 ) ) . slice ( 1 , - 1 ) ;
69- return d ( rawtext ) ;
47+ catch ( error ) {
48+ throw new Error ( `Failed to parse JSON data: ${ error . message } ` ) ;
7049 }
7150 } ,
72- _a = Symbol . toStringTag ,
73- _b ) ( ) ;
51+ stringify ( value , salt ) {
52+ try {
53+ const a = JSON . stringify ( JSON . stringify ( value ) . slice ( 1 , - 1 ) ) . slice ( 1 , - 1 ) ;
54+ return salt ? encrypt ( a , salt ) : a ;
55+ }
56+ catch ( error ) {
57+ throw new Error ( `Failed to stringify JSON data: ${ error . message } ` ) ;
58+ }
59+ }
60+ } ;
61+ const overworld = world . getDimension ( "overworld" ) ;
62+ ;
7463/**
7564 * Database using scoreboard
7665 * @beta
7766 */
7867class JaylyDB {
79- constructor ( id ) {
80- this [ _c ] = JaylyDB . name ;
81- this . objective = world . scoreboard . getObjective ( `jaylydb:` + id ) ?? world . scoreboard . addObjective ( `jaylydb:` + id , uuid ( ) ) ;
68+ get salt ( ) {
69+ return this . encrypted ? this . objective . displayName : undefined ;
8270 }
8371 ;
84- getParticipant ( key ) {
85- return this . objective . getParticipants ( ) . find ( participant => participant . type === ScoreboardIdentityType . fakePlayer
86- && key in DisplayName . parse ( participant . displayName , this . objective . displayName ) ) ;
72+ findParticipant ( key , getOptions ) {
73+ let data ;
74+ let participant ;
75+ this . displayNames . find ( displayName => {
76+ const displayData = DisplayName . parse ( displayName , this . salt ) ;
77+ if ( ! ( key in displayData ) )
78+ return false ;
79+ if ( getOptions . data )
80+ data = displayData ;
81+ if ( getOptions . participant )
82+ participant = this . objective . getParticipants ( ) . find ( ( participant ) => participant . displayName === displayName ) ;
83+ return true ;
84+ } ) ;
85+ if ( ! data )
86+ return ;
87+ return { data, participant } ;
8788 }
8889 ;
90+ updateParticipants ( ) {
91+ this . participants = this . objective . getParticipants ( ) . filter ( ( participant ) => participant . type === ScoreboardIdentityType . fakePlayer ) ;
92+ this . displayNames = this . participants . map ( ( participant ) => participant . displayName ) ;
93+ this . displayKeys = this . displayNames . map ( ( displayName ) => Object . keys ( DisplayName . parse ( displayName , this . salt ) ) [ 0 ] ) ;
94+ }
95+ constructor ( id , encrypted = false ) {
96+ this [ _a ] = JaylyDB . name ;
97+ this . objective = world . scoreboard . getObjective ( `jaylydb:` + id ) ?? world . scoreboard . addObjective ( `jaylydb:` + id , uuid ( ) ) ;
98+ this . encrypted = encrypted ;
99+ this . updateParticipants ( ) ;
100+ }
101+ get size ( ) {
102+ return this . participants . length ;
103+ }
89104 clear ( ) {
90- this . objective . getParticipants ( ) . forEach ( this . objective . removeParticipant ) ;
105+ this . participants . forEach ( this . objective . removeParticipant ) ;
106+ this . updateParticipants ( ) ;
91107 }
92108 delete ( key ) {
93- const participant = this . getParticipant ( key ) ;
94- if ( ! participant )
95- return ;
96- return this . objective . removeParticipant ( participant ) ;
109+ const scoreboard = this . findParticipant ( key , {
110+ participant : true ,
111+ data : false
112+ } ) ;
113+ if ( ! scoreboard )
114+ return false ;
115+ const success = this . objective . removeParticipant ( scoreboard . participant ) ;
116+ this . updateParticipants ( ) ;
117+ return success ;
97118 }
98119 forEach ( callbackfn ) {
99- for ( const [ key , value ] of this . entries ( ) ) {
120+ for ( const [ key , value ] of this . entries ( ) )
100121 callbackfn ( value , key , this ) ;
101- }
102122 }
103123 get ( key ) {
104- const participant = this . getParticipant ( key ) ;
105- return DisplayName . parse ( participant . displayName , this . objective . displayName ) [ key ] ;
124+ const scoreboard = this . findParticipant ( key , {
125+ participant : false ,
126+ data : true
127+ } ) ;
128+ if ( ! scoreboard )
129+ return ;
130+ return scoreboard . data [ key ] ;
106131 }
107132 has ( key ) {
108- const participant = this . getParticipant ( key ) ;
109- return ! ! participant ;
133+ return this . displayKeys . includes ( key ) ;
110134 }
111135 set ( key , value ) {
112- const allowedTypes = [ "string" , "number" , "boolean" ] ;
113136 if ( ! allowedTypes . includes ( typeof ( value ) ) )
114137 throw TypeError ( "JaylyDB::set only accepts value of string, number, or boolean." ) ;
138+ if ( this . get ( key ) === value )
139+ return this ; // No need to update if value hasn't changed
115140 // throws error if string value is over 32767
116- if ( typeof ( value ) === "string" && value . length > 32767 )
117- throw RangeError ( "JaylyDB::set only accepts string value of length less than 32767." ) ;
141+ const str = DisplayName . stringify ( { [ key ] : value } , this . salt ) ;
142+ if ( str . length > 32767 )
143+ throw RangeError ( "JaylyDB::set only accepts string value less than 32767 characters." ) ;
118144 this . delete ( key ) ;
119- world . getDimension ( "overworld" ) . runCommand ( `scoreboard players set "${ DisplayName . stringify ( { [ key ] : value } , this . objective . displayName ) } " ${ this . objective . id } 0` ) ;
145+ overworld . runCommand ( `scoreboard players set "${ str } " ${ this . objective . id } 0` ) ;
146+ this . updateParticipants ( ) ;
120147 return this ;
121148 }
122- get size ( ) {
123- return this . objective . getParticipants ( ) . length ;
124- }
125- ;
126149 * entries ( ) {
127- const values = this . objective . getParticipants ( ) ;
128- for ( const value of values ) {
129- const valueObject = DisplayName . parse ( value . displayName , this . objective . displayName ) ;
130- const valueLength = DisplayName . stringify ( valueObject , this . objective . displayName ) . length ;
131- if ( valueLength > 0 )
132- yield [ Object . keys ( valueObject ) [ 0 ] , Object . values ( valueObject ) [ 0 ] ] ;
150+ for ( const displayName of this . displayNames ) {
151+ const valueObject = DisplayName . parse ( displayName , this . salt ) ;
152+ yield [ Object . keys ( valueObject ) [ 0 ] , Object . values ( valueObject ) [ 0 ] ] ;
133153 }
134154 }
135155 * keys ( ) {
136- for ( const [ key ] of this . entries ( ) ) {
156+ for ( const [ key ] of this . entries ( ) )
137157 yield key ;
138- }
139158 }
140159 * values ( ) {
141- for ( const [ , value ] of this . entries ( ) ) {
160+ for ( const [ , value ] of this . entries ( ) )
142161 yield value ;
143- }
144162 }
145163 [ Symbol . iterator ] ( ) {
146164 return this . entries ( ) ;
147165 }
148166}
149- _c = Symbol . toStringTag ;
167+ _a = Symbol . toStringTag ;
150168;
151169export { JaylyDB } ;
0 commit comments