Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ This keeps both storage and cache synchronized.
| Storage Type | Backend Used | Description |
| ------------ | ------------ | ------------------------------------ |
| `local` | DynamicDB | Stores data using dynamic properties |
| `dynamic` | DynamicDB | Same as local |
| `global` | ScoreboardDB | Stores data using scoreboard |
| `scoreboard` | ScoreboardDB | Same as global |

Example:

Expand Down
228 changes: 92 additions & 136 deletions scripts/database.js
Original file line number Diff line number Diff line change
@@ -1,138 +1,94 @@
import { world } from "@minecraft/server";
const KEY_4NO = "⧉⧉";
export class ScoreboardDB {
constructor(name) {
this.keyacc = '⟡⟡';
this.cache = {};
this.identifier = `${KEY_4NO}${name}${KEY_4NO}`;
this.obj = world.scoreboard.getObjective(this.identifier) ??
world.scoreboard.addObjective(this.identifier);
this.participantNames = {};
this.participants = this.obj.getParticipants();
let iteration = this.participants.length;
while (iteration--) {
const participantName = this.participants[iteration]?.displayName;
const [key, rawValue] = participantName.split(this.keyacc);
const value = rawValue.startsWith('num:') ? Number(rawValue.slice('num:'.length)) : rawValue.startsWith('bool:') ? Boolean(rawValue.slice('bool:'.length)) : JSON.parse(rawValue);
this.participantNames[key] = participantName;
this.cache[key] = value;
}
}
set(key, value) {
if (key in this.cache && value == null)
this.delete(key);
const valueFormatting = typeof value == 'number' ? `num:${value}` : typeof value == 'boolean' ? `bool:${value}` : value;
const participantName = `${key}${this.keyacc}${JSON.stringify(valueFormatting)}`;
this.obj.setScore(participantName, 1);
this.participantNames[key] = participantName;
this.cache[key] = value;
}
get(key) {
return this.cache[key];
}
has(key) {
return !!this.cache;
}
delete(key) {
if (!(key in this.cache))
return false;
this.obj.removeParticipant(this.participantNames[key]);
delete this.participantNames[key];
delete this.cache[key];
return true;
}
keys() {
return Object.keys(this.cache);
}
values() {
return Object.values(this.cache);
}
entries() {
return Object.entries(this.cache);
}
}
export class DynamicDB {
constructor(name) {
this.cache = {};
this.identifier = `${KEY_4NO}${name}${KEY_4NO}`;
const ids = world.getDynamicPropertyIds();
let i = ids.length;
while (i--) {
const id = ids[i];
if (!id.startsWith(this.identifier))
continue;
const raw = world.getDynamicProperty(id);
const key = id.slice(this.identifier.length);
const value = typeof raw === "string"
? JSON.parse(raw)
: raw;
this.cache[key] = value;
}
}
set(key, value) {
const id = this.identifier + key;
if (key in this.cache && value == null) {
this.delete(key);
return;
}
const data = typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean"
? value
: JSON.stringify(value);
world.setDynamicProperty(id, data);
this.cache[key] = value;
}
get(key) {
return this.cache[key];
}
has(key) {
return key in this.cache;
}
delete(key) {
if (!(key in this.cache))
return false;
world.setDynamicProperty(this.identifier + key, undefined);
delete this.cache[key];
return true;
}
keys() {
return Object.keys(this.cache);
}
values() {
return Object.values(this.cache);
}
entries() {
return Object.entries(this.cache);
}
}
DynamicDB.size = world.getDynamicPropertyTotalByteCount();
import { world } from "@minecraft/server"

const KEY_4NO = "⧉⧉"

export default class QuickDB {
constructor(name, storage = "local") {
this.db =
storage === "scoreboard" || storage === "global"
? new ScoreboardDB(name)
: new DynamicDB(name);
}
set(key, value) {
this.db.set(key, value);
}
get(key) {
return this.db.get(key);
}
has(key) {
return this.db.has(key);
}
delete(key) {
return this.db.delete(key);
}
keys() {
return this.db.keys();
}
values() {
return this.db.values();
}
entries() {
return this.db.entries();
}
constructor(name, scope = "local") {
this.scope = scope
this.keyacc = "⟡⟡"
this.cache = {}

this.identifier = `${KEY_4NO}${name}${KEY_4NO}`

if (scope === "global") {
this.obj = world.scoreboard.getObjective(this.identifier) ?? world.scoreboard.addObjective(this.identifier)

const participants = this.obj.getParticipants()
let i = participants.length

while (i--) {
const p = participants[i]
const [key, raw] = p.displayName.split(this.keyacc)
const value = JSON.parse(raw)

this.cache[key] = value
}
} else {
const ids = world.getDynamicPropertyIds()
let i = ids.length

while (i--) {
const id = ids[i]
if (!id.startsWith(this.identifier)) continue

const key = id.slice(this.identifier.length)
const raw = world.getDynamicProperty(id)
const value = typeof raw === "string" ? JSON.parse(raw) : raw

this.cache[key] = value
}
}
}

set(key, value) {
if (value == null) return this.delete(key)

this.cache[key] = value

if (this.scope === "global") {
if (key in this.cache) {
const old = `${key}${this.keyacc}${JSON.stringify(this.cache[key])}`
this.obj.removeParticipant(old)
}

const name = `${key}${this.keyacc}${JSON.stringify(value)}`
this.obj.setScore(name, 1)
} else {
const id = this.identifier + key
const data = ["string", "number", "boolean"].includes(typeof value) ? value : JSON.stringify(value)
world.setDynamicProperty(id, data)
}
}

get(key) {
return this.cache[key]
}

has(key) {
return key in this.cache
}

delete(key) {
if (!(key in this.cache)) return false

if (this.scope === "global") {
const name = `${key}${this.keyacc}${JSON.stringify(this.cache[key])}`
this.obj.removeParticipant(name)
} else world.setDynamicProperty(this.identifier + key, undefined)

delete this.cache[key]
return true
}

keys() {
return Object.keys(this.cache)
}

values() {
return Object.values(this.cache)
}

entries() {
return Object.entries(this.cache)
}
}