1
- var _a ;
2
1
// Script example for ScriptAPI
3
2
// Author: Jayly <https://github.com/JaylyDev>
4
3
// Project: https://github.com/JaylyDev/ScriptAPI
5
- import { ScoreboardIdentityType , world } from "@minecraft/server" ;
6
- const version = "1.0.5" ;
4
+ var _a ;
5
+ /*!
6
+ * Copyright (c) Jayly. All rights reserved.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to
10
+ * deal in the Software without restriction, including without limitation the
11
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12
+ * sell copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24
+ * IN THE SOFTWARE.
25
+ */
26
+ import { ScoreboardIdentityType , system , world } from "@minecraft/server" ;
27
+ const version = "1.0.7" ;
7
28
const str = ( ) => ( '00000000000000000' + ( Math . random ( ) * 0xffffffffffffffff ) . toString ( 16 ) ) . slice ( - 16 ) ;
8
29
/**
9
30
* A rough mechanism for create a random uuid. Not as secure as uuid without as much of a guarantee of uniqueness,
@@ -33,7 +54,7 @@ const decrypt = (encrypted, salt) => {
33
54
return String . fromCharCode ( ...decryptedChars ) ;
34
55
} ;
35
56
const CreateCrashReport = ( action , data , error , salt ) => {
36
- console . log ( "[JaylyDB] Failed to " + action + " JSON data." , "\nVersion: " + version , "\nData: " + data , "\nSalt: " + salt , "\nError: " + error . message , "\n" + error . stack ) ;
57
+ console . warn ( "[JaylyDB] Failed to " + action + " JSON data." , "\nVersion: " + version , "\nData: " + data , "\nSalt: " + salt , "\nError: " + error . message , "\n" + error . stack ) ;
37
58
throw new Error ( `Failed to ${ action } data. Please check content log file for more info.\n` ) ;
38
59
} ;
39
60
/**
@@ -65,19 +86,37 @@ const overworld = world.getDimension("overworld");
65
86
* A simple database for storing data in a Minecraft world, using scoreboard.
66
87
*/
67
88
class JaylyDB {
68
- /** @internal */
69
- get salt ( ) {
70
- return this . encrypted ? this . objective . displayName : undefined ;
71
- }
72
- ;
73
89
/** @internal */
74
90
updateParticipants ( ) {
91
+ const id = this . objective . id . substring ( this . objective . id . indexOf ( ":" ) + 1 ) ;
92
+ if ( this . tempCache . size <= 0 && this . warningSent === true ) {
93
+ console . warn ( `[JaylyDB] Database '${ id } ' has written data to world. It is now safe to exit the world.` ) ;
94
+ this . warningSent = false ;
95
+ }
96
+ else if ( this . tempCache . size > 0 && this . warningSent === false ) {
97
+ console . warn ( `[JaylyDB] Database '${ id } ' is writing data to world. Please wait until the process is completed before exiting the world.` ) ;
98
+ this . warningSent = true ;
99
+ }
100
+ ;
101
+ try {
102
+ for ( const [ key , value ] of this . tempCache . entries ( ) ) {
103
+ overworld . runCommandAsync ( `scoreboard players set "${ value } " ${ this . objective . id } 0` ) ;
104
+ this . tempCache . delete ( key ) ;
105
+ }
106
+ ;
107
+ }
108
+ catch ( error ) {
109
+ if ( error . message !== "Runtime failure, command queue is full." )
110
+ throw error ;
111
+ }
112
+ ;
75
113
this . participants . clear ( ) ;
76
114
for ( const participant of this . objective . getParticipants ( ) ) {
77
115
if ( participant . type !== ScoreboardIdentityType . fakePlayer )
78
116
continue ;
79
117
this . participants . set ( Object . keys ( DisplayName . parse ( participant . displayName , this . salt ) ) [ 0 ] , participant ) ;
80
118
}
119
+ ;
81
120
}
82
121
/**
83
122
* @param id An identifier for the database
@@ -87,11 +126,23 @@ class JaylyDB {
87
126
/** @internal */
88
127
this . participants = new Map ( ) ;
89
128
/** @internal */
90
- this . displayDataCache = new Map ( ) ;
129
+ this . localCache = new Map ( ) ;
130
+ /** @internal */
131
+ this . warningSent = false ;
132
+ /**
133
+ * Internal cache object to allow data to write from memory to scoreboard every tick interval.
134
+ * This is done to prevent multiple values written to a same key to scoreboard each operation.
135
+ * @internal
136
+ */
137
+ this . tempCache = new Map ( ) ;
91
138
this [ _a ] = JaylyDB . name ;
92
139
this . objective = world . scoreboard . getObjective ( "jaylydb:" + id ) ?? world . scoreboard . addObjective ( "jaylydb:" + id , uuid ( ) ) ;
93
140
this . encrypted = encrypted ;
141
+ this . salt = this . encrypted ? this . objective . displayName : undefined ;
142
+ // Fetch all data when database initialize
94
143
this . updateParticipants ( ) ;
144
+ // This function queues the data to be written to the scoreboard every second interval.
145
+ system . runInterval ( ( ) => this . updateParticipants ( ) ) ;
95
146
}
96
147
/**
97
148
* @returns the number of elements in the database.
@@ -115,6 +166,7 @@ class JaylyDB {
115
166
return false ;
116
167
const success = this . objective . removeParticipant ( participant ) ;
117
168
this . participants . delete ( key ) ;
169
+ this . localCache . delete ( key ) ;
118
170
return success ;
119
171
}
120
172
/**
@@ -127,50 +179,43 @@ class JaylyDB {
127
179
/**
128
180
* Returns a specified element from the database.
129
181
* @param key The key of the element to return.
130
- * @param reloadCache If set to true, the database object reloads cache before returning the element. This is made for when the database is modified from a external source.
131
182
* @returns Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.
132
183
*/
133
- get ( key , reloadCache = false ) {
134
- if ( ! reloadCache && this . displayDataCache . has ( key ) )
135
- return this . displayDataCache . get ( key ) ;
184
+ get ( key ) {
185
+ if ( this . localCache . has ( key ) )
186
+ return this . localCache . get ( key ) ;
187
+ // local cache does not have element, fetch global participant
136
188
const participant = this . participants . get ( key ) ;
137
189
if ( ! participant )
138
190
return undefined ;
139
191
const displayName = participant . displayName ;
140
- const displayData = DisplayName . parse ( displayName , this . salt ) ;
141
- this . displayDataCache . set ( key , displayData [ key ] ) ;
142
- return displayData [ key ] ;
192
+ const data = DisplayName . parse ( displayName , this . salt ) ;
193
+ this . localCache . set ( key , data [ key ] ) ;
194
+ return data [ key ] ;
143
195
}
144
196
has ( key ) {
145
- return this . participants . has ( key ) ;
197
+ return this . localCache . has ( key ) ;
146
198
}
147
199
/**
148
200
* Adds a new element with a specified key and value to the database. If an element with the same key already exists, the element will be updated.
149
201
*/
150
202
set ( key , value ) {
151
203
if ( ! allowedTypes . includes ( typeof value ) )
152
204
throw new TypeError ( "JaylyDB::set only accepts a value of string, number, or boolean." ) ;
153
- const str = DisplayName . stringify ( { [ key ] : value } , this . salt ) ;
154
- if ( str . length > 32767 )
205
+ const encoded = DisplayName . stringify ( { [ key ] : value } , this . salt ) ;
206
+ if ( encoded . length > 32767 )
155
207
throw new RangeError ( "JaylyDB::set only accepts a string value less than 32767 characters." ) ;
156
- if ( this . displayDataCache . has ( key ) ) {
157
- const displayData = this . displayDataCache . get ( key ) ;
158
- if ( displayData [ key ] === value )
159
- return this ;
160
- }
161
- ;
162
- this . delete ( key ) ;
163
- overworld . runCommand ( `scoreboard players set "${ str } " ${ this . objective . id } 0` ) ;
164
- this . displayDataCache . set ( key , value ) ;
165
- this . updateParticipants ( ) ;
208
+ if ( this . localCache . get ( key ) === value )
209
+ return this ;
210
+ // push change to temp cache
211
+ this . participants . delete ( key ) ;
212
+ this . tempCache . set ( key , encoded ) ;
213
+ this . localCache . set ( key , value ) ;
166
214
return this ;
167
215
}
168
216
* entries ( ) {
169
- for ( const [ , { displayName } ] of this . participants ) {
170
- const valueObject = DisplayName . parse ( displayName , this . salt ) ;
171
- const [ entryKey , entryValue ] = Object . entries ( valueObject ) [ 0 ] ;
172
- yield [ entryKey , entryValue ] ;
173
- }
217
+ for ( const iterator of this . localCache . entries ( ) )
218
+ yield iterator ;
174
219
}
175
220
/**
176
221
* Returns an iterable of keys in the database
0 commit comments