Skip to content

Commit 420f9f5

Browse files
authored
update jaylydb and assert (JaylyDev#244)
* 1.0.6 * 1.0.7
1 parent 6df68b6 commit 420f9f5

File tree

7 files changed

+187
-101
lines changed

7 files changed

+187
-101
lines changed

scripts/assert/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# assert
2+
3+
## Description
4+
A function to test if a value is equal to true, an error is thrown otherwise. Used for unit tests.
5+
6+
## Credits
7+
These scripts were written by [Jayly](https://github.com/JaylyDev)

scripts/assert/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Script example for ScriptAPI
2+
// Author: Jayly <https://github.com/JaylyDev>
3+
// Project: https://github.com/JaylyDev/ScriptAPI
14
/**
25
* Indicates the failure of an assertion. All errors thrown by the `assert` function
36
* will be instances of the `AssertionError` class.

scripts/assert/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Script example for ScriptAPI
2+
// Author: Jayly <https://github.com/JaylyDev>
3+
// Project: https://github.com/JaylyDev/ScriptAPI
14

25
/**
36
* Indicates the failure of an assertion. All errors thrown by the `assert` function

scripts/jaylydb/index.d.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,13 @@ declare class JaylyDB implements Map<string, string | number | boolean> {
2222
/**
2323
* Executes a provided function once per each key/value pair in the database, in insertion order.
2424
*/
25-
forEach(callbackfn: (value: string | number | boolean, key: string, map: this) => void): void;
25+
forEach(callbackfn: (value: string | number | boolean, key: string, jaylydb: this) => void): void;
2626
/**
2727
* Returns a specified element from the database.
2828
* @param key The key of the element to return.
29-
* @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.
3029
* @returns Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.
3130
*/
32-
get(key: string, reloadCache?: boolean): string | number | boolean | undefined;
31+
get(key: string): string | number | boolean | undefined;
3332
has(key: string): boolean;
3433
/**
3534
* 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.

scripts/jaylydb/index.js

Lines changed: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
1-
var _a;
21
// Script example for ScriptAPI
32
// Author: Jayly <https://github.com/JaylyDev>
43
// 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";
728
const str = () => ('00000000000000000' + (Math.random() * 0xffffffffffffffff).toString(16)).slice(-16);
829
/**
930
* 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) => {
3354
return String.fromCharCode(...decryptedChars);
3455
};
3556
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);
3758
throw new Error(`Failed to ${action} data. Please check content log file for more info.\n`);
3859
};
3960
/**
@@ -65,19 +86,37 @@ const overworld = world.getDimension("overworld");
6586
* A simple database for storing data in a Minecraft world, using scoreboard.
6687
*/
6788
class JaylyDB {
68-
/** @internal */
69-
get salt() {
70-
return this.encrypted ? this.objective.displayName : undefined;
71-
}
72-
;
7389
/** @internal */
7490
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+
;
75113
this.participants.clear();
76114
for (const participant of this.objective.getParticipants()) {
77115
if (participant.type !== ScoreboardIdentityType.fakePlayer)
78116
continue;
79117
this.participants.set(Object.keys(DisplayName.parse(participant.displayName, this.salt))[0], participant);
80118
}
119+
;
81120
}
82121
/**
83122
* @param id An identifier for the database
@@ -87,11 +126,23 @@ class JaylyDB {
87126
/** @internal */
88127
this.participants = new Map();
89128
/** @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();
91138
this[_a] = JaylyDB.name;
92139
this.objective = world.scoreboard.getObjective("jaylydb:" + id) ?? world.scoreboard.addObjective("jaylydb:" + id, uuid());
93140
this.encrypted = encrypted;
141+
this.salt = this.encrypted ? this.objective.displayName : undefined;
142+
// Fetch all data when database initialize
94143
this.updateParticipants();
144+
// This function queues the data to be written to the scoreboard every second interval.
145+
system.runInterval(() => this.updateParticipants());
95146
}
96147
/**
97148
* @returns the number of elements in the database.
@@ -115,6 +166,7 @@ class JaylyDB {
115166
return false;
116167
const success = this.objective.removeParticipant(participant);
117168
this.participants.delete(key);
169+
this.localCache.delete(key);
118170
return success;
119171
}
120172
/**
@@ -127,50 +179,43 @@ class JaylyDB {
127179
/**
128180
* Returns a specified element from the database.
129181
* @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.
131182
* @returns Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.
132183
*/
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
136188
const participant = this.participants.get(key);
137189
if (!participant)
138190
return undefined;
139191
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];
143195
}
144196
has(key) {
145-
return this.participants.has(key);
197+
return this.localCache.has(key);
146198
}
147199
/**
148200
* 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.
149201
*/
150202
set(key, value) {
151203
if (!allowedTypes.includes(typeof value))
152204
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)
155207
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);
166214
return this;
167215
}
168216
*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;
174219
}
175220
/**
176221
* Returns an iterable of keys in the database

0 commit comments

Comments
 (0)