Skip to content
This repository has been archived by the owner on Aug 24, 2024. It is now read-only.

Commit

Permalink
Rollback 1.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
KocTu4eK committed Dec 15, 2022
1 parent 2f23ae8 commit 3aa99bc
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 63 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ This is an incomplete port of CoreProtect written in NodeJS with few features. M
## Capabilities
— Write (only) in SQLite
— Paginated log output
— Permission for the command
— Permission for the command
— Rollback of all actions
## Commands
— /coreprotect <inspect|i>
⠀⠀/coreprotect <l|lookup> <page>
⠀⠀/coreprotect <rollback|r> <radius: int> [time: float] [user: string]
⠀⠀/co — alias
— /coperms <player: target>
16 changes: 15 additions & 1 deletion command.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
const { isInspector, setInspector, lookupPage, clearUserPos } = require("./database.js");
const { isInspector, setInspector, lookupPage, clearUserPos, rollback } = require("./database.js");

mc.listen("onServerStarted", () => {
let command = mc.newCommand("coreprotect", "CoreProtect by KocTu4eK.", PermType.Any);
command.setAlias("co");

command.setEnum("Inspect", ["inspect", "i"]);
command.setEnum("Lookup", ["lookup", "l"]);
command.setEnum("Rollback", ["rollback", "r"]);

command.mandatory("inspect", ParamType.Enum, "Inspect", 1);
command.mandatory("lookup", ParamType.Enum, "Lookup", 1);
command.mandatory("page", ParamType.Int);
command.mandatory("rollback", ParamType.Enum, "Rollback", 1);
command.mandatory("radius", ParamType.Int);
command.optional("time", ParamType.Float);
command.optional("user", ParamType.String);

command.overload(["inspect"]);
command.overload(["lookup", "page"]);
command.overload(["rollback", "radius", "time", "user"]);

command.setCallback((_cmd, ori, out, res) => {
if (ori.player === undefined) return out.error("You are not a player!");
Expand All @@ -30,6 +39,11 @@ mc.listen("onServerStarted", () => {
if (res.page < 1) return out.error("Invalid integer specified!");
return lookupPage(ori.player, res.page, out);
}

if (res.rollback !== undefined) {
if (res.radius > 128) return out.success("§3CoreProtect §r- The maximum rollback radius is 128.");
return rollback(ori.player, res.radius, res.time, res.user, out);
}
}

return out.error("You don't have permission for this!");
Expand Down
128 changes: 79 additions & 49 deletions database.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,11 @@ function initDatabase() {

session.exec("CREATE TABLE IF NOT EXISTS co_art_map (id INTEGER PRIMARY KEY AUTOINCREMENT, block TEXT UNIQUE)");
session.exec("CREATE TABLE IF NOT EXISTS co_user (id INTEGER PRIMARY KEY AUTOINCREMENT, nickname TEXT UNIQUE, inspector INT DEFAULT 0, wid INT DEFAULT -1, x INT DEFAULT 0, y INT DEFAULT -256, z INT DEFAULT 0)");
session.exec("CREATE TABLE IF NOT EXISTS co_item (id INTEGER PRIMARY KEY AUTOINCREMENT, item TEXT UNIQUE)");
session.exec("CREATE TABLE IF NOT EXISTS co_block (time TIMESTAMP DEFAULT (CAST (((julianday('now') - 2440587.5) * 86400.0 * 1000) AS INT)), block INT, user INT, action INT, wid INT, x INT, y INT, z INT)");
session.exec("CREATE TABLE IF NOT EXISTS co_block (time TIMESTAMP DEFAULT (CAST (((julianday('now') - 2440587.5) * 86400.0 * 1000) AS INT)), block INT, user INT, action INT, wid INT, x INT, y INT, z INT, data INT, count INT, slot INT, rollback INT DEFAULT 0)");
}

function getUserId(playerName) {
let userId = session.query(`SELECT id FROM co_user WHERE nickname = "${playerName}"`);

if (userId === undefined) {
session.exec(`INSERT INTO co_user (nickname) VALUES ("${playerName}")`);
return session.query(`SELECT id FROM co_user WHERE nickname = "${playerName}"`)[1][0];
}

return userId[1][0];
}

function getUserName(userId) {
return session.query(`SELECT nickname FROM co_user WHERE id = ${userId}`)[1][0];
}

function getBlockId(blockName) {
blockName = blockName.replace("minecraft:", "");
let blockId = session.query(`SELECT id FROM co_art_map WHERE block = "${blockName}"`);

if (blockId === undefined) {
session.exec(`INSERT INTO co_art_map (block) VALUES ("${blockName}")`);
return session.query(`SELECT id FROM co_art_map WHERE block = "${blockName}"`)[1][0];
}

return blockId[1][0];
}

function getBlockName(blockId) {
return session.query(`SELECT block FROM co_art_map WHERE id = ${blockId}`)[1][0];
}

function logBlock(pl, blockName, wid, x, y, z, action) {
if (!isInspector(pl.realName)) session.exec(`INSERT INTO co_block (block, user, action, wid, x, y, z) VALUES (${getBlockId(blockName)}, ${getUserId(pl.realName)}, ${action}, ${wid}, ${x}, ${y}, ${z})`);
function logBlock(pl, blockName, wid, x, y, z, action, tileData, count = -1, slot = -1) {
if (!isInspector(pl.realName)) session.exec(`INSERT INTO co_block (block, user, action, wid, x, y, z, data, count, slot) VALUES (${getBlockId(blockName)}, ${getUserId(pl.realName)}, ${action}, ${wid}, ${x}, ${y}, ${z}, ${tileData}, ${count}, ${slot})`);
else {
if (action === 1) mc.setBlock(x, y, z, wid, "minecraft:air", 0);
let pageCount = getPageCount(wid, x, y, z);
Expand All @@ -51,13 +19,14 @@ function logBlock(pl, blockName, wid, x, y, z, action) {

let blockPage = getBlockPage(wid, x, y, z, 0);
for (i = 1; i < blockPage.length; i++) {
output += `§7${timeFormat(blockPage[i][0])} ago§r - §3${getUserName(blockPage[i][1])} §r${blockPage[i][3] === 0 ? "broke" : blockPage[i][3] === 1 ? "placed" : blockPage[i][3] === 2 ? "clicked" : blockPage[i][3] === 3 ? "add" : blockPage[i][3] === 4 ? "remove" : "?"} §3${getBlockName(blockPage[i][2])}§r.\n`;
if (blockPage[i][5] !== 1) output += `§7${timeFormat(blockPage[i][0])} ago§r - §3${getUserName(blockPage[i][1])} §r${blockPage[i][3] === 0 ? "broke" : blockPage[i][3] === 1 ? "placed" : blockPage[i][3] === 2 ? "clicked" : blockPage[i][3] === 3 ? `remove §3x${blockPage[i][4]}` : blockPage[i][3] === 4 ? `add §3x${blockPage[i][4]}` : "?"} §3${getBlockName(blockPage[i][2])}§r.\n`;
else output += `§o§7${timeFormat(blockPage[i][0])} ago§r§o - §3${getUserName(blockPage[i][1])} §r§o${blockPage[i][3] === 0 ? "broke" : blockPage[i][3] === 1 ? "placed" : blockPage[i][3] === 2 ? "clicked" : blockPage[i][3] === 3 ? `remove §3x${blockPage[i][4]}` : blockPage[i][3] === 4 ? `add §3x${blockPage[i][4]}` : "?"} §3${getBlockName(blockPage[i][2])}§r§o.§r\n`;
}

if (pageCount > 1) output += `-----\nPage 1/${pageCount}. View older data by typing "§3/co l <page>§r".`;
pl.tell(output);
}
else pl.tell(action ? `§3CoreProtect §r- No data found at this location.` : `§3CoreProtect §r- No data found at §o${blockName.replace("minecraft:", "")}§r.`);
else pl.tell(action ? "§3CoreProtect §r- No data found at this location." : `§3CoreProtect §r- No data found at §o${blockName.replace("minecraft:", "")}§r.`);

session.exec(`UPDATE co_user SET x = ${x}, y = ${y}, z = ${z}, wid = ${wid} WHERE id = ${getUserId(pl.realName)}`);

Expand All @@ -80,27 +49,44 @@ function lookupPage(pl, page, out) {

let blockPage = getBlockPage(userData[0], userData[1], userData[2], userData[3], (page - 1) * 7);
for (i = 1; i < blockPage.length; i++) {
output += `§7${timeFormat(blockPage[i][0])} ago§r - §3${getUserName(blockPage[i][1])} §r${blockPage[i][3] === 0 ? "broke" : blockPage[i][3] === 1 ? "placed" : blockPage[i][3] === 2 ? "clicked" : blockPage[i][3] === 3 ? "add" : blockPage[i][3] === 4 ? "remove" : "?"} §3${getBlockName(blockPage[i][2])}§r.\n`;
if (blockPage[i][5] !== 1) output += `§7${timeFormat(blockPage[i][0])} ago§r - §3${getUserName(blockPage[i][1])} §r${blockPage[i][3] === 0 ? "broke" : blockPage[i][3] === 1 ? "placed" : blockPage[i][3] === 2 ? "clicked" : blockPage[i][3] === 3 ? `remove x${blockPage[i][4]}` : blockPage[i][3] === 4 ? `add x${blockPage[i][4]}` : "?"} §3${getBlockName(blockPage[i][2])}§r.\n`;
else output += `§o§7${timeFormat(blockPage[i][0])} ago§r§o - §3${getUserName(blockPage[i][1])} §r§o${blockPage[i][3] === 0 ? "broke" : blockPage[i][3] === 1 ? "placed" : blockPage[i][3] === 2 ? "clicked" : blockPage[i][3] === 3 ? `remove x${blockPage[i][4]}` : blockPage[i][3] === 4 ? `add x${blockPage[i][4]}` : "?"} §3${getBlockName(blockPage[i][2])}§r§o.§r\n`;
}

if (pageCount > 1) output += `-----\nPage ${page}/${pageCount}. View older data by typing "§3/co l <page>§r".`;
return out.success(output);
}

function isInspector(playerName) {
return session.query(`SELECT inspector FROM co_user WHERE id = ${getUserId(playerName)}`)[1][0];
}

function setInspector(playerName, inspector) {
session.exec(`UPDATE co_user SET inspector = ${inspector} WHERE id = ${getUserId(playerName)}`);
}
function rollback(pl, radius, time, user, out) {
let blockData = session.query(`SELECT block, action, wid, x, y, z, data, count, slot FROM co_block WHERE ((x - ${pl.blockPos.x}) * (x - ${pl.blockPos.x}) + (y - ${pl.blockPos.y}) * (y - ${pl.blockPos.y}) + (z - ${pl.blockPos.z}) * (z - ${pl.blockPos.z}) <= ${radius ** 2}) and time > ${time !== undefined ? Date.now() - time * 3600000 : 0} and rollback == 0 and action != 2 ${user !== undefined ? `and user = ${getUserId(user)} ` : ""}ORDER BY time DESC`);
if (blockData === undefined) return out.success("§3CoreProtect §r- No rollback data found at this location.");
session.exec(`UPDATE co_block SET rollback = 1 WHERE ((x - ${pl.blockPos.x}) * (x - ${pl.blockPos.x}) + (y - ${pl.blockPos.y}) * (y - ${pl.blockPos.y}) + (z - ${pl.blockPos.z}) * (z - ${pl.blockPos.z}) <= ${radius ** 2}) and time > ${time !== undefined ? Date.now() - time * 3600000 : 0} and action != 2`);

for (i = 1; i < blockData.length; i++) {
switch (blockData[i][1]) {
case 0: // break
let blockName = getBlockName(blockData[i][0]);
mc.setBlock(blockData[i][3], blockData[i][4], blockData[i][5], blockData[i][2], `minecraft:${blockName === "water" || blockName === "lava" ? "flowing_" + blockName : blockName}`, blockData[i][6]);
break;
case 1: // place
mc.setBlock(blockData[i][3], blockData[i][4], blockData[i][5], blockData[i][2], "minecraft:air", 0);
break;
case 3: // take out
let ct = mc.getBlock(blockData[i][3], blockData[i][4], blockData[i][5], blockData[i][2]).getContainer();
let it = mc.newItem(`minecraft:${getBlockName(blockData[i][0])}`, blockData[i][7] + ct.getAllItems()[blockData[i][8]].count);
it.setAux(blockData[i][6]);
ct.setItem(blockData[i][8], it);
break;
case 4: // put
mc.getBlock(blockData[i][3], blockData[i][4], blockData[i][5], blockData[i][2]).getContainer().removeItem(blockData[i][8], blockData[i][7]);
}
}

function clearUserPos(playerName) {
session.exec(`UPDATE co_user SET y = -256 WHERE id = ${getUserId(playerName)}`);
return out.success("§3CoreProtect §r- Rollback completed.");
}

function getBlockPage(wid, x, y, z, offset) {
return session.query(`SELECT time, user, block, action FROM co_block WHERE wid = ${wid} AND x = ${x} AND y = ${y} AND z = ${z} ORDER BY time DESC LIMIT ${offset}, 7`);
return session.query(`SELECT time, user, block, action, count, rollback FROM co_block WHERE wid = ${wid} AND x = ${x} AND y = ${y} AND z = ${z} ORDER BY time DESC LIMIT ${offset}, 7`);
}

function getPageCount(wid, x, y, z) {
Expand All @@ -111,11 +97,55 @@ function timeFormat(time) {
return `${((Date.now() - time) / 3600000).toFixed(2)}/h`.replace(".", ",");
}

function getUserId(playerName) {
let userId = session.query(`SELECT id FROM co_user WHERE nickname = "${playerName}"`);

if (userId === undefined) {
session.exec(`INSERT INTO co_user (nickname) VALUES ("${playerName}")`);
return session.query(`SELECT id FROM co_user WHERE nickname = "${playerName}"`)[1][0];
}

return userId[1][0];
}

function getUserName(userId) {
return session.query(`SELECT nickname FROM co_user WHERE id = ${userId}`)[1][0];
}

function getBlockId(blockName) {
blockName = blockName.replace("minecraft:", "");
let blockId = session.query(`SELECT id FROM co_art_map WHERE block = "${blockName}"`);

if (blockId === undefined) {
session.exec(`INSERT INTO co_art_map (block) VALUES ("${blockName}")`);
return session.query(`SELECT id FROM co_art_map WHERE block = "${blockName}"`)[1][0];
}

return blockId[1][0];
}

function getBlockName(blockId) {
return session.query(`SELECT block FROM co_art_map WHERE id = ${blockId}`)[1][0];
}

function isInspector(playerName) {
return session.query(`SELECT inspector FROM co_user WHERE id = ${getUserId(playerName)}`)[1][0];
}

function setInspector(playerName, inspector) {
session.exec(`UPDATE co_user SET inspector = ${inspector} WHERE id = ${getUserId(playerName)}`);
}

function clearUserPos(playerName) {
session.exec(`UPDATE co_user SET y = -256 WHERE id = ${getUserId(playerName)}`);
}

module.exports = {
initDatabase,
logBlock,
isInspector,
setInspector,
lookupPage,
clearUserPos
clearUserPos,
rollback
};
25 changes: 14 additions & 11 deletions listener.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
const { logBlock } = require("./database.js");
const { logBlock, isInspector } = require("./database.js");

mc.listen("onDestroyBlock", (pl, bl) => logBlock(pl, bl.name, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 0));
mc.listen("afterPlaceBlock", (pl, bl) => logBlock(pl, bl.name, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 1));
mc.listen("onBlockInteracted", (pl, bl) => logBlock(pl, bl.name, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 2));
mc.listen("onDestroyBlock", (pl, bl) => logBlock(pl, bl.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 0, bl.tileData));
mc.listen("afterPlaceBlock", (pl, bl) => logBlock(pl, bl.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 1, bl.tileData));
mc.listen("onBlockInteracted", (pl, bl) => logBlock(pl, bl.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 2, bl.tileData));
mc.listen("onOpenContainer", (pl) => isInspector(pl.realName) ? false : true);

mc.listen("onUseItemOn", (pl, it, bl, side, pos) => {
if (it.type === "minecraft:bucket" && (bl.type === "minecraft:powder_snow" || bl.type === "minecraft:water" || bl.type === "minecraft:flowing_water" || bl.type === "minecraft:lava" || bl.type === "minecraft:flowing_lava")) {
return logBlock(pl, bl.type.replace("flowing_", ""), bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 0);
return logBlock(pl, bl.type.replace("flowing_", ""), bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 0, bl.tileData);
}

let x = bl.pos.x, y = bl.pos.y, z = bl.pos.z;
Expand All @@ -32,7 +33,7 @@ mc.listen("onUseItemOn", (pl, it, bl, side, pos) => {
bl = mc.getBlock(x, y, z, bl.pos.dimid);

if (it.type !== "minecraft:bucket" && it.type.includes("_bucket") && (bl.type === "minecraft:air" || bl.type === "minecraft:powder_snow" || bl.type === "minecraft:water" || bl.type === "minecraft:flowing_water" || bl.type === "minecraft:lava" || bl.type === "minecraft:flowing_lava")) {
if (!logBlock(pl, it.type.replace("_bucket", ""), bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 1)) {
if (!logBlock(pl, it.type.replace("_bucket", ""), bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 1, bl.tileData)) {
mc.setBlock(bl.pos, bl.type, bl.tileData);
return false;
}
Expand All @@ -42,13 +43,15 @@ mc.listen("onUseItemOn", (pl, it, bl, side, pos) => {
});

mc.listen("onContainerChange", (pl, bl, slotNum, oldIt, newIt) => {
if (!oldIt.isNull() && newIt.isNull()) logBlock(pl, oldIt.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 3); // take out
if (!oldIt.isNull() && newIt.isNull()) return logBlock(pl, oldIt.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 3, oldIt.aux, oldIt.count, slotNum); // take out
if (oldIt.isNull() && !newIt.isNull()) return logBlock(pl, newIt.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 4, newIt.aux, newIt.count, slotNum); // put

if (oldIt.isNull() && !newIt.isNull()) logBlock(pl, newIt.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 4); // put
if (oldIt.type === newIt.type && oldIt.count > newIt.count) return logBlock(pl, oldIt.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 3, oldIt.aux, oldIt.count - newIt.count, slotNum); // -
if (oldIt.type === newIt.type && oldIt.count < newIt.count) return logBlock(pl, oldIt.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 4, oldIt.aux, newIt.count - oldIt.count, slotNum); // +

if (!oldIt.isNull() && !newIt.isNull()) { // replace
logBlock(pl, oldIt.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 3);
logBlock(pl, newIt.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 4);
if (oldIt.type !== newIt.type && !oldIt.isNull() && !newIt.isNull()) { // replace
logBlock(pl, oldIt.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 3, oldIt.aux, oldIt.count, slotNum);
return logBlock(pl, newIt.type, bl.pos.dimid, bl.pos.x, bl.pos.y, bl.pos.z, 4, newIt.aux, newIt.count, slotNum);
}
});

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "coreprotectmini",
"version": "1.0.0",
"version": "1.1.0",
"description": "Stripped down version of CoreProtect",
"main": "main.js",
"author": "KocTu4eK",
Expand Down

0 comments on commit 3aa99bc

Please sign in to comment.