chore: 优化项目文件结构

This commit is contained in:
ProjectXero 2020-02-03 23:30:20 +08:00
parent a8702777d7
commit c504cd3ea4
93 changed files with 147 additions and 5518 deletions

6
.gitignore vendored
View File

@ -1,5 +1 @@
dist/
build/
snapshot/
tools/node_modules/
tools/config/ssh.txt
build/

View File

@ -18,5 +18,15 @@ App工程参见[命令助手Android版](https://gitee.com/projectxero/cadroid)
* [正式版下载链接](https://www.coolapk.com/game/com.xero.ca)
## 生成
在当前目录下运行 `build buildRelease` 即可。
文件会导出至 `/dist`
### 准备工作
1. 安装[命令助手构建工具](https://gitee.com/projectxero/cabuildtools)。
2. 按需要修改 `config` 文件夹内的配置文件。
### 生成正式版JS
在当前目录下运行 `cabuild buildRelease` 即可,文件会导出至 `/build/dist`
### 生成快照版JS
在当前目录下运行 `cabuild buildSnapshot` 即可,文件会导出至 `/build/dist`
### 生成正式版APP
在当前目录下运行 `cabuild shellBuildRelease` 即可,文件会导出至 `/build/dist`

View File

@ -1,4 +0,0 @@
@echo off
cd .\tools
node main.js %1 ..\ %2 %3 %4
cd ..

View File

@ -1,3 +0,0 @@
cd ./tools
node main.js $1 ../ $2 $3 $4
cd ..

View File

@ -1,108 +0,0 @@
(function() {
function random(seed) {
return (seed[0] = (seed[0] * 9301 + 49297) % 233280) / 233280;
}
function hash(s) {
var i, result = 0;
for (i = s.length - 1; i >= 0; i--) result = (result + s.charCodeAt(i)) % 233280;
return result;
}
function wind(str, p) {
var seed = [str.length * p], randoms = [], seq = [], j, t;
for (i = 0; i < str.length; i++) {
randoms[str.length - i - 1] = random(seed);
seq[i] = str.charAt(i);
}
i = 0;
while (i < str.length) {
j = Math.floor(randoms[i] * (i + 1));
t = seq[j];
seq[j] = seq[i];
seq[i] = t;
i++;
}
return seq.join("");
}
function tokenize(s) {
var i = 0, r = [], ch, ch2, fl, token;
while (i < s.length) {
switch (ch = s.charAt(i)) {
case "\"":
case "'":
fl = 0;
token = {
start : i,
type : ch,
kind : "string"
};
while (++i < s.length) {
ch2 = s.charAt(i);
if (ch2 == "\\") {
i++;
continue;
}
if (ch2 == ch) {
token.end = i + 1;
r.push(token);
break;
}
}
break;
case "/":
token = {
start : i,
kind : "comment"
};
ch2 = s.charAt(++i);
token.type = ch2;
if (ch2 == "/") {
while (++i < s.length) {
ch2 = s.charAt(i);
if (ch2 == "\r" || ch2 == "\n") {
token.end = i;
r.push(token);
break;
}
}
} else if (ch2 == "*") {
fl = 0;
while (++i < s.length) {
ch2 = s.charAt(i);
if (fl == 1 && ch2 == "/") {
token.end = i + 1;
r.push(token);
break;
}
fl = ch2 == "*" ? 1 : 0;
}
} else {
continue;
}
}
i++;
}
return r;
}
function encryptString(str) {
if (str.length < 3) return JSON.stringify(str);
var seed = Math.ceil(random([hash(str)]) * 233280 / str.length);
return "unwind(" + JSON.stringify(wind(str, seed)) + ", " + seed + ")";
}
function encrypt(source) {
var tokens = tokenize(source).filter((e) => e.kind == "string"), i, e, result = [], lastEnd = 0;
if (!tokens.length) return source;
for (i = 0; i < tokens.length; i++) {
e = tokens[i];
result.push(
source.slice(lastEnd, e.start),
encryptString(JSON.parse(source.slice(e.start, e.end)))
);
lastEnd = e.end;
}
result.push(source.slice(e.end));
return result.join("");
}
return function(source) {
return encrypt(source);
}
})()

View File

@ -1,134 +0,0 @@
Plugins.inject(function(host) {
host.name = "每日问题";
host.author = "ProjectXero";
host.version = [1, 0, 1];
host.uuid = "9ab8c0af-8749-4758-9e96-c25d340c9ee3";
host.description = "每日一问题,提升你的命令水平";
host.init = function() {
Plugins.addMenu({
text : "每日问题",
onclick : function() {
show();
}
});
}
var Verify = Loader.fromFile("./verify.js");
var contentView = {}, popup, ans, curq;
function initView() {
contentView.main = L.ScrollView({
fillViewport : true,
style : "message_bg",
child : L.LinearLayout({
orientation : L.LinearLayout("vertical"),
layout : { width : -1, height : -1 },
padding : [15 * G.dp, 15 * G.dp, 15 * G.dp, 0],
children : [
L.TextView({
text : "每日问题",
padding : [0, 0, 0, 10 * G.dp],
layout : { width : -1, height : -2 },
gravity : L.Gravity("center"),
style : "textview_default",
fontSize : 4
}),
contentView.problem = L.TextView({
padding : [0, 0, 0, 10 * G.dp],
layout : { width : -1, height : -2 },
gravity : L.Gravity("center"),
style : "textview_default",
fontSize : 3
}),
contentView.answer = L.EditText({
padding : [0, 0, 0, 0],
imeOptions : L.EditorInfo("IME_FLAG_NO_FULLSCREEN"),
style : "edittext_default",
fontSize : 2,
gravity : L.Gravity("top|start"),
layout : { width : -1, height : 0, weight : 1.0 }
}),
L.TextView({
text : "提交答案",
padding : [20 * G.dp, 10 * G.dp, 20 * G.dp, 10 * G.dp],
gravity : L.Gravity("center"),
layout : { width : -1, height : -2 },
style : "button_critical",
fontSize : 4,
onClick : function() {
ans = String(contentView.answer.getText());
if (checkAnswer(ans)) {
popup.exit();
} else {
Common.toast("答案错误");
}
}
}),
L.TextView({
text : "关闭",
padding : [20 * G.dp, 10 * G.dp, 20 * G.dp, 10 * G.dp],
gravity : L.Gravity("center"),
layout : { width : -1, height : -2 },
style : "button_critical",
fontSize : 4,
onClick : function() {
popup.exit();
}
}),
contentView.about = L.TextView({
padding : [5 * G.dp, 5 * G.dp, 5 * G.dp, 15 * G.dp],
layout : { width : -1, height : -2 },
gravity : L.Gravity("center"),
style : "textview_default",
fontSize : 2
})
]
})
});
popup = new PopupPage(contentView.main, "dailyquestion.Main");
popup.on("exit", function() {
if (host.settings) {
host.settings.lastInput = String(contentView.answer.getText());
host.settings.lastExpired = Verify.getNextUpdateTime().getTime();
}
});
PWM.registerResetFlag(contentView, "main");
}
function fixZero(s, n) {
s = String(s);
return n > s.length ? fixZero("0" + s, n) : s;
}
function toChineseDateTime(date) {
return date.getFullYear() + "年" + (date.getMonth() + 1) + "月" + date.getDate() + "日 " + fixZero(date.getHours(), 2) + ":" + fixZero(date.getMinutes(), 2) + ":" + fixZero(date.getSeconds(), 2);
}
function updateView() {
contentView.problem.setText(curq.question);
contentView.answer.setText(ans);
contentView.answer.setHint(curq.answerType == "number" ? "请使用一个数字来解答以下问题允许使用1.203e56这样的科学表示法)" : "请使用一句命令来解答以下问题(如非必要,请不要使用嵌套命令)");
contentView.about.setText("下次更换问题于" + toChineseDateTime(Verify.getNextUpdateTime()) + "\n题库:" + Verify.getCount() + "题 | " + Verify.getLastUpdateAt() + "\n\n命令助手讨论区 @ ProjectXero");
}
function checkAnswer(answer) {
var code;
try {
code = Verify.checkAnswer(answer);
if (code) {
Common.showTextDialog("祝贺你!你答对了!\n密码为" + fixZero(code, 6));
return true;
}
} catch(e) {
Log.e(e);
}
return false;
}
function show() {
Verify.setDate(Date.now());
curq = Verify.requestQuestion();
if (host.settings && Number(host.settings.lastExpired) > Date.now()) {
ans = host.settings.lastInput;
if (checkAnswer(ans)) return;
} else {
ans = "";
}
if (!contentView.main) initView();
updateView();
popup.enter();
}
})

View File

@ -1,242 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>每日问题</title>
<style>
body {
background-color: black;
}
h1, div {
color: white;
text-align: center;
padding: 10px;
}
a:link, a:visited {
color: lightblue;
text-decoration: underline;
}
a:hover, a:active {
color: white;
text-decoration: underline;
}
#about {
color: gray;
bottom: 5px;
left: 5px;
right: 5px;
animation: body_visible 0.5s ease 1.7s backwards;
}
#question_title {
white-space: nowrap;
text-overflow: clip;
animation: title_scale 1s ease-out;
}
#question_usage {
animation: body_visible 0.5s ease 0.7s backwards;
}
#question_body, #question_answer {
animation: body_visible 0.5s ease 1.5s backwards;
font-family: 'Courier New', Courier, monospace
}
#answer_box {
background-color: black;
color: white;
border: 2px gray dotted;
width: 75%;
}
#question_success {
animation: body_visible 0.5s;
}
#check_button {
background-color: black;
color: white;
border: 1px solid white;
}
.toast {
animation: toast_opacity 1.5s linear both;
}
@keyframes title_scale {
from {letter-spacing: 20px}
to {letter-spacing: 0px}
}
@keyframes body_visible {
from {opacity: 0}
to {opacity: 1}
}
@keyframes toast_opacity {
0% {opacity: 0}
25% {opacity: 1}
75% {opacity: 1}
100% {opacity: 0}
}
</style>
</head>
<body>
<h1 id="question_title">每 日 问 题</h1>
<div id="question_usage"></div>
<div id="question_body">如果您看到这段文字,说明网页可能无法使用某些页面特性。请您检查您的浏览器设置或者更新您的浏览器。</div>
<div id="question_answer" style="display: none">
请填写你的答案 <button id="check_button" onclick="checkAnswer(document.getElementById('answer_box'), true)">验证</button><br />
<input type="text" id="answer_box" onchange="checkAnswer(this)"></input>
<div id="question_failure">答案错误</div>
</div>
<div id="question_success"></div>
<div id="about"></div>
<script>
/*
别以为看到这儿就可以作弊了,这里的答案可都是正则表达式
如果你有能力看懂正则表达式,区区命令又有何难?
*/
var Verify = Loader.fromFile("./verify.js");
function getQueryString() {
var url = location.search;
var r = {}, i, strs, t;
if ((t = url.indexOf("?")) >= 0) {
strs = url.slice(t + 1).split("&");
for(i in strs) {
t = strs[i].indexOf("=");
if (t >= 0) {
r[strs[i].slice(0, t)] = unescape(strs[i].slice(t + 1));
} else {
r[strs[i]] = true;
}
}
}
return r;
}
var query = getQueryString();
var date;
if (query.date) date = Date.parse(query.date);
if (isNaN(date)) date = Date.now();
var cur;
var isSuccessed;
function reload() {
var body_node = document.getElementById("question_body");
var about_node = document.getElementById("about");
var answer_node = document.getElementById("question_answer");
var usage_node = document.getElementById("question_usage");
var input_node = document.getElementById("answer_box");
var success_node = document.getElementById("question_success");
var failure_node = document.getElementById("question_failure");
var setter_node = document.getElementById("day_box");
if (self != top) {
body_node.innerHTML = "检测到可能存在代码注入";
return;
}
var siteName, hostName;
if (location.protocol == "file:") {
siteName = "本地文件系统";
} else {
hostName = location.hostname.toLowerCase();
if (hostName == "projectxero.gitee.io") {
siteName = "码云";
} else if (hostName == "xeroalpha.github.io") {
siteName = "GitHub";
} else if (hostName.endsWith("projectxero.top")) {
siteName = "话唠兔的小站";
}
}
if (!siteName) return;
Verify.setDate(date);
if (query.verify) {
cur = Verify.requestVerification();
} else {
cur = Verify.requestQuestion();
}
body_node.innerText = cur.question;
usage_node.innerHTML = cur.answerType == "number" ? "请使用一个数字来解答以下问题允许使用1.203e56这样的科学表示法)" : "请使用一句命令来解答以下问题(如非必要,请不要使用嵌套命令)";
about_node.innerHTML = "下次更换问题于" + toChineseDateTime(Verify.getNextUpdateTime()) + "<br />题库:" + Verify.getCount() + "题 | " + Verify.getLastUpdateAt() + "<br /><br />命令助手讨论区 @ ProjectXero<br />本页面由" + siteName + "托管";
answer_node.style = "";
success_node.style = "display: none";
success_node.innerHTML = "";
failure_node.style = "opacity: 0";
isSuccessed = false;
if (window.localStorage && Number(window.localStorage.lastExpired) > Date.now()) {
input_node.value = window.localStorage.lastInput;
input_node.onchange();
}
if (isSuccessed) {
success_node.style = "animation: body_visible 0.5s ease 1.5s backwards";
}
if (setter_node) setter_node.value = toSimpleDate(new Date(date - date % 86400000));
}
window.onload = function() {
reload();
onresize();
if (query.daycontrol) {
dayControl();
}
}
window.onresize = function() {
var about_node = document.getElementById("about");
if (window.innerHeight < document.body.offsetHeight + about_node.offsetHeight) {
about_node.style.position = "static";
} else {
about_node.style.position = "fixed";
}
}
window.offsetDay = function(n) {
if (!n || isNaN(n)) n = 0;
date += 86400000 * n;
reload();
}
window.setDay = function(d) {
date = new Date(d).getTime();
reload();
}
window.dayControl = function() {
var control_node = document.getElementById("day_control");
if (!control_node) {
control_node = document.createElement("div");
control_node.id = "day_control";
control_node.innerHTML = '<button onclick="offsetDay(-1)">&lt;</button><input id="day_box" onchange="setDay(this.value)" /><button onclick="offsetDay(1)">&gt;</button>';
document.body.appendChild(control_node);
}
reload();
}
function toChineseDateTime(date) {
return date.getFullYear() + "年" + (date.getMonth() + 1) + "月" + date.getDate() + "日 " + fixZero(date.getHours(), 2) + ":" + fixZero(date.getMinutes(), 2) + ":" + fixZero(date.getSeconds(), 2);
}
function toSimpleDate(date) {
return date.getFullYear() + "-" + fixZero(date.getMonth() + 1, 2) + "-" + fixZero(date.getDate(), 2);
}
function fixZero(s, n) {
s = String(s);
return n > s.length ? fixZero("0" + s, n) : s;
}
function succeed_action(code) {
var answer_node = document.getElementById("question_answer");
var success_node = document.getElementById("question_success");
success_node.innerHTML = "祝贺你!你答对了!<br />代码为:" + fixZero(code, 6) + '<br /><br />如果你希望你的题目出现在题库里,您可以加群<a target="_blank" href="https://jq.qq.com/?_wv=1027&k=46Yl84D">MCBE命令助手讨论区</a>';
success_node.style = "";
answer_node.style = "display: none";
isSuccessed = true;
}
function failed_action() {
var failure_node = document.getElementById("question_failure");
failure_node.className = "";
setTimeout(function() {
failure_node.className = "toast";
}, 100);
}
window.checkAnswer = function(answer, fromButton) {
var code;
if (answer != null) {
if (window.localStorage) {
window.localStorage.lastInput = answer.value;
window.localStorage.lastExpired = Verify.getNextUpdateTime().getTime();
}
try {
code = Verify.checkAnswer(answer.value);
if (code) succeed_action(code);
} catch(e) {
console.log(e);
}
if (fromButton || answer.value.length) failed_action();
}
}
</script>
</body>
</html>

View File

@ -1,230 +0,0 @@
[{
question: "如何检测最近玩家是否携带了命令方块?",
answer: "clear\\s+@p\\s+command_block\\s+-1\\s+0"
}, {
question: "如何复制(1,3,5)-(2,4,6)区域内所有的非空气方块到(-1,8,-5)-(0,9,-4)?请让第一个坐标的X、Y、Z分别小于等于第二个坐标的X、Y、Z",
answer: "clone\\s+1\\s+3\\s+5\\s+2\\s+4\\s+6\\s+-1\\s+8\\s+-5\\s+masked(\\s+(normal|force))?"
}, {
question: "如何复制(7,17,2)-(9,18,3)区域内所有的泥土方块,使复制后(7,17,2)位置的方块被复制到当前位置请让第一个坐标的X、Y、Z分别小于等于第二个坐标的X、Y、Z",
answer: "clone\\s+7\\s+17\\s+2\\s+9\\s+18\\s+3\\s+~\\s*~\\s*~\\s+filtered\\s+(normal|force)\\s+dirt(\\s+0)?"
}, {
question: "如何给予最近玩家无敌效果10秒且隐藏粒子",
answer: "effect\\s+@p\\s+resistance\\s+10\\s+([1-9]\\d+|[5-9])\\s+true"
}, {
question: "如何给予所有玩家徒手攻击其他实体无伤的效果1分钟",
answer: "effect\\s+@a\\s+weakness\\s+60(\\s+[19-]\\d*(\\s+(true|false))?)?"
}, {
question: "如何检测最近玩家手持物品是否是钓鱼竿钓鱼竿已被附魔为饵钓I",
answer: "enchant\\s+@p\\s+lure(\\s+1)?"
}, {
question: "如何杀死所有站在灰色羊毛上的玩家?(命令执行点为玩家所在坐标)",
answer: "execute\\s+@a\\s+~\\s*~\\s*~\\s+detect\\s+~\\s+~-1\\s+~\\s+wool\\s+7\\s+kill(\\s+(@s|@p))?"
}, {
question: "如何将玩家A传送到玩家B前方两格",
answer: "execute\\s+B\\s+~\\s+~\\s+~\\s+(tp|teleport)\\s+A\\s+\\^\\s+\\^\\s+\\^2"
}, {
question: "如何给予以(5,31,2)为中心半径50格范围内的所有玩家“雷罚”一次",
answer: function(str, unwind) {
var a = new RegExp("^execute\\s+@a\\[(.+?)\\]\\s+~\\s+~\\s+~\\s+summon\\s+lightning_bolt(\\s+~\\s+~\\s+~)?$", "").exec(str);
if (!a) return false;
var i, p = parseSelector(a[1], [
{
type: "equalsPositiveKeys",
keys: ["x", "y", "z", "r"]
}, {
type: "noNegativeKeys"
}, {
type: "numbericPositiveKeys",
keys: ["x", "y", "z", "r"]
}
]);
if (!p) return false;
var pos = p.positive;
return pos.x == 5 && pos.y == 31 && pos.z == 2 && pos.r == 50;
}
}, {
question: "如何将(1,3,5)-(2,4,6)区域内所有的石头方块替换为空气请让第一个坐标的X、Y、Z分别小于等于第二个坐标的X、Y、Z",
answer: "fill\\s+1\\s+3\\s+5\\s+2\\s+4\\s+6\\s+air\\s+0\\s+replace\\s+stone(\\s+0)?"
}, {
question: "如何将以命令执行点为中心清空半径为5格的立方体内的所有方块并在六面覆盖上玻璃请让第一个坐标的X、Y、Z分别小于等于第二个坐标的X、Y、Z",
answer: "fill\\s+~-5\\s+~-5\\s+~-5\\s+~5\\s+~5\\s+~5\\s+glass\\s+0\\s+hollow"
}, {
question: "如何设置所有非生存模式玩家为生存模式?",
answer: "gamemode\\s+(0|s|survival)\\s+@a\\[m=!(0|s|survival)\\]"
}, {
question: "如何把以(4,5,6)为中心边长为4的正方体内的所有玩家变成生存模式",
answer: function(str, unwind) {
var a = new RegExp("^gamemode\\s+(0|s|survival)\\s+@a\\[(.+?)\\]$", "").exec(str);
if (!a) return false;
var i, p = parseSelector(a[2], [
{
type: "equalsPositiveKeys",
keys: ["x", "y", "z", "dx", "dy", "dz"]
}, {
type: "noNegativeKeys"
}, {
type: "numbericPositiveKeys",
keys: ["x", "y", "z", "dx", "dy", "dz"]
}
]);
if (!p) return false;
var pos = p.positive;
normalizeSelectorBox(pos);
return pos.x == 2 && pos.y == 3 && pos.z == 4 && pos.dx == 4 && pos.dy == 4 && pos.dz == 4;
}
}, {
question: "如何防止玩家溺死?(即氧气条走完后不伤血)",
answer: "gamerule\\s+drowningdamage\\s+false"
}, {
question: "如何给予最近玩家一把在冒险模式下只能挖黑曜石的钻石镐?",
answer: function(str, unwind) {
var a = new RegExp("^give\\s+@p\\s+diamond_pickaxe\\s+1\\s+(\\d+)\\s+(.+)$", "").exec(str);
var p = JSON.parse(a[2]);
p = p["minecraft:can_destroy"].blocks;
return Array.isArray(p) && p.length == 1 && p[0] == "obsidian";
}
}, {
question: "如果游戏内一开始有6个盔甲架执行两次execute @e[type=armor_stand] ~ ~ ~ execute @e[type=armor_stand] ~ ~ ~ summon armor_stand后游戏内会有几个盔甲架不考虑运行环境限制",
answer: function(str) {
return Math.abs(Number(str) - 6 * Math.pow(2, 6) * Math.pow(2, 384)) < 1e+115;
},
answerType: "number"
}, {
question: "如何在所有玩家耳边播放一次末影人死亡声?(每个玩家收到的音量相同)",
answer: "execute\\s+@a\\s+~\\s+~\\s+~\\s+playsound\\s+mob.endermen.death\\s+@s(\\s+~\\s+~\\s+~(\\s+\\d+(\\s+\\d+(\\s+\\d+)?)?)?)?"
}, {
question: "如何替换位于(51,8,-56)的箱子内的第五格物品为一个潮涌核心?",
answer: "replaceitem\\s+block\\s+51\\s+8\\s+-56\\s+slot\\.container\\s+4\\s+conduit(\\s+1(\\s+\\d+)?)?"
}, {
question: "如何替换最近玩家的快捷栏第一格为一块在冒险模式下只能放在草方块上的玻璃?",
answer: function(str, unwind) {
var a = new RegExp("^replaceitem\\s+entity\\s+@p\\s+slot.hotbar\\s+0\\s+glass\\s+1\\s+0\\s+(.+)$").exec(str);
var p = JSON.parse(a[1]);
p = p["minecraft:can_place_on"].blocks;
return Array.isArray(p) && p.length == 1 && p[0] == "grass";
}
}, {
question: "如何用命令让半径30格内的随机一个玩家戴上钻石头盔",
answer: "replaceitem\\s+entity\\s+@r\\[r=30\\]\\s+slot\\.armor\\.head\\s+0\\s+diamond_helmet(\\s+\\d+(\\s+\\d+)?)?"
}, {
question: "如何将所有玩家传送到以(17,?,5)为中心半径为20的区域",
answer: "spreadplayers\\s+17\\s+5\\s+\\d+\\s+20\\s+@a"
}, {
question: "如何让显示给所有玩家的下次标题瞬间显示持续1s后瞬间消失",
answer: "title\\s+@a\\s+times\\s+0\\s+20\\s+0"
}, {
question: "如何让所有名称为A的盔甲架不断原地旋转",
answer: function(str, unwind) {
var a = new RegExp("^execute\\s+@e\\[(.+)\\]\\s+~\\s+~\\s+~\\s+tp\\s+(@s\\s+)?~\\s+~\\s+~\\s+~(-?\\d+)(\\s+~)?$", "").exec(str);
if (!a) return false;
var i, p = parseSelector(a[1], [
{
type: "equalsPositiveKeys",
keys: ["type", "name"]
}, {
type: "noNegativeKeys"
}
]);
if (!p) return false;
var pos = p.positive;
return pos.type == "armor_stand" && pos.name == "A";
}
}, {
question: "如何把以(7,8,9)为顶点第五卦限方向里边长为6的正方体里的所有生物传送到(0,4,0)?(不懂什么叫卦限的自己百度)",
answer: function(str, unwind) {
var a = new RegExp("^tp\\s+@e\\[(.+?)\\]\\s+0\\s+4\\s+0$", "").exec(str);
if (!a) return false;
var i, p = parseSelector(a[1], [
{
type: "equalsPositiveKeys",
keys: ["x", "y", "z", "dx", "dy", "dz"]
}, {
type: "noNegativeKeys"
}, {
type: "numbericPositiveKeys",
keys: ["x", "y", "z", "dx", "dy", "dz"]
}
]);
if (!p) return false;
var pos = p.positive;
normalizeSelectorBox(pos);
return pos.x == 7 && pos.y == 8 && pos.z == 3 && pos.dx == 6 && pos.dy == 6 && pos.dz == 6;
}
}, (function() {
var op = [{
id: "+=",
op: (a, b) => {a[0] = a[0] + b[0]}
}, {
id: "-=",
op: (a, b) => {a[0] = a[0] - b[0]}
}, {
id: "*=",
op: (a, b) => {a[0] = a[0] * b[0]}
}, {
id: "><",
op: (a, b) => {
var t = a[0];
a[0] = b[0]; b[0] = t;
}
}];
var a = [Math.floor(Math.random() * 10 + 1)],
b = [Math.floor(Math.random() * 10 + 1)],
c = [Math.floor(Math.random() * 10 + 1)],
m1 = Math.floor(Math.random() * op.length),
m2 = Math.floor(Math.random() * op.length),
m3 = Math.floor(Math.random() * op.length);
var question = [
"请填写当我的世界执行完以下命令后玩家Mark的记分项a的分数",
"/scoreboard objectives add a dummy",
"/scoreboard objectives add b dummy",
"/scoreboard objectives add c dummy",
"/scoreboard players set Mark a " + a[0],
"/scoreboard players set Mark b " + b[0],
"/scoreboard players set Mark c " + c[0],
"/scoreboard players operation Mark c " + op[m1].id + " Mark a",
"/scoreboard players operation Mark b " + op[m2].id + " Mark c",
"/scoreboard players operation Mark a " + op[m3].id + " Mark b"
].join("\n");
op[m1].op(c, a);
op[m2].op(b, c);
op[m3].op(a, b);
return {
question: question,
answer: function(str) {
return Number(str) == a[0];
},
answerType: "number"
};
})(), {
question: "如何让记分项aaa显示在侧边栏并使分数升序排序",
answer: "scoreboard\\s+objectives\\s+setdisplay\\s+sidebar\\s+aaa\\s+ascending"
}, {
question: "如何让不在线的玩家Mark的记分项mark小于等于50时执行成功否则失败",
answer: "scoreboard\\s+players\\s+test\\s+Mark\\s+mark\\s+\\*\\s+50"
}, {
question: "如何检测所有记分项mark大于等于30但time小于等于20的玩家使用testfor命令",
answer: function(str, unwind) {
var a = new RegExp("testfor\\s+@a\\[(.+)\\]", "").exec(str);
if (!a) return false;
var i, p = parseSelector(a[1], [
{
type: "equalsPositiveKeys",
keys: ["scores"]
}, {
type: "noNegativeKeys"
}, {
type: "scoresKey",
key: "scores"
}
]);
if (!p) return false;
var sk = p.positive.scores;
return sk.mark.type == "geq" && sk.mark.score == 30 && sk.time.type == "leq" && sk.time.score == 20;
}
}, {
question: "如何设置所有记分项mark不等于255的玩家的记分项mark的分数为255",
answer: "scoreboard\\s+players\\s+set\\s+@a\\[scores=\\{mark=!255\\}\\]\\s+mark\\s+255"
}, {
question: "如何交换玩家A和玩家B的记分项mark的分数",
answer: "scoreboard\\s+players\\s+operation\\s+(A\\s+mark\\s+><\\s+B\\s+mark|B\\s+mark\\s+><\\s+A\\s+mark)"
}]

View File

@ -1,60 +0,0 @@
function random(seed) {
return (seed[0] = (seed[0] * 9301 + 49297) % 233280) / 233280;
}
function hash(s) {
var i, result = 0;
for (i = s.length - 1; i >= 0; i--) result = (result + s.charCodeAt(i)) % 233280;
return result;
}
function wind(str, p) {
var seed = [str.length * p], randoms = [], seq = [], j, t;
for (i = 0; i < str.length; i++) {
randoms[str.length - i - 1] = random(seed);
seq[i] = str.charAt(i);
}
i = 0;
while (i < str.length) {
j = Math.floor(randoms[i] * (i + 1));
t = seq[j];
seq[j] = seq[i];
seq[i] = t;
i++;
}
return seq.join("");
}
function unwind(str, p) {
var seed = [str.length * p], seq = [], j, t;p
for (i = 0; i < str.length; i++) seq[i] = str.charAt(i);
while (i > 0) {
j = Math.floor(random(seed) * i--);
t = seq[j];
if (t == undefined) console.log(i, seed);
seq[j] = seq[i];
seq[i] = t;
}
return seq.join("");
}
function randomstr(base, length) {
var i, r = [];
for (i = 0; i < length; i++) {
r.push(base.charAt(Math.floor(Math.random() * base.length)));
}
return r.join("");
}
function main() {
var i, j, a, b, c, seed;
for (i = 1; i < 600; i++) {
for (j = 0; j < 1000; j++) {
a = randomstr("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()_+-=|\\[{]};:'\",<.>/?", i);
seed = Math.floor(random([hash(a)]) * 233280 / a.length);
b = wind(a, seed);
c = unwind(b, seed);
if (a != c) {
console.log("Test failed. len=" + i + ",seed=" + seed + ",a=" + a);
return;
}
}
console.log("Test #" + i + " completed.");
}
}
main();

View File

@ -1,4 +0,0 @@
var loader = require("../../loader");
var fs = require("fs");
fs.writeFileSync("../DailyQuestion.js", loader.load("./main.js"));
fs.writeFileSync("../../pages/question.html", loader.load("./question.html"));

View File

@ -1,260 +0,0 @@
(function() {/*LOADER
setAfterFill(eval(load("./encrypt.js")));
*/
function random(seed) {
return (seed[0] = (seed[0] * 9301 + 49297) % 233280) / 233280;
}
function unwind(str, p) {
var seed = [str.length * p], seq = [], j, t;p
for (i = 0; i < str.length; i++) seq[i] = str.charAt(i);
while (i > 0) {
j = Math.floor(random(seed) * i--);
t = seq[j];
seq[j] = seq[i];
seq[i] = t;
}
return seq.join("");
}
var Filter = {
allOf : function(r, param) {
param.filters.forEach(function(e) {
if (!Filter[e.type](r, e)) throw "Denied by " + e.type;
});
},
someOf : function(r, param) {
var count = 0;
param.filters.forEach(function(e) {
if (Filter[e.type](r, e)) count++;
});
return count > 0;
},
noneOf : function(r, param) {
param.filters.forEach(function(e) {
if (Filter[e.type](r, e)) throw "Denied by " + e.type;
});
},
noPositiveKeys : function(r, param) {
return Object.keys(r.positive).length == 0;
},
containsPositiveKeys : function(r, param) {
var a = Object.keys(r.positive), i;
for (i in param.keys) if (a.indexOf(param.keys[i]) < 0) return false;
return true;
},
allOfPositiveKeys : function(r, param) {
var a = Object.keys(r.positive), i;
for (i in a) if (param.keys.indexOf(a[i]) < 0) return false;
return true;
},
equalsPositiveKeys : function(r, param) {
var a = Object.keys(r.positive), i;
for (i in a) if (param.keys.indexOf(a[i]) < 0) return false;
return a.length == param.keys.length;
},
noNegativeKeys : function(r, param) {
return r.negative.length == 0;
},
containsNegativeKeys : function(r, param) {
var a = r.negative, i, keys = {};
for (i in a) {
if (param.keys.indexOf(a[i].key) >= 0) {
keys[a[i].key] = 1;
}
}
return param.keys.length == Object.keys(keys).length;
},
allOfNegativeKeys : function(r, param) {
var a = r.negative, i;
for (i in a) if (param.keys.indexOf(a[i].key) < 0) return false;
return true;
},
equalsNegativeKeys : function(r, param) {
var a = r.negative, i, keys = {};
for (i in a) {
if (param.keys.indexOf(a[i].key) >= 0) {
keys[a[i].key] = 1;
} else {
return false;
}
}
return param.keys.length == Object.keys(keys).length;
},
numbericPositiveKeys : function(r, param) {
var a = Object.keys(r.positive), i;
for (i in a) {
if (param.keys.indexOf(a[i]) >= 0) {
r.positive[a[i]] = Number(r.positive[a[i]]);
if (isNaN(r.positive[a[i]])) return false;
}
}
return true;
},
numbericNegativeKeys : function(r, param) {
var a = r.negative, i;
for (i in a) {
if (param.keys.indexOf(a[i].key) >= 0) {
a[i].value = Number(a[i].value);
if (isNaN(a[i].value)) return false;
}
}
return true;
},
scoresKey : function(ks, param) {
var a = ks.positive[param.key], r = {};
if (!a.startsWith("{") || !a.endsWith("}")) return false;
a = a.slice(1, -1).split(",");
a.forEach(function(e) {
var i = e.indexOf("=");
if (i < 0) throw "Cannot find equals sign";
var a = e.slice(0, i), b = e.slice(i + 1), c;
if (b.startsWith("!")) {
r[a] = {
type : "neq",
score : Number(b.slice(1))
}
} else {
i = b.indexOf("..");
if (i < 0) {
r[a] = {
type : "equ",
score : Number(b)
}
} else {
c = b.slice(i + 2);
b = b.slice(0, i);
if (b.length == 0) {
r[a] = {
type : "leq",
score : Number(c)
}
} else if (c.length == 0) {
r[a] = {
type : "geq",
score : Number(b)
}
} else {
r[a] = {
type : "in",
scoreMin : Number(b),
scoreMax : Number(c)
}
if (isNaN(r[a].scoreMin) || isNaN(r[a].scoreMax)) throw "Not a number";
return;
}
}
}
if (isNaN(r[a].score)) throw "Not a number";
});
ks.positive[param.key] = r;
return true;
}
};
var parseSelector = function(s, filters) {
var positive = {}, negative = [], r;
try {
splitSelector(s).forEach(function(e) {
var i = e.indexOf("=");
if (i < 0) throw "Cannot find equals sign";
var a = e.slice(0, i), b = e.slice(i + 1);
if (b.startsWith("!")) {
negative.push({key: a, value: b.slice(1)});
} else {
positive[a] = b;
}
});
r = {positive: positive, negative: negative};
if (filters) {
Filter.allOf(r, {
filters : filters
});
}
return r;
} catch(e) {}
return null;
}
var normalizeSelectorBox = function(pos) {
if (pos.dx < 0) {
pos.dx = -pos.dx; pos.x -= pos.dx;
}
if (pos.dy < 0) {
pos.dy = -pos.dy; pos.y -= pos.dy;
}
if (pos.dz < 0) {
pos.dz = -pos.dz; pos.z -= pos.dz;
}
}
var splitSelector = function(s) {
var arr = [], i, j, k;
i = 0;
while (i < s.length) {
j = s.indexOf(",", i);
if (j < 0) break;
k = s.indexOf("{", i);
if (k >= i && k < j) {
k = s.indexOf("}", k);
if (k < 0) break;
j = s.indexOf(",", k + 1);
if (j < 0) break;
}
arr.push(s.slice(i, j));
i = j + 1;
}
arr.push(s.slice(i));
return arr;
}
var questions = Loader.fromFile("./questions.js");
var i = questions.length, j, t, seed = [questions.length];
while (i > 0) {
j = Math.floor(random(seed) * i--);
t = questions[j];
questions[j] = questions[i];
questions[i] = t;
}
var current = {};
return {
setDate : function(date) {
var i, seed;
current.date = date;
seed = [Math.floor(Math.abs((current.date + 39600000) / 86400000))];
for (i = questions.length - 1; i >= 0; i--) random(seed);
current.base = seed[0];
return this;
},
requestQuestion : function() {
current.random = random([current.base]);
return current.question = questions[Math.floor((current.date + 39600000) / 86400000) % questions.length];
},
requestVerification : function() {
var rnd = random([current.base]);
current.random = 207.913610;
return current.question = {
question: "请问今天的代码是?",
answer: function(s) {
return parseInt(s) == Math.floor(rnd * 1000000);
},
answerType: "number",
verification : true
};
},
checkAnswer : function(answer) {
var cur = current.question, t;
if (answer.startsWith("/")) answer = answer.slice(1);
if (cur.answer instanceof Function) {
if (cur.answer(answer, unwind)) return Math.floor(current.random * 1000000);
} else {
if (t = new RegExp(cur.wp ? unwind(cur.answer, cur.wp) : cur.answer, "").exec(answer)) {
if (t[0].length == answer.length) return Math.floor(current.random * 1000000);
}
}
},
getNextUpdateTime : function() {
return new Date(Math.ceil((current.date + 39600000) / 86400000) * 86400000 - 39600000);
},
getCount : function() {
return questions.length;
},
getLastUpdateAt : function() {
return "2019年2月5日";
}
};
})()

View File

@ -1,182 +0,0 @@
Plugins.inject(function(o) {
var port = 10523, server, connection;
o.name = "调试器";
o.author = "ProjectXero";
o.version = [1, 0, 0];
o.uuid = "56b45fa6-ee17-43c4-968d-05c7bd3ee134";
o.feature("corePlugin");
var preference = ctx.getSharedPreferences("user_settings", ctx.MODE_PRIVATE);
o.menu = [{
text : "启用在线调试器",
hidden : function() {
return o.corePlugin;
},
onclick : function() {
o.requestLoadAsCore();
Common.toast("已启用,下次启动时生效");
}
}, {
text : "关闭在线调试器",
hidden : function() {
return !o.corePlugin;
},
onclick : function() {
o.cancelLoadAsCore();
Common.toast("已关闭,下次启动时生效");
}
}, {
text : "使用外置代码源",
hidden : function() {
return String(preference.getString("debugSource", "")).length > 0;
},
onclick : function() {
Common.showFileDialog({
type : 0,
callback : function(f) {
var intent = new android.content.Intent("com.xero.ca.DEBUG_EXEC")
.setComponent(new android.content.ComponentName("com.xero.ca", "com.xero.ca.MainActivity"))
.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
preference.edit().putString("debugSource", f.result.getAbsolutePath()).apply();
AndroidBridge.createShortcut(intent, "调试启动", com.xero.ca.R.mipmap.icon_small);
Common.toast("源已更改,下次调试启动时生效");
}
});
}
}, {
text : "使用内置代码源",
hidden : function() {
return !String(preference.getString("debugSource", "")).length;
},
onclick : function() {
preference.edit().remove("debugSource").apply();
Common.toast("源已更改,下次调试启动时生效");
}
}, {
text : "打开当前代码源",
onclick : function() {
try {
var sm = ScriptInterface.getScriptManager();
var cls = sm.getClass();
var method = cls.getDeclaredMethod("getScriptReader");
method.setAccessible(true);
var q, s = [], rd = new java.io.BufferedReader(method.invoke(sm));
while (q = rd.readLine()) s.push(q);
rd.close();
var f = new java.io.File(ctx.getExternalCacheDir(), "sourcedump.js");
f.delete();
var fs = new java.io.FileOutputStream(f);
fs.write(new java.lang.String(s.join("\n")).getBytes());
fs.close();
ctx.startActivity(new android.content.Intent(android.content.Intent.ACTION_VIEW)
.setDataAndType(AndroidBridge.fileToUri(f), "text/plain")
.addFlags(android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION | android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION | android.content.Intent.FLAG_ACTIVITY_NEW_TASK));
} catch(e) {
Common.toast(e);
}
}
}, {
text : "导出当前代码源",
onclick : function() {
try {
var sm = ScriptInterface.getScriptManager();
var cls = sm.getClass();
var method = cls.getDeclaredMethod("getScriptReader");
method.setAccessible(true);
var q, s = [], rd = new java.io.BufferedReader(method.invoke(sm));
while (q = rd.readLine()) s.push(q);
rd.close();
Common.showFileDialog({
type : 1,
callback : function(f) {
Common.saveFile(f.result.getAbsolutePath(), s.join("\n"));
Common.toast("代码源已保存");
}
});
} catch(e) {
Common.toast(e);
}
}
}];
MapScript.loadModule("OnlineDebugger", {
unload : function() {
stopServer();
}
});
try {
if (o.corePlugin) startServer();
} catch(e) {Common.toast(e)}
function startServer() {
server = ScriptInterface.createWebSocketHelper(port, {
onOpen : function(conn, handshake) {try {
if (connection) conn.close(1);
connection = conn;
sendVersion();
Log.start(println);
Common.toast("设备" + conn.getRemoteSocketAddress() + "已连接");
} catch(e) {erp(e)}},
onClose : function(conn, code, reason, remote) {try {
Log.stop();
connection = null;
} catch(e) {erp(e)}},
onMessage : function(conn, message) {try {
try {
var o = JSON.parse(message);
switch (o.type) {
case "exec":
executeCommand(o.cmd);
break;
case "ping":
conn.send(JSON.stringify({type : "pong"}));
break;
}
} catch(e) {
Log.e(e);
}
} catch(e) {erp(e)}},
onError : function(conn, err) {
Common.toast(err);
},
onStart : function() {try {
Common.toast("服务器已在端口" + port + "开启");
} catch(e) {erp(e)}}
});
server.setTcpNoDelay(true);
server.start();
}
function stopServer() {
if (!server) return;
server.stop();
server = null;
}
function sendVersion() {
connection.send(JSON.stringify({
type : "version",
version : CA.version,
publishDate : CA.publishDate
}));
}
function executeCommand(cmd) {
if (cmd.startsWith("#")) {
G.ui(function() {
try {
Log.s(eval.call(null, cmd.slice(1)));
} catch(e) {
Log.e(e);
}
});
} else {
try {
Log.s(eval.call(null, cmd));
} catch(e) {
Log.e(e);
}
}
}
function println(level, text) {
connection.send(JSON.stringify({
type : "println",
level : level,
text : text
}));
}
})

View File

@ -1,226 +0,0 @@
Plugins.inject(function(o) {
o.name = "MC图标";
o.author = "ProjectXero";
o.version = [2, 0, 1];
o.uuid = "06b2fb31-668e-4693-92ad-c0ac8da3e7a9";
o.description = "在命令助手中添加MC图标\n\n用法在菜单里点击“显示样式代码栏”然后点击省略号再点击“MC图标”\n或者在菜单里点击“插入……”然后点击“短语”再点击“MC图标”";
o.feature("userExpressionMenuAppendable");
o.init = function() {
Plugins.addExpressionMenu({
text : "MC图标",
get : function() {
MCIcon.show(function(text) {
Common.replaceSelection(CA.cmd.getText(), text);
});
}
});
}
function fixZero(s, n) {
while (n > s.length) {
s = "0" + s;
}
return s;
}
function readAsset(zf, path) {
var entry = zf.getEntry(path);
if (entry == null) return null;
return new java.io.BufferedReader(new java.io.InputStreamReader(zf.getInputStream(entry)));
}
function readAssetJSON(zf, path, defaultValue) {
try{
var rd = readAsset(zf, path);
var s = [], q;
while (q = rd.readLine()) s.push(q);
rd.close();
return JSON.parse(s.join("\n"));
} catch(e) {
return defaultValue;
}
}
MapScript.loadModule("MCIcon", {
preload : function() {
var pkg = NeteaseAdapter.mcPackage;
if (!pkg) throw "未找到Minecraft应用";
this.zipFile = new java.util.zip.ZipFile(ctx.getPackageManager().getApplicationInfo(pkg, 128).publicSourceDir);
this.emoticons = readAssetJSON(this.zipFile, "assets/resource_packs/vanilla/font/emoticons.json", []);
this.initCache();
this.ready = true;
},
checkReady : function() {
if (this.ready) return;
this.preload();
},
getGlyphSheet : function(index) {
var entry = this.zipFile.getEntry("assets/resource_packs/vanilla/font/glyph_" + fixZero(index.toString(16).toUpperCase(), 2) + ".png");
if (!entry) Log.throwError(new Error("GlyphSheet not exist. index=" + index));
var stream = this.zipFile.getInputStream(entry);
var bmp = G.BitmapFactory.decodeStream(stream);
stream.close();
return bmp;
},
getGlyphSheetCached : function(index) {
if (this.glyphSheet[index]) {
return this.glyphSheet[index];
} else {
return this.glyphSheet[index] = this.getGlyphSheet(index);
}
},
getGlyphBitmap : function(code) {
var sheet = this.getGlyphSheetCached(code >> 8);
var width = sheet.getWidth() >> 4, height = sheet.getHeight() >> 4;
var cn = code & 0xf, rn = (code >> 4) & 0xf;
return G.Bitmap.createBitmap(sheet, cn * width, rn * height, width, height);
},
getGlyphBitmapCached : function(code) {
if (this.glyph[code]) {
return this.glyph[code];
} else {
return this.glyph[code] = this.getGlyphBitmap(code);
}
},
initCache : function() {
this.glyph = new Array(65536);
this.glyphSheet = new Array(256);
},
releaseCache : function() {
var i;
for (i in this.glyph) {
if (this.glyph[i]) {
this.glyph[i].recycle();
}
}
for (i in this.glyphSheet) {
if (this.glyphSheet[i]) {
this.glyphSheet[i].recycle();
}
}
this.initCache();
},
getGlyphDrawable : function(code, heightPixels) {
var bmp = this.getGlyphBitmapCached(code);
var drawable = new G.BitmapDrawable(ctx.getResources(), bmp);
drawable.setFilterBitmap(false);
var scaleFactor = heightPixels / bmp.getHeight();
drawable.setBounds(0, 0, bmp.getWidth() * scaleFactor, bmp.getHeight() * scaleFactor);
return drawable;
},
getGlyphSpannable : function(code, heightPixels) {
var span = new G.ImageSpan(this.getGlyphDrawable(code, heightPixels));
var spannableStr = new G.SpannableString(String.fromCharCode(code));
spannableStr.setSpan(span, 0, spannableStr.length(), G.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannableStr;
},
getFontHeightPixel : function(textSize, typeface) {
var pt = new G.Paint();
textSize *= G.sp;
pt.setTextSize(textSize);
if (typeface) pt.setTypeface(typeface);
var fm = pt.getFontMetrics();
return fm.descent - fm.ascent;
},
show : function self(callback) {
if (!self.linear) {
self.vmaker = function(holder) {
var view = new G.ImageView(ctx);
view.setLayoutParams(new G.AbsListView.LayoutParams(64 * G.dp, 64 * G.dp));
view.setPadding(5 * G.dp, 5 * G.dp, 5 * G.dp, 5 * G.dp);
view.setScaleType(G.ImageView.ScaleType.FIT_CENTER);
return view;
}
self.vbinder = function(holder, e) {
if (!e.drawable) e.drawable = MCIcon.getGlyphDrawable(e.code, 64 * G.dp);
holder.self.setImageDrawable(e.drawable);
}
self.init = function() {
MCIcon.checkReady();
self.icons = MCIcon.emoticons.map(function(e) {
return {
name : e.name,
lcname : e.name.toLowerCase(),
code : parseInt(e.code)
};
});
self.fontHeight = MCIcon.getFontHeightPixel(Common.theme.textsize[3]) * 1.5;
self.update("");
}
self.update = function(s) {
s = s.toLowerCase();
self.adpt.setArray(self.icons.filter(function(e) {
return e.lcname.indexOf(s) >= 0;
}));
}
self.adpt = SimpleListAdapter.getController(new SimpleListAdapter([], self.vmaker, self.vbinder));
self.linear = new G.LinearLayout(ctx);
self.linear.setOrientation(G.LinearLayout.VERTICAL);
Common.applyStyle(self.linear, "container_default");
self.header = new G.LinearLayout(ctx);
self.header.setOrientation(G.LinearLayout.HORIZONTAL);
self.header.setPadding(5 * G.dp, 0, 0, 0)
self.header.setLayoutParams(new G.LinearLayout.LayoutParams(-1, -2));
Common.applyStyle(self.header, "bar_float");
self.edit = new G.EditText(ctx);
self.edit.setSingleLine(true);
self.edit.setLayoutParams(new G.LinearLayout.LayoutParams(0, -2, 1.0));
self.edit.setImeOptions(G.EditorInfo.IME_FLAG_NO_FULLSCREEN);
self.edit.setTypeface(G.Typeface.MONOSPACE);
Common.applyStyle(self.edit, "edittext_default", 3);
self.edit.addTextChangedListener(new G.TextWatcher({
afterTextChanged : function(s) {try {
self.update(String(s));
} catch(e) {erp(e)}}
}));
self.header.addView(self.edit);
self.exit = new G.TextView(ctx);
self.exit.setText("×");
self.exit.setGravity(G.Gravity.CENTER);
self.exit.setPadding(10 * G.dp, 0, 10 * G.dp, 0)
self.exit.setLayoutParams(new G.LinearLayout.LayoutParams(-2, -1));
Common.applyStyle(self.exit, "button_critical", 3);
self.exit.setOnClickListener(new G.View.OnClickListener({onClick : function(v) {try {
self.popup.exit();
} catch(e) {erp(e)}}}));
self.header.addView(self.exit);
self.linear.addView(self.header);
self.list = new G.GridView(ctx);
self.list.setAdapter(self.adpt.self);
self.list.setGravity(G.Gravity.CENTER);
self.list.setNumColumns(4);
self.list.setStretchMode(2);
self.list.setLayoutParams(new G.LinearLayout.LayoutParams(-1, -1));
self.list.setOnItemClickListener(new G.AdapterView.OnItemClickListener({onItemClick : function(parent, view, pos, id) {try {
var e = self.adpt.array[pos];
if (self.callback) {
self.popup.exit();
self.callback(MCIcon.getGlyphSpannable(e.code, self.fontHeight));
} else {
self.edit.setText(e.name);
self.edit.setSelection(self.edit.length());
}
} catch(e) {erp(e)}}}));
self.list.setOnItemLongClickListener(new G.AdapterView.OnItemLongClickListener({onItemLongClick : function(parent, view, pos, id) {try {
var e = self.adpt.array[pos];
self.edit.setText(e.name);
self.edit.setSelection(self.edit.length());
return true;
} catch(e) {return erp(e), true}}}));
if (G.style == "Material") {
self.list.setFastScrollEnabled(true);
self.list.setFastScrollAlwaysVisible(false);
}
self.linear.addView(self.list);
self.popup = new PopupPage(self.linear, "mcicon.SelectIcon");
PWM.registerResetFlag(self, "linear");
}
try {
self.init();
} catch(e) {
Common.toast("加载MC图标列表失败\n" + e);
return;
}
self.callback = callback;
self.popup.enter();
}
});
})

View File

@ -1,327 +0,0 @@
{
"name": "WebSocket命令库",
"author": "ProjectXero",
"description": "本命令库包含了只有启用WebSocket服务器并成功连接才能远程执行的命令\n\n部分与吉祥物相关的命令需要订阅事件AgentCommand才能看到返回的内容",
"uuid": "17e3d453-acc9-48a2-9806-f516235ceccd",
"version": [1, 0],
"require": [
"acf728c5-dd5d-4a38-b43d-7c4f18149fbd"
],
"update": "https://projectxero.gitee.io/ca/clib/wsagent.json",
"enums": {
"agentDirection": {
"forward": "向前",
"back": "向后",
"left": "向左",
"right": "向右",
"up": "向上",
"down": "向下"
},
"agentTurnDirection": {
"left": "向左",
"right": "向右"
}
},
"commands": {
"closewebsocket": {
"description": "让Minecraft客户端断开与WebSocket服务器的连接",
"noparams": {}
},
"agent": {
"description": "管理玩家控制的吉祥物(Agent)",
"patterns": {
"move": {
"description": "将玩家的吉祥物向指定方向移动一格",
"params": [
{
"type": "plain",
"name": "move",
"prompt": "将玩家的吉祥物向指定方向移动一格"
},
{
"type": "enum",
"name": "方向",
"list": "agentDirection"
}
]
},
"turn": {
"description": "向指定方向转身",
"params": [
{
"type": "plain",
"name": "turn",
"prompt": "向指定方向转身"
},
{
"type": "enum",
"name": "方向",
"list": "agentTurnDirection"
}
]
},
"attack": {
"description": "攻击指定方向一格方块内的实体",
"params": [
{
"type": "plain",
"name": "attack",
"prompt": "攻击指定方向一格方块内的实体"
},
{
"type": "enum",
"name": "方向",
"list": "agentDirection"
}
]
},
"destroy": {
"description": "强行挖掘指定方向一格的方块,不考虑方块的硬度",
"params": [
{
"type": "plain",
"name": "destroy",
"prompt": "强行挖掘指定方向一格的方块,不考虑方块的硬度"
},
{
"type": "enum",
"name": "方向",
"list": "agentDirection"
}
]
},
"drop": {
"description": "向指定方向丢出吉祥物背包指定格子内的指定数量的物品",
"params": [
{
"type": "plain",
"name": "drop",
"prompt": "向指定方向丢出吉祥物背包指定格子内的指定数量的物品"
},
{
"type": "uint",
"name": "格子序号"
},
{
"type": "uint",
"name": "数量"
},
{
"type": "enum",
"name": "方向",
"list": "agentDirection"
}
]
},
"dropall": {
"description": "向指定方向丢出吉祥物背包内的所有物品",
"params": [
{
"type": "plain",
"name": "dropall",
"prompt": "向指定方向丢出吉祥物背包内的所有物品"
},
{
"type": "enum",
"name": "方向",
"list": "agentDirection"
}
]
},
"inspect": {
"description": "检测指定方向一格方块的ID并返回",
"params": [
{
"type": "plain",
"name": "inspect",
"prompt": "检测指定方向一格方块的ID"
},
{
"type": "enum",
"name": "方向",
"list": "agentDirection"
}
]
},
"inspectdata": {
"description": "检测指定方向一格方块的数据值并返回",
"params": [
{
"type": "plain",
"name": "inspectdata",
"prompt": "检测指定方向一格方块的数据值"
},
{
"type": "enum",
"name": "方向",
"list": "agentDirection"
}
]
},
"detect": {
"description": "检测向指定方向移动是否会被阻挡如果会则返回true否则返回false",
"params": [
{
"type": "plain",
"name": "detect",
"prompt": "检测向指定方向移动是否会被阻挡"
},
{
"type": "enum",
"name": "方向",
"list": "agentDirection"
}
]
},
"detectredstone": {
"description": "检测指定方向一格方块是否处于激活状态或被充能如果满足上述条件则返回true否则返回false",
"params": [
{
"type": "plain",
"name": "detectredstone",
"prompt": "检测指定方向一格方块是否处于激活状态或被充能"
},
{
"type": "enum",
"name": "方向",
"list": "agentDirection"
}
]
},
"transfer": {
"description": "将吉祥物背包源格子内的指定数量的物品移动到目标格子内",
"params": [
{
"type": "plain",
"name": "transfer",
"prompt": "将吉祥物背包源格子内的指定数量的物品移动到目标格子内"
},
{
"type": "uint",
"name": "源格子序号"
},
{
"type": "uint",
"name": "数量"
},
{
"type": "uint",
"name": "目标格子序号"
}
]
},
"createagent": {
"description": "如果玩家无吉祥物,则创建一个属于该玩家的吉祥物",
"params": [
{
"type": "plain",
"name": "create",
"prompt": "如果玩家无吉祥物,则创建一个属于该玩家的吉祥物"
}
]
},
"tpagent": {
"description": "将吉祥物传送到自身所在位置",
"params": [
{
"type": "plain",
"name": "tp",
"prompt": "将吉祥物传送到自身所在位置"
}
]
},
"collect": {
"description": "收集半径一格内指定的物品到吉祥物背包",
"params": [
{
"type": "plain",
"name": "collect",
"prompt": "收集半径一格内指定的物品到吉祥物背包"
},
{
"type": "string",
"name": "物品ID",
"suggestion": "item"
}
]
},
"till": {
"description": "耕指定方向一格的方块",
"params": [
{
"type": "plain",
"name": "till",
"prompt": "耕指定方向一格的方块"
},
{
"type": "enum",
"name": "方向",
"list": "agentDirection"
}
]
},
"place": {
"description": "对指定方向放置(或使用)吉祥物背包指定格子内的方块(或工具),就像玩家点击那样",
"params": [
{
"type": "plain",
"name": "place",
"prompt": "对指定方向放置(或使用)吉祥物背包指定格子内的方块(或工具)"
},
{
"type": "uint",
"name": "格子序号"
},
{
"type": "enum",
"name": "方向",
"list": "agentDirection"
}
]
},
"getitemcount": {
"description": "返回吉祥物背包指定格子内的物品的堆叠数量",
"params": [
{
"type": "plain",
"name": "getitemcount",
"prompt": "返回吉祥物背包指定格子内的物品的堆叠数量"
},
{
"type": "uint",
"name": "格子序号"
}
]
},
"getitemspace": {
"description": "返回吉祥物背包指定格子内剩余可堆叠的相同物品数",
"params": [
{
"type": "plain",
"name": "getitemspace",
"prompt": "返回吉祥物背包指定格子内剩余可堆叠的相同物品数"
},
{
"type": "uint",
"name": "格子序号"
}
]
},
"getitemdetail": {
"description": "返回吉祥物背包指定格子内的物品的ID",
"params": [
{
"type": "plain",
"name": "getitemdetail",
"prompt": "返回吉祥物背包指定格子内的物品的ID"
},
{
"type": "uint",
"name": "格子序号"
}
]
}
}
}
}
}

View File

@ -1,15 +0,0 @@
(function() {try {//已经弃用 命令助手已经支持自定义更新了
Updater.checkUpdate(function(){});
return {
"name": "自动检查更新",
"author": "ProjectXero",
"description": "今天是" + new Date().toLocaleDateString(),
"uuid": "45dd9a7c-a129-42ca-9135-036886f2c3c4",
"version": [0, 0, 1],
"require": [],
"commands": {},
"enums": {},
"selectors": {},
"help": {}
};
} catch(e) {}})()

View File

@ -1,823 +0,0 @@
(function self() {try {
var basePath, filterPath, exportPath, wikiDataPath, resPack;
function initFiles(rp) {
resPack = rp;
basePath = new java.io.File(path).getParent() + "/";
filterPath = basePath + resPack + "/filter.json";
exportPath = basePath + resPack + "/export.json";
wikiDataPath = basePath + "suggestion.json";
}
function switchResPack() {
var r = [{
text : "普通",
description : "vanilla"
}, {
text : "化学(教育版)",
description : "chemistry"
}];
Common.showListChooser(r, function(i) {
initFiles(r[i].description);
Common.toast("资源包已切换为" + resPack);
});
}
function editFilter() {
var f = loadFilter();
JSONEdit.show({
source : f,
update : function() {
saveFilter(f);
}
});
}
function loadFilter() {
var f = MapScript.readJSON(filterPath, null);
if (!f) f = importFromCA();
if (!f.blockname) f.blockname = {};
if (!f.itemname) f.itemname = {};
if (!f.soundname) f.soundname = {};
if (!f.entityname) f.entityname = {};
if (!f.particlename) f.particlename = {};
if (!f.blockadd) f.blockadd = [];
if (!f.blockremove) f.blockremove = [];
if (!f.itemadd) f.itemadd = [];
if (!f.itemremove) f.itemremove = [];
if (!f.entityadd) f.entityadd = [];
if (!f.entityremove) f.entityremove = [];
if (!f.entitysummonable) f.entitysummonable = {};
return f;
}
function saveFilter(o) {
Common.saveFile(filterPath, JSON.stringify(o, null, "\t"));
}
function loadExport() {
return MapScript.readJSON(exportPath, null);
}
function saveExport(o) {
Common.saveFile(exportPath, JSON.stringify(o, null, "\t"));
}
function getExportData() {
var z = loadExport();
if (!z) return null;
var i, entities = {}, e, hasMinecraftNamespace = CA.Library.checkPackVer({minSupportVer : "1.8"}) == 0;
for (i in z.entity) {
e = z.entity[i];
if (z.entity_summonable[i] == "unsummonable") {
e += "(无法用summon生成)";
}
if (hasMinecraftNamespace && z.entity_minecraft[i]) {
entities["minecraft:" + i] = e;
} else {
entities[i] = e;
}
}
return {
"block" : z.block,
"item" : z.item,
"sound" : z.sound,
"entity" : entities,
"particle_emitter" : z.particle
}
}
function loadWikiData() {
return MapScript.readJSON(wikiDataPath, null);
}
function getPackageName() {
return NeteaseAdapter.mcPackage;
}
function showProgress() {
var r = Common.showProgressDialog(null, true);
r.info = "";
var rf = new java.lang.Runnable(function() {try {
r.setText(r.info);
gHandler.postDelayed(this, 50);
} catch(e) {erp(e)}});
gHandler.post(rf);
return r;
}
function startTranslate(prg) {try {
prg.info = "初始化";
var pkg = getPackageName();
if (!pkg) {
Common.toast("未找到合适的Minecraft版本");
return;
}
var zf = new java.util.zip.ZipFile(ctx.getPackageManager().getApplicationInfo(pkg, 128).publicSourceDir);
prg.info = "正在加载语言数据";
var lang = initLang(zf, "assets/resource_packs/" + resPack + "/texts/zh_CN.lang", prg);
prg.info = "正在加载相关JSON";
var items = Object.keys(readAssetJSON(zf, "assets/resource_packs/" + resPack + "/items_client.json", {}).items || {}),
blocks = Object.keys(readAssetJSON(zf, "assets/resource_packs/" + resPack + "/blocks.json", {})),
sounds = Object.keys(readAssetJSON(zf, "assets/resource_packs/" + resPack + "/sounds/sound_definitions.json", {})),
entities = listAssetFiles(zf, "assets/behavior_packs/" + resPack + "/entities/").map(function(e) {
try {
var k = readAssetJSON(zf, e, null)["minecraft:entity"];
if (k.description) return k.description.identifier;
return k.components["minecraft:identifier"].id;
} catch(e) {Log.e(e)}
}).filter(function(e) {
return e != null;
}),
particles = Log.d([].concat(listAssetFiles(zf, "assets/particles/"), listAssetFiles(zf, "assets/resource_packs/" + resPack + "/particles/"))).map(function(e) {
var k;
try {
var k = readAssetJSON(zf, e, null);
if (k.particles) return Object.keys(k.particles);
return k.particle_effect.description.identifier;
} catch(e) {Log.e(e)}
}).reduce(function(acc, e) {
return Array.isArray(e) ? acc.concat(e) : (acc.push(e), acc);
}, []),
imports = loadFilter();
var ret = {
block : {},
block_src : {},
block_notranslation : {},
item : {},
item_src : {},
item_notranslation : {},
sound : {},
sound_src : {},
sound_notranslation : {},
entity : {},
entity_src : {},
entity_notranslation : {},
entity_minecraft : {},
entity_summonable : {},
particle : {},
particle_src : {},
particle_notranslation : {}
};
prg.info = "正在加载过滤器";
if (imports.itemremove) imports.itemremove.forEach(function(e) {
var t = items.indexOf(e);
if (t >= 0) items.splice(t, 1);
});
if (imports.itemadd) imports.itemadd.forEach(function(e) {
var t = items.indexOf(e);
if (t < 0) items.push(e);
});
if (imports.blockremove) imports.blockremove.forEach(function(e) {
var t = blocks.indexOf(e);
if (t >= 0) blocks.splice(t, 1);
});
if (imports.blockadd) imports.blockadd.forEach(function(e) {
var t = blocks.indexOf(e);
if (t < 0) blocks.push(e);
});
if (imports.entityremove) imports.entityremove.forEach(function(e) {
var t = entities.indexOf(e);
if (t >= 0) entities.splice(t, 1);
});
if (imports.entityadd) imports.entityadd.forEach(function(e) {
var t = entities.indexOf(e);
if (t < 0) entities.push(e);
});
prg.info = "正在排序";
blocks.sort(); items.sort(); entities.sort();
blocks.forEach(function(e, i, a) {
var el = e.toLowerCase();
prg.info = "正在翻译方块ID" + e;
if (el in imports.blockname) {
ret.block[el] = imports.blockname[el];
ret.block_src[el] = ret.block[el] ? "filter" : "filter_void";
} else if (("tile." + e + ".name") in lang) {
ret.block[el] = lang["tile." + e + ".name"];
ret.block_src[el] = "lang_exact";
} else {
ret.block[el] = searchObject(lang, new RegExp("tile\\." + e + "\\..*name")).values.join("/");
if (ret.block[el].length) {
ret.block_src[el] = "lang";
} else {
ret.block_notranslation[e] = "NoTranslation";
}
}
});
items.forEach(function(e, i, a) {
var el = e.toLowerCase();
if (el in ret.block) return;
prg.info = "正在翻译物品ID" + e;
if (el in imports.itemname) {
ret.item[el] = imports.itemname[el];
ret.item_src[el] = ret.item[el] ? "filter" : "filter_void";
} else if (("item." + e + ".name") in lang) {
ret.item[el] = lang["item." + e + ".name"];
ret.item_src[el] = "lang_exact";
} else {
ret.item[el] = searchObject(lang, new RegExp("item\\." + e + "\\..*name")).values.join("/");
if (ret.item[el].length) {
ret.item_src[el] = "lang";
} else {
ret.item_notranslation[e] = "NoTranslation";
}
}
});
sounds.forEach(function(e, i, a) {
prg.info = "正在翻译声音ID" + e;
if (e in imports.soundname) {
ret.sound[e] = imports.soundname[e];
ret.sound_src[e] = ret.sound[e] ? "filter" : "filter_void";
} else {
ret.sound[e] = "";
ret.sound_notranslation[e] = "NoTranslation";
}
});
entities.forEach(function(e, i, a) {
var minecraftOwn = e.startsWith("minecraft:");
if (minecraftOwn) e = e.slice(10);
if (e in ret.entity) return;
prg.info = "正在翻译实体ID" + e;
if (e in imports.entityname) {
ret.entity[e] = imports.entityname[e];
ret.entity_src[e] = ret.entity[e] ? "filter" : "filter_void";
} else if (("entity." + e + ".name") in lang) {
ret.entity[e] = lang["entity." + e + ".name"];
ret.entity_src[e] = "lang_exact";
} else {
ret.entity[e] = "";
ret.entity_notranslation[e] = "NoTranslation";
}
ret.entity_minecraft[e] = minecraftOwn;
ret.entity_summonable[e] = e in imports.entitysummonable ? imports.entitysummonable[e] : "summonable";
});
particles.forEach(function(e, i, a) {
prg.info = "正在翻译粒子ID" + e;
if (e in imports.particlename) {
ret.particle[e] = imports.particlename[e];
ret.particle_src[e] = ret.particle[e] ? "filter" : "filter_void";
} else {
ret.particle[e] = "";
ret.particle_notranslation[e] = "NoTranslation";
}
});
prg.info = "正在保存文件";
saveExport(ret);
Common.toast("翻译已保存,重启命令助手后将应用");
} catch(e) {
Common.toast("翻译出错!\n" + e + "\n" + e.stack);
}}
function readAsset(zf, path) {
var entry = zf.getEntry(path);
if (entry == null) return null;
return new java.io.BufferedReader(new java.io.InputStreamReader(zf.getInputStream(entry)));
}
function listAssetFiles(zf, path) {
var entries = zf.entries(), e, r = [];
while (entries.hasMoreElements()) {
e = entries.nextElement();
if (!e.isDirectory() && e.getName().startsWith(path)) {
r.push(String(e.getName()));
}
}
return r;
}
function initLang(zf, path, prg) {
var rd = readAsset(zf, path), q, di, ei, t, r = {};
if (!rd) return r;
while (q = rd.readLine()) {
if (q.startsWith("##")) continue;
di = q.indexOf("=");
if (di < 0) continue;
ei = q.indexOf("\t", di);
if (ei < 0) ei = q.length();
r[t = q.substring(0, di)] = String(q.substring(di + 1, ei));
prg.info = "正在加载语言ID" + t;
}
rd.close();
return r;
}
function readJSON(path, defaultValue) {
try{
var rd = java.io.BufferedReader(new java.io.FileReader(path));
var s = [], q;
while (q = rd.readLine()) s.push(q);
rd.close();
return eval("(" + s.join("\n") + ")");
} catch(e) {
return defaultValue;
}
}
function readAssetJSON(zf, path, defaultValue) {
try{
var rd = readAsset(zf, path);
var s = [], q;
while (q = rd.readLine()) s.push(q);
rd.close();
return eval("(" + s.join("\n") + ")");
} catch(e) {
return defaultValue;
}
}
function saveCSV(path, obj) {
var f = new java.io.File(path).getParentFile();
if (f) f.mkdirs();
var wr = new java.io.FileOutputStream(path);
wr.write(new java.lang.String(Object.keys(obj).map(function(e) {
return e + "," + obj[e];
}).join("\n")).getBytes());
wr.close();
}
function searchObject(obj, v) {
var rk = [], rp = [];
(Object.keys(obj)).forEach(function(e, i, a) {
if (e.search(v) >= 0) {
rk.push(e);
rp.push(obj[e]);
}
});
return {
keys : rk,
values : rp
};
}
function httpGet(url) {
var url = new java.net.URL(url);
var conn = url.openConnection();
conn.setConnectTimeout(5000);
conn.setUseCaches(true);
conn.setRequestMethod("GET");
conn.connect();
var rd = new java.io.BufferedReader(new java.io.InputStreamReader(conn.getInputStream()));
var s = [], ln, r;
while (ln = rd.readLine()) s.push(ln);
rd.close();
return s.join("\n");
}
function fetchWikiSource(page) {
var html = httpGet("https://minecraft-zh.gamepedia.com/index.php?title=" + encodeURI(page) + "&action=edit");
var sp = html.match(/<textarea .* name="wpTextbox1">([^]*)<\/textarea>/);
return sp[1];
}
function convertList(data, prg) {
var r = {};
data.split("\n").forEach(function(e) {
var ret = e.match(/\['(.*)'\] = '(.*)'/);
if (ret && !e.startsWith("--")) {
r[ret[1]] = ret[2];
prg.info = "正在处理列表:" + ret[1];
}
});
return r;
}
function fetchTranslation(prg) {try {
prg.info = "正在获取方块标准化译名列表";
var blocks = convertList(fetchWikiSource("模块:Autolink/Block"), prg);
prg.info = "正在获取物品标准化译名列表";
var items = convertList(fetchWikiSource("模块:Autolink/Item"), prg);
prg.info = "正在获取其他标准化译名列表";
var others = convertList(fetchWikiSource("模块:Autolink/Other"), prg);
prg.info = "正在保存标准化译名列表";
Common.saveFile(wikiDataPath, JSON.stringify({
block : blocks,
item : items,
others : others
}, null, "\t"));
Common.toast("标准化译名数据已保存");
} catch(e) {
Common.toast("获取出错!\n" + e + "\n" + e.stack);
}}
function exportAsCode() {
var d = getExportData();
if (!d) {
Common.toast("请先启动翻译");
return;
}
Common.setClipboardText(JSON.stringify(getExportData(), null, "\t").replace(/^\{\s*/, "").replace(/\n\}$/, ",").replace(/\n/g, "\n\t"));
Common.toast("代码已复制");
}
function importFromCA() {
var p = CA.Library.inner.default.enums;
var i, r = Object.copy({
blockname : p.block,
itemname : p.item,
soundname : p.sound,
entityname : p.entity,
particlename : p.particle_emitter
});
for (i in r.blockname) if (!r.blockname[i]) delete r.blockname[i];
for (i in r.itemname) if (!r.itemname[i]) delete r.itemname[i];
for (i in r.soundname) if (!r.soundname[i]) delete r.soundname[i];
for (i in r.entityname) if (!r.entityname[i]) delete r.entityname[i];
for (i in r.particlename) if (!r.particlename[i]) delete r.particlename[i];
return r;
}
var showTranslation = function self(o, onModify) {
if (!self.popup) {
self.vmaker = function(holder) {
var layout = holder.layout = new G.LinearLayout(ctx),
text1 = holder.text1 = new G.TextView(ctx),
text2 = holder.text2 = new G.TextView(ctx);
layout.setLayoutParams(new G.AbsListView.LayoutParams(-1, -2));
layout.setOrientation(G.LinearLayout.HORIZONTAL);
layout.setPadding(10 * G.dp, 10 * G.dp, 10 * G.dp, 10 * G.dp);
text1.setLayoutParams(new G.LinearLayout.LayoutParams(0, -2, 3));
text1.setTextSize(Common.theme.textsize[1]);
layout.addView(text1);
text2.setLayoutParams(new G.LinearLayout.LayoutParams(0, -2, 1));
text2.setTextSize(Common.theme.textsize[1]);
text2.setGravity(G.Gravity.RIGHT);
layout.addView(text2);
return layout;
}
self.vbinder = function(holder, e) {
holder.text1.setText(e.name);
if (e.onClick) {
holder.text1.setTextColor(Common.theme.highlightcolor);
holder.text2.setText(">");
holder.text2.setTextColor(Common.theme.textcolor);
} else {
holder.text1.setTextColor(self.textColor[e.state]);
holder.text2.setText(e.translation);
holder.text2.setTextColor(e.match ? Common.theme.highlightcolor : Common.theme.textcolor);
}
}
self.textColor = {
filter : Common.theme.highlightcolor,
filter_void : Common.theme.highlightcolor,
lang_exact : Common.theme.textcolor,
lang : Common.theme.criticalcolor,
notranslation : Common.theme.promptcolor
}
self.menu = [{
name : "关闭",
onClick : function() {
self.popup.exit();
}
}, {
name : "导出为文本",
onClick : function() {
self.exportAsText();
}
}, {
name : "查看统计信息(修改前)",
onClick : function() {
self.showStat();
}
}];
self.refresh = function() {
var i, e, t;
var a, b, c, states = {
filter : [],
filter_void : [],
lang_exact : [],
lang : [],
notranslation : []
}, stat = {
filter : 0,
filter_void : 0,
lang_exact : 0,
lang : 0,
wikiMatch : 0,
translated : 0,
untranslated : 0,
total : 0
}
a = self.data.items; b = self.data.sources, c = self.data.suggestion;
for (i in b) {
e = {
name : i,
translation : a[i],
state : b[i],
match : a[i] in c
};
states[e.state].push(e);
stat[e.state]++;
stat.translated++;
if (e.match) stat.wikiMatch++;
}
stat.total = Object.keys(a).length;
a = self.data.notranslation;
for (i in a) {
states.notranslation.push({
name : i,
translation : "缺少翻译",
state : "notranslation"
});
stat.untranslated++;
}
self.statInfo = stat;
for (i in states) states[i].sort(function(a, b) {
return a.name.localeCompare(b.name);
});Log.s(self.data)
self.list.setAdapter(t = new SimpleListAdapter(self.menu.concat(states.notranslation, states.lang, states.lang_exact, states.filter_void, states.filter), self.vmaker, self.vbinder));
self.adpt = SimpleListAdapter.getController(t);
}
self.editItem = function(pos, data, modifier) {
CA.Assist.editParamDialog({
param : {
type : "text",
name : data.name,
suggestion : self.data.suggestion
},
text : data.state == "notranslation" ? "" : data.translation
}, function(s) {
data.translation = s;
data.state = "filter";
data.match = s in self.data.suggestion;
self.adpt.rebind(pos);
modifier(data.name, data.translation);
});
}
self.showStat = function() {
var i = self.statInfo;
Common.showTextDialog([
"总数:" + i.total,
"未翻译:" + i.untranslated,
"翻译完成度:" + (i.translated / i.total * 100).toFixed(2) + "% (" + i.translated + "条)",
"Wiki匹配率" + (i.wikiMatch / i.total * 100).toFixed(2) + "% (" + i.wikiMatch + "条)",
"过滤器来源:" + (i.filter + i.filter_void) + " (" + i.filter + "条包含翻译|"+ i.filter_void + "条不包含翻译)",
"语言文件来源:" + (i.lang + i.lang_exact) + " (精确查找:" + i.lang_exact + "条|模糊查找:"+ i.lang + "条)"
].join("\n"));
}
self.saveFileDialog = function(text) {
Common.showFileDialog({
type : 1,
callback : function(f) {
Common.saveFile(f.result, text);
Common.toast("文件已保存。");
}
});
}
self.exportAsText = function() {
Common.showOperateDialog([{
text : "JSON文件",
onclick : function() {
var kv = self.data.items;
self.saveFileDialog(JSON.stringify(kv, null, 4));
}
}, {
text : "TXT文件分隔符=>",
onclick : function() {
var kv = self.data.items;
self.saveFileDialog(Object.keys(kv).map(function(k) {
return k + " => " + kv[k];
}).join("\n"));
}
}, {
text : "CSV文件分隔符,",
onclick : function() {
var kv = self.data.items;
self.saveFileDialog(Object.keys(kv).map(function(k) {
return k + "," + kv[k];
}).join("\n"));
}
}, {
text : "百度输入法自定义符号表INI文件分隔符空格",
onclick : function() {
var kv = self.data.items;
self.saveFileDialog("[" + self.data.title + ",1,0]\n" + Object.keys(kv).map(function(k) {
return k + " " + kv[k];
}).join("\n"));
}
}]);
}
self.frame = new G.FrameLayout(ctx);
self.frame.setBackgroundColor(Common.theme.message_bgcolor);
self.list = new G.ListView(ctx);
self.list.setLayoutParams(new G.FrameLayout.LayoutParams(-1, -1));
self.list.setBackgroundColor(G.Color.TRANSPARENT);
self.list.setOnItemClickListener(new G.AdapterView.OnItemClickListener({onItemClick : function(parent, view, pos, id) {try {
var data = parent.getAdapter().getItem(pos);
if (data.onClick) {
data.onClick();
return;
}
if (self.onModify) self.editItem(pos, data, self.onModify);
} catch(e) {erp(e)}}}));
if (G.style == "Material") {
self.list.setFastScrollEnabled(true);
self.list.setFastScrollAlwaysVisible(false);
}
self.frame.addView(self.list);
self.popup = new PopupPage(self.frame, "xero.Translation");
PWM.registerResetFlag(self, "popup");
}
self.data = o;
self.onModify = onModify;
if (!o.suggestion) o.suggestion = {};
self.popup.enter();
self.refresh();
}
function convertWikiData(o) {
var i, r = {}, t;
for (i in o) {
t = o[i].lastIndexOf("|");
if (t >= 0) {
r[o[i].slice(t + 1)] = i;
} else {
r[o[i]] = i;
}
}
return r;
}
function showExport() {
var d = loadExport(), w = loadWikiData();
if (!d) {
Common.toast("请先启动翻译");
return;
}
Common.showOperateDialog([{
text : "方块",
onclick : function() {
showTranslation({
title : "方块",
items : d.block,
sources : d.block_src,
notranslation : d.block_notranslation,
suggestion : w ? convertWikiData(w.block) : null,
}, function(name, translation) {
var a = loadFilter();
a.blockname[name] = translation;
saveFilter(a);
});
}
}, {
text : "物品",
onclick : function() {
showTranslation({
title : "物品",
items : d.item,
sources : d.item_src,
notranslation : d.item_notranslation,
suggestion : w ? convertWikiData(w.item) : null
}, function(name, translation) {
var a = loadFilter();
a.itemname[name] = translation;
saveFilter(a);
});
}
}, {
text : "声音",
onclick : function() {
showTranslation({
title : "声音",
items : d.sound,
sources : d.sound_src,
notranslation : d.sound_notranslation
}, function(name, translation) {
var a = loadFilter();
a.soundname[name] = translation;
saveFilter(a);
});
}
}, {
text : "实体",
onclick : function() {
showTranslation({
title : "实体",
items : d.entity,
sources : d.entity_src,
notranslation : d.entity_notranslation,
suggestion : w ? convertWikiData(w.others) : null
}, function(name, translation) {
var a = loadFilter();
a.entityname[name] = translation;
saveFilter(a);
});
}
}, {
text : "实体是否可生成",
onclick : function() {
var i, sources = {};
for (i in d.entity_summonable) sources[i] = "filter";
showTranslation({
title : "实体是否可生成",
items : d.entity_summonable,
sources : sources,
notranslation : {},
suggestion : {
"summonable": "可用summon生成",
"unsummonable": "不可用summon生成"
}
}, function(name, translation) {
var a = loadFilter();
a.entitysummonable[name] = translation;
saveFilter(a);
});
}
}, {
text : "粒子",
onclick : function() {
showTranslation({
title : "粒子",
items : d.particle,
sources : d.particle_src,
notranslation : d.particle_notranslation
}, function(name, translation) {
var a = loadFilter();
a.particlename[name] = translation;
saveFilter(a);
});
}
}]);
}
function viewJSON(o) {
JSONEdit.show({
source : o
});
}
function openApk() {
var pkg = getPackageName();
if (!pkg) {
Common.toast("未找到合适的Minecraft版本");
return;
}
var zf = new java.util.zip.ZipFile(ctx.getPackageManager().getApplicationInfo(pkg, 128).publicSourceDir);
Common.showOperateDialog([{
text : "zh_CN.lang",
onclick : function() {
var prg = showProgress();
prg.async(function() {
viewJSON(initLang(zf, "assets/resource_packs/" + resPack + "/texts/zh_CN.lang", prg));
});
}
}, {
text : "blocks.json",
onclick : function() {
viewJSON(readAssetJSON(zf, "assets/resource_packs/" + resPack + "/blocks.json", {}));
}
}, {
text : "items_client.json",
onclick : function() {
viewJSON(readAssetJSON(zf, "assets/resource_packs/" + resPack + "/items_client.json", {}));
}
}, {
text : "sound_definitions.json",
onclick : function() {
viewJSON(readAssetJSON(zf, "assets/resource_packs/" + resPack + "/sounds/sound_definitions.json", {}));
}
}]);
}
initFiles("vanilla");
var r = {
"name": "自定义ID表",
"author": "ProjectXero",
"description": "已在" + basePath + "上加载",
"uuid": "41e7d897-8f85-441a-8a81-89573cd6cfaf",
"version": [0, 0, 6],
"require": [],
"menu" : [{
text : "切换资源包",
onclick : function() {
switchResPack();
}
}, {
text : "编辑过滤器",
onclick : function() {
editFilter();
}
}, {
text : "提取Wiki翻译",
onclick : function() {
var prg = showProgress();
prg.async(fetchTranslation);
}
}, {
text : "查看安装包源数据",
onclick : function() {
openApk();
}
}, {
text : "启动翻译",
onclick : function() {
var prg = showProgress();
prg.async(startTranslate);
}
}, {
text : "查看翻译",
onclick : function() {
showExport();
}
}, {
text : "导出为代码",
onclick : function() {
exportAsCode();
}
}]
}, z = getExportData();
if (z) {
r.versionPack = {
"ids": {
"mode": "overwrite",
"enums": z
},
"base": {
"enums": {
"item": "block"
}
}
}
}
return r;
} catch(e) {
return {
"name": "自定义ID表",
"author": "ProjectXero",
"description": "加载失败:" + e,
"uuid": "41e7d897-8f85-441a-8a81-89573cd6cfaf",
"version": [0, 0, 6],
"require": []
};
}
})()

View File

@ -1,167 +0,0 @@
(function self() {
function readAsset(path) {
var entry = zf.getEntry(path);
if (entry == null) return null;
return new java.io.BufferedReader(new java.io.InputStreamReader(zf.getInputStream(entry)));
}
function initLang(path) {
var rd = readAsset(path), q, z, r = {};
while (q = rd.readLine()) {
z = (/(.+?)\=(.*)#/).exec(q);
if (!z) continue;
r[z[1]] = z[2].replace(/\s*$/, "");
}
rd.close();
return r;
}
function readAssetJSON(path, defaultValue) {
try{
var rd = readAsset(path);
var s = [], q;
while (q = rd.readLine()) s.push(q);
rd.close();
return eval("(" + s.join("\n") + ")");
} catch(e) {
return defaultValue;
}
}
function searchObject(obj, v) {
var rk = [], rp = [];
(Object.keys(obj)).forEach(function(e, i, a) {
if (e.search(v) >= 0) {
rk.push(e);
rp.push(obj[e]);
}
});
return {
keys : rk,
values : rp
};
}
try {
var pkgname = CA.settings._autoid_pkgname;
var ret, result;
if (!pkgname) {
Common.toast("[自适配ID表]请稍候……");
var pm = ctx.getPackageManager();
var lp = pm.getInstalledPackages(0).toArray();
var i, j, as, r = [], f;
for (i in lp) {
if (!lp[i].applicationInfo) continue;
f = true;
try { //非常神奇的Exception:Package manager has died
as = pm.getPackageInfo(lp[i].packageName, 1).activities;
for (j in as) {
if (as[j].name == "com.mojang.minecraftpe.MainActivity") {
f = false;
break;
}
}
if (f) continue;
} catch(e) {}
r.push({
text : pm.getApplicationLabel(lp[i].applicationInfo),
description : lp[i].versionName,
result : lp[i].packageName
});
}
if (r.length > 0) {
Common.toast("[自适配ID表]请选择您期望从哪个应用中提取ID表选中后将无法更改");
var lock = new java.util.concurrent.Semaphore(0);
Common.showListChooser(r, function(id) {
CA.settings._autoid_pkgname = String(r[id].result);
}, false, function() {
lock.release();
});
lock.acquire();
if (CA.settings._autoid_pkgname) {
ret = self().versionPack.ids.enums;
}
} else {
Common.toast("[自适配ID表]找不到可供提取的应用");
}
} else {
Common.toast("[自适配ID表]请稍候……正在生成ID表\n(1/5)读取语言文件");
var zf = new java.util.zip.ZipFile(ctx.getPackageManager().getApplicationInfo(pkgname, 128).publicSourceDir);
var lang = initLang("assets/resource_packs/vanilla/texts/zh_CN.lang");
Common.toast("[自适配ID表]请稍候……正在生成ID表\n(2/5)读取资源包信息");
var items = Object.keys(readAssetJSON("assets/resource_packs/vanilla/items_client.json").items),
blocks = Object.keys(readAssetJSON("assets/resource_packs/vanilla/blocks.json")),
sounds = Object.keys(readAssetJSON("assets/resource_packs/vanilla/sounds/sound_definitions.json"));
ret = {
block : {},
item : {},
sound : {}
}
Common.toast("[自适配ID表]请稍候……正在生成ID表\n(3/5)尝试匹配物品中文译名");
items.forEach(function(e, i, a) {
ret.item[e.toLowerCase()] = ("item." + e + ".name") in lang ? lang["item." + e + ".name"] : searchObject(lang, new RegExp("item\\." + e + "\\..*name")).values.join("/");
});
Common.toast("[自适配ID表]请稍候……正在生成ID表\n(4/5)尝试匹配方块中文译名");
blocks.forEach(function(e, i, a) {
ret.block[e.toLowerCase()] = ("tile." + e + ".name") in lang ? lang["tile." + e + ".name"] : searchObject(lang, new RegExp("tile\\." + e + "\\..*name")).values.join("/");
});
Common.toast("[自适配ID表]请稍候……正在生成ID表\n(5/5)生成声音列表");
Object.keys(ret.block).forEach(function(e, i, a) {
ret.item[e] = ret.block[e];
});
sounds.forEach(function(e, i, a) {
ret.sound[e] = "";
});
}
var menu = [{
text : "重置ID表",
onclick : function() {
CA.settings._autoid_pkgname = null;
Common.toast("[自适配ID表]ID表重置成功将在下次应用时生效。");
}
}, {
text : "创建静态副本",
onclick : function(v, tag) {
Common.showFileDialog({
type : 1,
callback : function(f) {
var fp = String(f.result.getAbsolutePath());
result.name = "自适配ID表(静态版本)";
delete result.menu;
CA.IntelliSense.disableLibrary(tag.data.src);
CA.IntelliSense.savePrefixed(fp, result);
CA.IntelliSense.enableLibrary(fp);
Common.toast("[自适配ID表]静态ID表创建成功将在下次应用时生效。");
}
});
}
}]
result = {
"name": "自适配ID表",
"author": "ProjectXero",
"description": ret ? "已配置成功" : "未配置",
"uuid": "04a9e9b2-8fae-4f30-84fa-d52f9457f4eb",
"version": [0, 0, 2],
"require": [],
"update" : "https://projectxero.gitee.io/ca/clib/autoid.json",
"menu" : menu
};
if (ret) {
result.versionPack = {
"ids": {
"mode": "overwrite",
"enums": ret
}
}
Common.toast("[自适配ID表]已生成ID表并导入");
}
return result;
} catch(e) {
CA.settings._autoid_pkgname = null;
return {
"name": "自适配ID表",
"author": "ProjectXero",
"description": "加载失败:" + e,
"uuid": "04a9e9b2-8fae-4f30-84fa-d52f9457f4eb",
"version": [0, 0, 2],
"require": [],
"update" : "https://projectxero.gitee.io/ca/clib/autoid.json"
};
}
})()

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +0,0 @@
{
"sourceId": "7c9d392b-7a1f-4226-a35a-a1137cf64e47",
"sourceUrl": "https://projectxero.gitee.io/ca/clib/",
"sourceDir": "pages/clib/",
"pageLimit": 10,
"public": [{
"id": "idmapeditor",
"src": "clib/自定义ID表编辑器.js",
"name": "自定义ID表",
"author": "ProjectXero",
"description": "[开发者专用]使用本拓展包您可以自定义ID的翻译增删ID。目前支持方块、物品、声音和粒子的ID。",
"uuid": "41e7d897-8f85-441a-8a81-89573cd6cfaf",
"version": [0, 0, 6]
}, {
"id": "mcicon",
"src": "clib/MC图标.js",
"name": "MC图标",
"author": "ProjectXero",
"description": "允许命令助手显示MC的图标",
"uuid": "06b2fb31-668e-4693-92ad-c0ac8da3e7a9",
"version": [2, 0, 0],
"link": "https://projectxero.gitee.io/ca/mcemoji.html"
}, {
"id": "wsagent",
"src": "clib/WebSocket命令库.json",
"name": "WebSocket命令库",
"author": "ProjectXero",
"description": "本命令库包含了只有启用WebSocket服务器并成功连接才能远程执行的命令",
"uuid": "17e3d453-acc9-48a2-9806-f516235ceccd",
"version": [1, 0],
"requirement": "请确认您会使用命令助手的WebSocket服务器并能成功连接后再下载"
}],
"signKey": "clib/libsource.pem",
"verifyKey": "clib/libsourcepub.pem",
"lockFile": "clibs_lock.json",
"maintainer": "ProjectXero",
"details": "本站托管于Gitee\n++官方拓展包源++"
}

View File

@ -1 +0,0 @@
{"clib":{"04a9e9b2-8fae-4f30-84fa-d52f9457f4eb":"vnNP+qW/1iyXcWeSHPvrn3a007g=","06b2fb31-668e-4693-92ad-c0ac8da3e7a9":"daDVYjrUl3eaquEQ1UrZ+N9sxFg=","41e7d897-8f85-441a-8a81-89573cd6cfaf":"JFHTVSMF6uZWwFCFzc1FSpitykI=","17e3d453-acc9-48a2-9806-f516235ceccd":"DRUA3VloefCJOjO9ASDNXI5KZTo="}}

2
config/import.txt Normal file
View File

@ -0,0 +1,2 @@
@androidJarPath C:\Users\Administrator\AppData\Local\Android\Sdk\platforms\android-29\android.jar
android.jar的路径越新的sdk版本越好

9
config/publish.txt Normal file
View File

@ -0,0 +1,9 @@
@method local
发布的方式,支持本地文件发布("local")与通过SFTP发布("sftp")。
如果使用本地发布,则需要以下字段
destPath 发布目录
如果使用SFTP发布则需要以下字段
remoteRoot 远程主机的发布目录
sshConfig JSON形式的SSH连接选项参见ssh2.Client.connect。

29
config/shell.txt Normal file
View File

@ -0,0 +1,29 @@
@shellPath ..\cadroid
cadroid项目的路径
@jarsignerPath C:\Program Files\Java\jdk1.8.0_221\bin\jarsigner.exe
JDK中jarsigner.exe的路径没有安装JDK则可使用(Android Studio安装目录)\jre\bin\jarsigner.exe
@zipalignPath C:\Users\Administrator\AppData\Local\Android\Sdk\build-tools\29.0.1\zipalign.exe
Build Tools中zipalign.exe的路径
@dexPath .\app\build\intermediates\dex\release\mergeDexRelease\out\classes.dex
Gradle Build时生成的classes.dex文件路径可以为相对于shellPath的相对路径
@releaseSignPath .\app\signatures\release.signature
正式版安装包签名公钥文件路径可以为相对于shellPath的相对路径
@debugSignPath .\app\signatures\debug.signature
调试用安装包签名公钥文件路径可以为相对于shellPath的相对路径
@hotfixPrivateKey .\app\signatures\privateKey.pem
热更新签名用私钥文件路径可以为相对于shellPath的相对路径
@keystorePath .\app\signatures\release.keystore
签名文件路径可以为相对于shellPath的相对路径
@keyName appkey
密钥名
@keyPasswordPath .\app\signatures\release.password
密钥密码文件路径可以为相对于shellPath的相对路径

12
config/update.txt Normal file
View File

@ -0,0 +1,12 @@
@downloadSource
{
"酷安网(最推荐)": "https://www.coolapk.com/game/com.xero.ca",
"话唠兔的小站(直链)": "https://projectxero.top/ca/release.apk",
"Gitee": "https://gitee.com/projectxero/ca/releases",
"反馈群加群303697689获得": "https://jq.qq.com/?_wv=1027&k=5OOYWLn"
}
@end downloadSource
可用的下载地址
@remoteRoot https://ca.projectxero.top/
更新源站点目录,以/结尾

View File

@ -1,3 +1,12 @@
/*LOADER
if (variables.buildConfig.variants == "release") {
postprocessor = function(src) {
var jsmin = require("jsmin").jsmin;
return jsmin(src, 2);
};
}
*/
Intl.defaultLang = Loader.fromFile("./zh_CN/main.json");
switch (Intl.lookupLang({
"zh_CN" : {
language : "zh",
@ -9,12 +18,10 @@ switch (Intl.lookupLang({
}
})) {
case "en_US":
"IGNORELN_START";
Intl.loadLang({
language : "en",
country : "US"
}, Loader.fromFile("./en_US/main.json"), false);
"IGNORELN_END";
break;
default:
Intl.loadLang({

16
main.js
View File

@ -590,6 +590,22 @@ MapScript.loadModule("Loader", {
});
Loader.load(function() {
/*LOADER
if (variables.buildConfig.variants == "release") {
postprocessor = function(src) {
var jsmin = require("jsmin").jsmin;
return jsmin(src, 1)
.replace(/\{DATE\}/g, variables.buildConfig.date)
.replace(/^\s+/, "") //去除开头多余的空行
.replace(/^"ui";\n/, "").replace(/CA\.RELEASE/g, "true"); //去除UI标志标记正式版
};
} else if (variables.buildConfig.variants == "snapshot") {
postprocessor = function(src) {
return src.replace(/\{DATE\}/g, "S" + variables.buildConfig.date);
};
}
*/
Loader.fromFile("modules/BuildConfig.js")
Loader.fromFile("modules/test/FileLogger.js")

View File

@ -1,11 +1,12 @@
/*LOADER
source = "var BuildConfig=" + JSON.stringify(variables.buildConfig);
*/
var BuildConfig = (function() {
var readConfig = Loader.require("./tools/readConfig.js");
var config = readConfig(Loader.readFile("./buildinfo.txt"));
config.variants = "debug";
config.publishTime = Date.now();
config.licenceUpdate = "1970/1/1";
return config;
})();
var BuildConfig = {
variants: "debug",
version: "Unknown",
versionCode: [9],
date: "2099-01-01",
publishTime: Date.now(),
licenceUpdate: "1970/1/1",
description: ""
};

View File

@ -1,7 +1,4 @@
MapScript.loadModule("Intl", {
/*"IGNORELN_START";*/
defaultLang : Loader.fromFile("../intl/zh_CN/main.json"),
/*"IGNORELN_END";*/
rescache : {},
getLocales : function() {
var r, i, a;

View File

@ -1,4 +1,11 @@
"IGNORELN_START";
/*LOADER
if (variables.buildConfig.variants == "release") {
postprocessor = function(src) {
var jsmin = require("jsmin").jsmin;
return jsmin(src, 2);
};
}
*/
CA.Library.inner["default"] = Loader.fromFile("builtinLibrarys/default.json");
CA.Library.inner["addition"] = Loader.fromFile("builtinLibrarys/addition.json");
CA.Library.inner["basicedu"] = Loader.fromFile("builtinLibrarys/basicedu.json");
@ -75,5 +82,4 @@ CA.tips = CA.defalutTips = [
//by ProjectXero
"潜影贝只是站错了阵营的好孩子~"
];
"IGNORELN_END";
];

View File

@ -111,6 +111,12 @@ MapScript.loadModule("WSServer", {
erp(e, true, message);
}
},
/**
* @callback EventReceiver
* 事件回调
* @param {Object} body 事件body
* @param {Object} message 事件消息
*/
onEvent : function(json) {
var listeners = this.events.get(json.body.eventName), iter, e;
if (listeners != null) {
@ -123,6 +129,12 @@ MapScript.loadModule("WSServer", {
}
}
},
/**
* @callback CommandResponseReceiver
* 命令响应回调
* @param {Object} body 命令响应body
* @param {Object} message 命令响应消息
*/
onResponse : function(json) {
var callback = this.responsers.remove(json.header.requestId);
if (callback != null) {
@ -164,6 +176,12 @@ MapScript.loadModule("WSServer", {
messageType : "commandRequest"
};
},
/**
* 订阅一个事件
* @param {string} name 事件名
* @param {EventReceiver} callback 事件回调
* @returns {boolean} 服务器是否在线
*/
subscribeEvent : function(name, callback) {
var listeners;
if (!this.conn || !this.conn.isOpen()) return false;
@ -181,6 +199,12 @@ MapScript.loadModule("WSServer", {
}));
return true;
},
/**
* 取消订阅一个事件
* @param {string} name 事件名
* @param {EventReceiver} callback 事件回调
* @returns {boolean} 服务器是否在线
*/
unsubscribeEvent : function(name, callback) {
if (!this.conn || !this.conn.isOpen()) return false;
var listeners = this.events.get(name);
@ -198,6 +222,12 @@ MapScript.loadModule("WSServer", {
}
return true;
},
/**
* 发送一条命令
* @param {string} cmd 命令不包括斜杠
* @param {CommandResponseReceiver} callback 命令响应回调
* @returns {boolean} 服务器是否在线
*/
sendCommand : function(cmd, callback) {
if (!this.conn || !this.conn.isOpen()) return null;
var json = {

View File

@ -1,4 +1,11 @@
"IGNORELN_START";
/*LOADER
if (variables.buildConfig.variants == "release") {
postprocessor = function(src) {
var jsmin = require("jsmin").jsmin;
return jsmin(src, 2);
};
}
*/
MapScript.loadModule("G", {
onCreate : function() {
var t;
@ -138,5 +145,4 @@ MapScript.loadModule("G", {
WebView: android.webkit.WebView,
WindowManager: android.view.WindowManager
//IMPORTS_END
});
"IGNORELN_END";
});

View File

@ -1,146 +0,0 @@
var fs = require("fs");
var process = require("process");
var crypto = require("crypto");
var js2lib = require("./js2lib");
var js2signlib = require("./js2signlib");
function main(path) {
console.log("Reading config...");
var i, s, libs = JSON.parse(fs.readFileSync(path, "utf-8")), libslock;
process.chdir(path + "/../");
try {
libslock = JSON.parse(fs.readFileSync(libs.lockFile, "utf-8"));
} catch(e) {}
if (!libslock) libslock = {
clib : {}
};
var index = [], map = {};
for (i in libs.public) {
if (libs.public[i].src) {
console.log("Compiling " + libs.public[i].name);
s = digestSHA1(fs.readFileSync(libs.public[i].src));
if (libslock.clib[libs.public[i].uuid] != s) {
if (libs.signKey) {
js2signlib(libs.public[i].src, libs.signKey, libs.sourceDir + libs.public[i].id + ".lib");
} else {
js2lib(libs.public[i].src, libs.sourceDir + libs.public[i].id + ".lib");
}
libslock.clib[libs.public[i].uuid] = s;
}
}
console.log("Indexing " + libs.public[i].name);
index.push(toIndex(libs.public[i], libs));
fs.writeFileSync(libs.sourceDir + libs.public[i].id + ".json", JSON.stringify(toUpdate(libs.public[i], libs)));
map[libs.public[i].uuid] = libs.sourceUrl + libs.public[i].id + ".json"
}
for (i in libs.private) {
if (libs.private[i].src) {
console.log("Compiling " + libs.private[i].name);
s = digestSHA1(fs.readFileSync(libs.private[i].src));
if (libslock.clib[libs.private[i].uuid] != s) {
if (libs.signKey) {
js2signlib(libs.private[i].src, libs.signKey, libs.sourceDir + libs.private[i].id + ".lib");
} else {
js2lib(libs.private[i].src, libs.sourceDir + libs.private[i].id + ".lib");
}
libslock.clib[libs.private[i].uuid] = s;
}
}
console.log("Indexing " + libs.private[i].name);
fs.writeFileSync(libs.sourceDir + libs.private[i].id + ".json", JSON.stringify(toUpdate(libs.private[i], libs)));
map[libs.private[i].uuid] = libs.sourceUrl + libs.private[i].id + ".json";
}
for (i in libs.store) {
console.log("Indexing " + libs.store[i].name);
index.push(toIndex(libs.store[i], libs));
map[libs.store[i].uuid] = libs.store[i].updateurl;
}
console.log("Wrinting Index...");
for (i = 0, s = 0; i < index.length; i += libs.pageLimit, s++) {
fs.writeFileSync(libs.sourceDir + "index" + (s > 0 ? "-" + s : "") + ".json", JSON.stringify({
sourceId : libs.sourceId,
pageNo : s,
nextPage : (i + libs.pageLimit) < index.length ? libs.sourceUrl + "index-" + (s + 1) + ".json" : undefined,
content : index.slice(i, i + libs.pageLimit)
}));
}
console.log("Wrinting Map...");
fs.writeFileSync(libs.sourceDir + "map.json", JSON.stringify({
sourceId : libs.sourceId,
content : map
}));
console.log("Wrinting Authorities...");
if (!libs.authorities) libs.authorities = {};
for (i in libs.authorities) {
if (!libs.authorities[i].startsWith("http")) {
fs.copyFileSync(libs.authorities[i], libs.sourceDir + i + ".key");
libs.authorities[i] = libs.sourceUrl + i + ".key";
}
}
libs.authorities[libs.sourceId] = libs.verifyKey ? libs.sourceUrl + "verify.key" : undefined;
fs.writeFileSync(libs.sourceDir + "authorities.json", JSON.stringify({
sourceId : libs.sourceId,
content : libs.authorities
}));
console.log("Wrinting Info...");
if (libs.verifyKey) {
var data = fs.readFileSync(libs.verifyKey, "utf-8").split(/\r?\n/);
fs.writeFileSync(libs.sourceDir + "verify.key", Buffer.from(data.slice(1, -2).join(""), "base64"));
}
fs.writeFileSync(libs.sourceDir + "info.json", JSON.stringify({
sourceId : libs.sourceId,
map : libs.sourceUrl + "map.json",
index : libs.sourceUrl + "index.json",
indexPages : s,
indexLibs : index.length,
pubkey : libs.verifyKey ? libs.sourceUrl + "verify.key" : undefined,
authorities : libs.sourceUrl + "authorities.json",
lastUpdate : Date.now(),
maintainer : libs.maintainer || libs.sourceUrl,
details : libs.details
}));
fs.writeFileSync(libs.lockFile, JSON.stringify(libslock));
}
/*
如何生成所需的signKey(私钥)和verifyKey(公钥)
1) 打开openssl
2) genrsa -out 输出私钥文件.pem 密钥位数(e.g. 2048)
3) rsa -in 输出私钥文件.pem -out 输出公钥文件.pub -pubout
*/
function toIndex(o, libs) {
var r = {
"name": o.name,
"author": o.author,
"description": o.description,
"uuid": o.uuid,
"version": o.version,
"requirement": o.requirement,
"downloadurl" : o.downloadurl || libs.sourceUrl + o.id + ".lib",
"updateurl" : o.updateurl || libs.sourceUrl + o.id + ".json"
};
r.sha1 = o.downloadurl ? o.sha1 : digestSHA1(fs.readFileSync(libs.sourceDir + o.id + ".lib"));
return r;
}
function toUpdate(o, libs) {
var r = {
"uuid": o.uuid,
"version": o.version,
"url" : libs.sourceUrl + o.id + ".lib",
"message" : o.updateMessage,
"source" : libs.sourceUrl
};
r.sha1 = digestSHA1(fs.readFileSync(libs.sourceDir + o.id + ".lib"));
return r;
}
function digestSHA1(data) {
var digest = crypto.createHash("sha1");
digest.update(data);
return digest.digest("base64");
}
if (require.main == module) main(process.argv[2]);
module.exports = main;

View File

@ -1,18 +0,0 @@
@url https://projectxero.top/ca
更新源URL
@autopublish sftp
自动发布的方式,可以为以下值之一:
sftp - 通过sftp发布
(其他值或不提供) - 不使用自动发布
@remotepath /home/www/htdocs/ca
更新源远程文件夹的路径
@sshconfig ssh.txt
指定sshconfig设置参见ssh2.Client.connect的参数格式
例如:
@host 192.168.0.100
@port 22
@username admin
@password 123456

View File

@ -1,59 +0,0 @@
'use strict';
// Note: we can't get significant speed boost here.
// So write code to minimize size - no pregenerated tables
// and array tools dependencies.
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
// Use ordinary array, since untyped makes no boost here
function makeTable() {
var c, table = [];
for (var n = 0; n < 256; n++) {
c = n;
for (var k = 0; k < 8; k++) {
c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
}
table[n] = c;
}
return table;
}
// Create table on load. Just 255 signed longs. Not a problem.
var crcTable = makeTable();
function crc32(crc, buf, len, pos) {
var t = crcTable,
end = pos + len;
crc ^= -1;
for (var i = pos; i < end; i++) {
crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
}
return (crc ^ (-1)) >>> 0;
}
module.exports = crc32;

View File

@ -1,21 +0,0 @@
var fs = require("fs");
var process = require("process");
var zlib = require("zlib");
function main(src, dest) {
var s, o;
var dh = Buffer.alloc(15), date = Date.now();
s = src instanceof Buffer ? src : fs.readFileSync(src);
dh.write("LIBRARY");
dh.writeInt32BE(Math.floor(date / 0xffffffff), 7);
dh.writeInt32BE(date & 0xffffffff, 11);
s = zlib.gzipSync(s);
o = Buffer.alloc(dh.length + s.length);
dh.copy(o, 0);
s.copy(o, dh.length);
if (dest) fs.writeFileSync(dest, o);
return o;
}
if (require.main == module) main(process.argv[2], process.argv[3]);
module.exports = main;

View File

@ -1,23 +0,0 @@
var fs = require("fs");
var process = require("process");
var zlib = require("zlib");
var crypto = require("crypto");
var js2lib = require("./js2lib");
function main(src, prvkey, dest) {
var s = js2lib(src), prv = fs.readFileSync(prvkey), o;
var dh1 = Buffer.alloc(9);
var sign = crypto.createSign("RSA-SHA256");
sign.update(s.slice(7));
var dh2 = sign.sign(prv.toString());
dh1.write("SIGNLIB01");
o = Buffer.alloc(dh1.length + dh2.length + s.length - 7);
dh1.copy(o, 0);
dh2.copy(o, dh1.length);
s.copy(o, dh1.length + dh2.length, 7);
if (dest) fs.writeFileSync(dest, o);
return o;
}
if (require.main == module) main(process.argv[2], process.argv[3], process.argv[4]);
module.exports = main;

View File

@ -1,59 +0,0 @@
const fs = require("fs");
var charset = "utf-8";
function getParentDir(path) {
var sp;
path = path.replace(/\\/g, "/");
sp = path.lastIndexOf("/")
return sp < 0 ? null : path.slice(0, sp);
}
function addFrontSpace(arr, frontSpace) {
var i;
for (i = 1; i < arr.length; i++) {
arr[i] = frontSpace + arr[i];
}
}
function preprocess(code, source, parentDir, path, charset, variables, setAfterFill, addFlags, removeFlags) {
var TestOnly = () => addFlags("test");
eval(code);
return source;
}
var sourceCache = {};
function load(path, variables) {
path = fs.realpathSync(path);
if (path in sourceCache) return sourceCache[path];
var r = fs.readFileSync(path, charset), i, afterFill, flags = {};
var parent = getParentDir(path);
var processer = (/\/\*LOADER\s([\s\S]+?)\*\//).exec(r);
if (processer) {
r = preprocess(processer[1], r, parent, path, charset, variables, function setAfterFill(f) {
afterFill = f;
}, function addFlags() {
for (i = 0; i < arguments.length; i++) flags[arguments[i]] = true;
}, function removeFlags() {
for (i = 0; i < arguments.length; i++) flags[arguments[i]] = false;
}).replace(/\/\*LOADER\s([\s\S]+?)\*\//, "");
if (flags.test) return "";
}
r = r.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
for (i = 0; i < r.length; i++) {
r[i] = r[i].replace(/Loader.fromFile\("(.+)"\)/g, function(match, mpath) {
var frontSpace = r[i].match(/^\s*/);
var res = load(parent ? parent + "/" + mpath : mpath, variables).split("\n");
if (frontSpace) {
addFrontSpace(res, frontSpace[0]);
}
return res.join("\n");
});
}
r = r.join("\n");
if (afterFill) {
r = afterFill(r);
}
return sourceCache[path] = r;
}
module.exports = {
load : function(path, cs, variables) {
charset = cs || "utf-8";
return load(path, variables);
}
}

View File

@ -1,87 +0,0 @@
const process = require("process");
const fs = require("fs");
var Tasks = require("./tasks");
var Build = {
execute : function(task, args) {
console.log("Process " + task);
return executeTask(task, args)
.then(result => {
console.log("Success " + task);
return result;
}, reason => {
console.log("Failed " + task + " : " + reason);
throw reason;
});
},
task : function(task, args) {
return () => this.execute(task, args);
},
pipe : function(task, args) {
return result => this.execute(task, [result, args]);
},
loadTasks : function(path) {
initTasks(path);
},
Result : {
OK : "ok"
}
}
var context = Build.context = Object.create(Build);
function getFileName(nameWithExt) {
var p = nameWithExt.lastIndexOf(".");
return p >= 0 ? nameWithExt.slice(0, p) : nameWithExt;
}
function procArgs() {
var i, args = process.argv, task, taskArgs = [], time = Date.now();
task = args[2] || "help";
for (i = 3; i < args.length; i++) {
taskArgs.push(args[i]);
}
console.log("Process " + task);
try {
if (!(task in Tasks)) throw new Error("Task not found: " + task);
if (Tasks[task].input != "cli") throw new Error("Task is not available in CLI: " + task);
executeTask(task, taskArgs)
.then(result => {
console.log("Success " + task + " in " + ((Date.now() - time) / 1000).toFixed(2) + "s");
return result;
}, reason => {
console.log("Failed " + task);
console.log(reason);
process.exit(1);
});
} catch(e) {
console.log(String(e));
}
}
function initTasks(path) {
var e, fn, files = fs.readdirSync(path);
for (e of files) {
if (!fs.statSync("./tasks/" + e).isDirectory()) {
fn = getFileName(e);
if (fn.length != 0) {
try {
Tasks[fn] = require("./tasks/" + e);
} catch(e) {
console.log("Cannot load task: " + fn + "\n" + e);
}
}
}
}
}
function executeTask(task, args) {
if (!(task in Tasks)) throw new Error("Task not found: " + task);
var result;
try {
result = Tasks[task](context, args);
} catch(e) {
return Promise.reject(e);
}
return result instanceof Promise ? result : Promise.resolve(result);
}
initTasks("./tasks");
if (require.main == module) {
procArgs();
} else {
module.exports = Build;
}

143
tools/package-lock.json generated
View File

@ -1,143 +0,0 @@
{
"name": "ca_build_tools",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"requires": {
"safer-buffer": "~2.1.0"
}
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"requires": {
"tweetnacl": "^0.14.3"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"jszip": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.2.1.tgz",
"integrity": "sha512-iCMBbo4eE5rb1VCpm5qXOAaUiRKRUKiItn8ah2YQQx9qymmSAY98eyQfioChEYcVQLh0zxJ3wS4A0mh90AVPvw==",
"requires": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"set-immediate-shim": "~1.0.1"
}
},
"lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"requires": {
"immediate": "~3.0.5"
}
},
"pako": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz",
"integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw=="
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"set-immediate-shim": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
},
"ssh2": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/ssh2/-/ssh2-0.8.2.tgz",
"integrity": "sha512-oaXu7faddvPFGavnLBkk0RFwLXvIzCPq6KqAC3ExlnFPAVIE1uo7pWHe9xmhNHXm+nIe7yg9qsssOm+ip2jijw==",
"requires": {
"ssh2-streams": "~0.4.2"
}
},
"ssh2-streams": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/ssh2-streams/-/ssh2-streams-0.4.2.tgz",
"integrity": "sha512-2rSj3oTIJnbAIzR3+XwIYef9wCOVrPQZNLL+fFPPjnPxf09tKkAbgrlYgh/1qynBTz65AUOS+s1zuko4M/GKCw==",
"requires": {
"asn1": "~0.2.0",
"bcrypt-pbkdf": "^1.0.2",
"streamsearch": "~0.1.2"
}
},
"streamsearch": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
}
}
}

View File

@ -1,15 +0,0 @@
{
"name": "ca_build_tools",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "ProjectXero",
"license": "GPL-3.0",
"dependencies": {
"jszip": "^3.2.1",
"ssh2": "^0.8.2"
}
}

View File

@ -1,30 +0,0 @@
function parseNative(data) {
var result;
try {
return JSON.parse(data);
} catch(e) {
return data;
}
}
function readConfig(content) {
var i, a = content.split("\n"), result = {};
var lastData = [], spacePos, multiline = "";
for (i = 0; i < a.length; i++) {
if (a[i].startsWith("@")) {
if (multiline && a[i] == "@end " + multiline) {
result[multiline] = parseNative(lastData.join("\n"));
} else {
spacePos = a[i].indexOf(" ");
if (spacePos >= 0) {
result[a[i].slice(1, spacePos)] = parseNative(a[i].slice(spacePos + 1));
} else {
multiline = a[i].slice(1);
}
}
} else if (multiline) {
lastData.push(a[i]);
}
}
return result;
}
module.exports = readConfig;

View File

@ -1,11 +0,0 @@
const fs = require("fs");
const zlib = require("zlib");
module.exports = function(source, signPath, targetPath) {
var srcbuf = zlib.gzipSync(Buffer.from(source));
var sgnbuf = fs.readFileSync(signPath);
var i, srcsize = srcbuf.length, sgnsize = sgnbuf.length;
for (i = 0; i < srcsize; i++) {
srcbuf[i] ^= sgnbuf[i % sgnsize];
}
return srcbuf;
}

View File

@ -1,44 +0,0 @@
var Tasks = {};
Tasks.help = function(context, args) {
if (args[0]) {
var task;
if (!(args[0] in Tasks)) throw new Error("Task not found: " + args[0]);
console.log("Task : " + args[0]);
task = Tasks[args[0]];
if (typeof task.help == "function") {
task.help(args);
} else {
console.log(task.help || "(Nothing)");
}
} else {
console.log("CA Build Tools 1.0.0");
console.log("\nTo run a build, run build <task> ...");
console.log("\nTo see a list of available tasks, run build tasks");
console.log("\nTo see more detail of a task, run build help <task>");
}
}
Tasks.help.input = "cli";
Tasks.help.help = function() {
console.log("build help - Show help message of tool");
console.log("build help <task> - Show help message of a task");
}
Tasks.tasks = function(context, args) {
var i, showAll = args[0] == "all", result = [];
for (i in Tasks) {
if (showAll || Tasks[i].input == "cli") {
result.push(i);
}
}
console.log("All Tasks:");
console.log(" " + result.join("\n "));
console.log(result.length + " task(s).");
}
Tasks.tasks.input = "cli";
Tasks.tasks.help = function() {
console.log("build tasks - Show all available tasks");
console.log("build tasks all - Show all tasks");
}
module.exports = Tasks;

View File

@ -1,14 +0,0 @@
module.exports = function(context, args) {
context.cwd = args[0];
return context.execute("initDirectory")
.then(context.task("initUpdateConfig"))
.then(context.task("getBuildConfig", "release"))
.then(context.task("getSourceCode"))
.then(context.pipe("minifyJS"))
.then(context.pipe("preprocessRelease"))
.then(context.pipe("writeMinify"))
.then(context.pipe("compressRelease"))
.then(context.pipe("writeRelease"))
.then(context.task("writeUpdate"));
}
module.exports.input = "cli";

View File

@ -1,13 +0,0 @@
module.exports = function(context, args) {
context.cwd = args[0];
return context.execute("initDirectory")
.then(context.task("initUpdateConfig"))
.then(context.task("getBuildConfig", "snapshot"))
.then(context.task("getSourceCode"))
.then(context.pipe("preprocessSnapshot"))
.then(context.pipe("writeSnapshot"))
.then(context.pipe("writeSnapshotLib"))
.then(context.task("writeSnapshotUpdate"))
.then(context.task("writeUpdate"));
}
module.exports.input = "cli";

View File

@ -1,20 +0,0 @@
const fs = require("fs");
function rmdir(path) {
if (!fs.existsSync(path)) return;
var e, fn, files = fs.readdirSync(path);
for (e of files) {
if (fs.statSync(path + "/" + e).isDirectory()) {
rmdir(path + "/" + e);
} else {
fs.unlinkSync(path + "/" + e);
}
}
fs.rmdirSync(path);
}
module.exports = function(context, args) {
context.cwd = args[0];
rmdir(context.cwd + "/build");
rmdir(context.cwd + "/dist");
return 1;
}
module.exports.input = "cli";

View File

@ -1,7 +0,0 @@
const zlib = require("zlib");
module.exports = function(context, args) {
var b = Buffer.from(args[0]);
b = zlib.gzipSync(b); //GZIP压缩
var r = '"ui";\nvar a=new java.io.BufferedReader(new java.io.InputStreamReader(new java.util.zip.GZIPInputStream(new java.io.ByteArrayInputStream(android.util.Base64.decode("' + b.toString("base64") + '",2))))),b=[],c;while(c=a.readLine())b.push(c);a.close();eval(b.join("\\n"));';
return r;
}

View File

@ -1,13 +0,0 @@
module.exports = function(context, args) {
return new Promise(function(resolve, reject) {
var ms = parseInt(Array.isArray(args) ? args[0] : args);
if (ms > 0) {
setTimeout(function() {
resolve();
}, ms);
} else {
reject(new Error("delay should not be " + ms));
}
});
}
module.exports.input = "cli";

View File

@ -1,5 +0,0 @@
const clibspawn = require("../clibspawn");
module.exports = function(context, args) {
return clibspawn(args[0]);
}
module.exports.input = "cli";

View File

@ -1,3 +0,0 @@
module.exports = function(context, args) {
return args[0].close(context);
}

View File

@ -1,38 +0,0 @@
const fs = require("fs");
const readConfig = require("../readconfig");
module.exports = function(context, args) {
context.cwd = args[0];
var importConfig = readConfig(fs.readFileSync(context.cwd + "/tools/config/import.txt", "utf-8")), jarClasses = [];
return context.execute("initDirectory")
.then(context.task("initUpdateConfig"))
.then(context.task("getBuildConfig", "snapshot"))
.then(context.task("readJarClasses", [jarClasses, {
path : importConfig.androidJarPath
}]))
.then(context.task("getSourceCode"))
.then(context.pipe("processImportScope", {
target : context.cwd + "/modules/uiCore/G.js",
scopeName : "G",
classes : jarClasses,
packages : [
"android",
"android.widget",
"android.view",
"android.view.animation",
"android.view.inputmethod",
"android.animation",
"android.app",
"android.content",
"android.graphics",
"android.graphics.drawable",
"android.media",
"android.os",
"android.text",
"android.text.format",
"android.text.method",
"android.text.style",
"android.webkit"
]
}));
}
module.exports.input = "cli";

View File

@ -1,8 +0,0 @@
const fs = require("fs");
const readConfig = require("../readconfig");
module.exports = function(context, args) {
context.buildConfig = readConfig(fs.readFileSync(context.cwd + "/buildinfo.txt", "utf-8"));
context.buildConfig.variants = args;
context.buildConfig.publishTime = Date.now();
}

View File

@ -1,7 +0,0 @@
const fs = require("fs");
const loader = require("../loader");
module.exports = function(context, args) {
var result = loader.load(context.cwd + "/main.js", null, { buildConfig : context.buildConfig });
fs.writeFileSync(context.cwd + "/build/export.js", result);
return result;
}

View File

@ -1,15 +0,0 @@
const fs = require("fs");
function ensureDir(dir) {
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
}
module.exports = function(context, args) {
ensureDir(context.cwd + "/build");
ensureDir(context.cwd + "/dist");
ensureDir(context.cwd + "/dist/release"); //js
ensureDir(context.cwd + "/dist/snapshot"); //snapshot lib
ensureDir(context.cwd + "/dist/update"); //update json
ensureDir(context.cwd + "/dist/hotfix"); //hotfix lib
ensureDir(context.cwd + "/dist/releaseApk"); //apk
ensureDir(context.cwd + "/dist/hotfixApk"); //apk hotfix
return 1;
}

View File

@ -1,7 +0,0 @@
const fs = require("fs");
const readConfig = require("../readconfig");
module.exports = function(context, args) {
context.shellConfig = readConfig(fs.readFileSync("./config/shell.txt", "utf-8"));
context.shellConfig.dexPath = "/app/build/intermediates/dex/release/mergeDexRelease/out/classes.dex";
}

View File

@ -1,23 +0,0 @@
const fs = require("fs");
const readConfig = require("../readconfig");
module.exports = function(context, args) {
var info = readConfig(fs.readFileSync("./config/info.txt", "utf-8"));
context.updateConfig = {
pageUrl : info.url + "/",
downloadSource : {
"酷安网(最推荐)": "https://www.coolapk.com/game/com.xero.ca",
"话唠兔的小站(直链)": "https://projectxero.top/ca/release.apk",
"Gitee": "https://gitee.com/projectxero/ca/releases",
"百度网盘(备用)": "http://pan.baidu.com/share/link?shareid=2966673396&uk=404195919",
"反馈群加群303697689获得": "https://jq.qq.com/?_wv=1027&k=5OOYWLn"
}
};
if (info.autopublish == "sftp") {
context.publishConfig = {
method : "sftp",
remotePath : info.remotepath,
sshConfig : readConfig(fs.readFileSync("./config/" + info.sshconfig, "utf-8")),
};
}
}

View File

@ -1,213 +0,0 @@
module.exports = function(context, args) {
return jsmin("", args[0], 1);
}
String.prototype.has = function(c) {
return this.indexOf(c) > -1;
};
function jsmin(comment, input, level) {
if (input === undefined) {
input = comment;
comment = '';
level = 2;
} else if (level === undefined || level < 1 || level > 3) {
level = 2;
}
if (comment.length > 0) {
comment += '\n';
}
var a = '',
b = '',
EOF = -1,
LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
DIGITS = '0123456789',
ALNUM = LETTERS + DIGITS + '_$\\',
theLookahead = EOF;
function isAlphanum(c) {
return c != EOF && (ALNUM.has(c) || c.charCodeAt(0) > 126);
}
function get() {
var c = theLookahead;
if (get.i == get.l) {
return EOF;
}
theLookahead = EOF;
if (c == EOF) {
c = input.charAt(get.i); ++get.i;
}
if (c >= ' ' || c == '\n') {
return c;
}
if (c == '\r') {
return '\n';
}
return ' ';
}
get.i = 0;
get.l = input.length;
function peek() {
theLookahead = get();
return theLookahead;
}
function next() {
var c = get();
if (c == '/') {
switch (peek()) {
case '/':
for (;;) {
c = get();
if (c <= '\n') {
return c;
}
}
break;
case '*':
get();
for (;;) {
switch (get()) {
case '*':
if (peek() == '/') {
get();
return ' ';
}
break;
case EOF:
throw 'Error: Unterminated comment.';
}
}
break;
default:
return c;
}
}
return c;
}
function action(d) {
var r = [];
if (d == 1) {
r.push(a);
}
if (d < 3) {
a = b;
if (a == '\'' || a == '"') {
for (;;) {
r.push(a);
a = get();
if (a == b) {
break;
}
if (a <= '\n') {
throw 'Error: unterminated string literal: ' + a;
}
if (a == '\\') {
r.push(a);
a = get();
}
}
}
}
b = next();
if (b == '/' && '(,=:[!&|'.has(a)) {
r.push(a);
r.push(b);
for (;;) {
a = get();
if (a == '/') {
break;
} else if (a == '\\') {
r.push(a);
a = get();
} else if (a <= '\n') {
throw 'Error: unterminated Regular Expression literal';
}
r.push(a);
}
b = next();
}
return r.join('');
}
function m() {
var r = [];
a = '\n';
r.push(action(3));
while (a != EOF) {
switch (a) {
case ' ':
if (isAlphanum(b)) {
r.push(action(1));
} else {
r.push(action(2));
}
break;
case '\n':
switch (b) {
case '{':
case '[':
case '(':
case '+':
case '-':
r.push(action(1));
break;
case ' ':
r.push(action(3));
break;
default:
if (isAlphanum(b)) {
r.push(action(1));
} else {
if (level == 1 && b != '\n') {
r.push(action(1));
} else {
r.push(action(2));
}
}
}
break;
default:
switch (b) {
case ' ':
if (isAlphanum(a)) {
r.push(action(1));
break;
}
r.push(action(3));
break;
case '\n':
if (level == 1 && a != '\n') {
r.push(action(1));
} else {
switch (a) {
case '}':
case ']':
case ')':
case '+':
case '-':
case '"':
case '\'':
if (level == 3) {
r.push(action(3));
} else {
r.push(action(1));
}
break;
default:
if (isAlphanum(a)) {
r.push(action(1));
} else {
r.push(action(3));
}
}
}
break;
default:
r.push(action(1));
break;
}
}
}
return r.join('');
}
jsmin.oldSize = input.length;
ret = m(input);
jsmin.newSize = ret.length;
return comment + ret;
}

View File

@ -1,30 +0,0 @@
const ssh2 = require("ssh2");
var sftpInterface = {
upload : function(context, args) {
return context.execute("sftpPut", {
session : this,
localPath : args.localPath,
remotePath : args.remotePath
});
},
close : function(context) {
return context.execute("sftpDisconnect", {
session : this
});
}
}
module.exports = function(context, args) {
var publishCfg = context.publishConfig;
if (!publishCfg) throw new Error("publishConfig not found");
if (publishCfg.method == "sftp") {
return context.execute("sftpConnect", publishCfg.sshConfig)
.then(function(v) {
var o = Object.create(sftpInterface);
o.sftp = v.sftp;
o.connection = v.connection;
return o;
});
} else {
throw new Error("Unknown publish method: " + publishCfg.method);
}
}

View File

@ -1,9 +0,0 @@
module.exports = function(context, args) {
return args[0]
.replace(/\{DATE\}/g, context.buildConfig.date)
.replace(/"IGNORELN_START";([^]*?)"IGNORELN_END";/g, function(match, p) {
return p.replace(/\s*\n\s*/g, "");
}) //去除部分换行符
.replace(/^\s*/, "") //去除开头多余的空行
.replace(/^"ui";\n/, "").replace(/CA\.RELEASE/g, "true"); //去除UI标志标记正式版
}

View File

@ -1,3 +0,0 @@
module.exports = function(context, args) {
return args[0].replace(/\{DATE\}/g, "S" + context.buildConfig.date);
}

View File

@ -1,45 +0,0 @@
const fs = require("fs");
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
}
function searchClasses(src, scopeName) {
var regex = new RegExp("\\W" + escapeRegExp(scopeName) + "\\.(\\w+)", "g");
var r = [], match;
while (match = regex.exec(src)) {
if (r.indexOf(match[1]) < 0) r.push(match[1]);
}
return r;
}
function peekClass(name, classes, packages) {
var i, path;
for (i = 0; i < packages.length; i++) {
path = packages[i] + "." + name;
if (classes.indexOf(path) >= 0) return path;
}
return null;
}
function locateClasses(names, classes, packages) {
var i, r = {};
names.forEach(e => {
r[e] = peekClass(e, classes, packages);
});
return r;
}
module.exports = function(context, args) {
var param = args[1];
var target = fs.readFileSync(param.target, "utf-8");
var names = searchClasses(args[0], param.scopeName);
var classes = locateClasses(names, param.classes, param.packages);
names = names.filter(e => {
if (classes[e] != null) {
return true;
} else {
console.log("Unknown class: " + param.scopeName + "." + e);
return false;
}
});
names.sort();
names = names.map(e => "\t" + e + ": " + classes[e]);
target = target.replace(/\/\/IMPORTS_BEGIN\n([^]*?)\n\/\/IMPORTS_END/, "//IMPORTS_BEGIN\n" + names.join(",\n") + "\n//IMPORTS_END");
fs.writeFileSync(param.target, target);
}

View File

@ -1,8 +0,0 @@
module.exports = function(context, args) {
console.log("Publishing " + args[1].remotePath);
return args[0].upload(context, {
localPath : args[1].localPath,
remotePath : context.publishConfig.remotePath + "/" + args[1].remotePath
})
.then(() => args[0]);
}

View File

@ -1,31 +0,0 @@
module.exports = function(context, args) {
var promise;
if (Array.isArray(args)) {
if (args[1] == "rebuild") {
var buildArgs = args.slice();
buildArgs.splice(1, 1);
promise = context.execute("shellBuildReleaseHotfix", buildArgs);
} else {
context.cwd = args[0];
promise = context.execute("initDirectory")
.then(context.task("initUpdateConfig"));
}
} else {
promise = Promise.resolve();
}
return promise.then(context.task("preparePublish"))
.then(context.pipe("publishFile", {
localPath : context.cwd + "/dist/hotfixApk/release.js",
remotePath : "hotfix/release.js"
}))
.then(context.pipe("publishFile", {
localPath : context.cwd + "/dist/hotfixApk/release.sign",
remotePath : "hotfix/release.sign"
}))
.then(context.pipe("publishFile", {
localPath : context.cwd + "/dist/hotfixApk/release.json",
remotePath : "hotfix.json"
}))
.then(context.pipe("endPublish"));
}
module.exports.input = "cli";

View File

@ -1,21 +0,0 @@
module.exports = function(context, args) {
var promise;
if (Array.isArray(args)) {
if (args[1] == "rebuild") {
promise = context.execute("buildRelease", args);
} else {
context.cwd = args[0];
promise = context.execute("initDirectory")
.then(context.task("initUpdateConfig"));
}
} else {
promise = Promise.resolve();
}
return promise.then(context.task("preparePublish"))
.then(context.pipe("publishFile", {
localPath : context.cwd + "/dist/update/release.json",
remotePath : "update.json"
}))
.then(context.pipe("endPublish"));
}
module.exports.input = "cli";

View File

@ -1,25 +0,0 @@
module.exports = function(context, args) {
var promise;
if (Array.isArray(args)) {
if (args[1] == "rebuild") {
promise = context.execute("buildSnapshot", args);
} else {
context.cwd = args[0];
promise = context.execute("initDirectory")
.then(context.task("initUpdateConfig"));
}
} else {
promise = Promise.resolve();
}
return promise.then(context.task("preparePublish"))
.then(context.pipe("publishFile", {
localPath : context.cwd + "/dist/snapshot/snapshot.json",
remotePath : "snapshot.json"
}))
.then(context.pipe("publishFile", {
localPath : context.cwd + "/dist/snapshot/snapshot.js",
remotePath : "snapshot.js"
}))
.then(context.pipe("endPublish"));
}
module.exports.input = "cli";

View File

@ -1,20 +0,0 @@
const fs = require("fs");
const jszip = require("jszip");
function getShortName(name) {
var i = name.lastIndexOf(".");
return i >= 0 ? name.slice(i + 1) : name;
}
module.exports = function(context, args) {
var r = args[0], param = args[1];
return jszip.loadAsync(fs.readFileSync(param.path)).then(zf => {
zf.forEach((path, entry) => {
var name;
if (path.endsWith(".class") || path.endsWith(".java")) {
name = path.replace(/\.\w+$/, "").replace(/\//g, ".").replace(/\$/g, ".");
if (/^\d/.test(getShortName(name))) return;
if (r.indexOf(name) < 0) r.push(name);
}
});
return r;
});
}

View File

@ -1,16 +0,0 @@
const ssh2 = require("ssh2");
module.exports = function(context, args) {
return new Promise(function(resolve, reject) {
var conn = new ssh2.Client();
conn.on("ready", function() {
conn.sftp(function(err, sftp) {
if (err) {
reject(err);
return;
}
resolve({ sftp : sftp, connection : conn });
});
});
conn.connect(args);
});
}

View File

@ -1,4 +0,0 @@
module.exports = function(context, args) {
var connection = args.session.connection;
connection.end();
}

View File

@ -1,13 +0,0 @@
const ssh2 = require("ssh2");
module.exports = function(context, args) {
return new Promise(function(resolve, reject) {
var sftp = args.session.sftp;
sftp.fastPut(args.localPath, args.remotePath, function(err) {
if (err) {
reject(err);
return;
}
resolve();
});
});
}

View File

@ -1,10 +0,0 @@
const fs = require("fs");
const crc32 = require("../crc32");
function crc32wrap(buffer) {
return crc32(0, buffer, buffer.length, 0);
}
module.exports = function(context, args) {
var crc = crc32wrap(fs.readFileSync(context.shellcwd + context.shellConfig.dexPath)).toString(16);
context.dexCrc = crc;
return args[0].replace(/\$dexCrc\$/g, crc);
}

View File

@ -1,12 +0,0 @@
const child_process = require("child_process");
module.exports = function(context, args) {
var child = child_process.spawnSync(context.shellConfig.zipalignPath, [
"-f", "4",
context.shellcwd + "/app/build/outputs/apk/release/app-release-unaligned.apk",
context.shellcwd + "/app/build/outputs/apk/release/app-release.apk"
], {
cwd : context.shellcwd,
stdio : "pipe"
});
if (child.error) throw child.error;
}

View File

@ -1,33 +0,0 @@
module.exports = function(context, args) {
context.cwd = args[0];
context.shellcwd = args[1];
context.shellsign = args[2];
return context.execute("initDirectory")
.then(context.task("initShellConfig"))
.then(context.task("initUpdateConfig"))
.then(context.task("getBuildConfig", "release"))
.then(context.task("shellUpdateGradle"))
.then(context.task("shellGradle", ":app:buildRelease"))
.then(context.task("getSourceCode"))
.then(context.pipe("minifyJS"))
.then(context.pipe("preprocessRelease"))
.then(context.pipe("writeMinify"))
.then(function self(script) {
return context.execute("shellAddDexVerify", [script])
.then(context.pipe("shellEncryptScript"))
.then(context.pipe("shellWriteScript"))
.then(context.task("shellPrepareHotfix", [script]))
.then(context.pipe("shellEncryptScript"))
.then(context.pipe("shellWriteHotfix"))
.then(context.pipe("shellWriteHotfixSign"))
.then(context.pipe("shellWriteHotfixLib"))
.then(context.task("shellGradle", ":app:assembleRelease"))
.then(context.pipe("shellCheckDexUnchanged"))
.then(unchanged => unchanged ? null : self(script));
})
.then(context.task("shellSignApk"))
.then(context.task("shellAlignApk"))
.then(context.task("shellExportApk"))
.then(context.task("shellWriteUpdate"));
}
module.exports.input = "cli";

View File

@ -1,21 +0,0 @@
module.exports = function(context, args) {
context.cwd = args[0];
context.shellcwd = args[1];
context.shellsign = args[2];
return context.execute("initDirectory")
.then(context.task("initShellConfig"))
.then(context.task("initUpdateConfig"))
.then(context.task("getBuildConfig", "release"))
.then(context.task("shellUpdateGradle"))
.then(context.task("getSourceCode"))
.then(context.pipe("minifyJS"))
.then(context.pipe("preprocessRelease"))
.then(context.pipe("writeMinify"))
.then(context.pipe("shellPrepareHotfix"))
.then(context.pipe("shellEncryptScript"))
.then(context.pipe("shellWriteHotfix"))
.then(context.pipe("shellWriteHotfixSign"))
.then(context.pipe("shellWriteHotfixLib"))
.then(context.task("shellWriteUpdate"));
}
module.exports.input = "cli";

View File

@ -1,9 +0,0 @@
const fs = require("fs");
const crc32 = require("../crc32");
function crc32wrap(buffer) {
return crc32(0, buffer, buffer.length, 0);
}
module.exports = function(context, args) {
var crc = crc32wrap(fs.readFileSync(context.shellcwd + context.shellConfig.dexPath)).toString(16);
return context.dexCrc == crc;
}

View File

@ -1,4 +0,0 @@
const signscript = require("../signscript");
module.exports = function(context, args) {
return signscript(args[0], context.shellsign);
}

View File

@ -1,5 +0,0 @@
const fs = require("fs");
module.exports = function(context, args) {
fs.copyFileSync(context.shellcwd + "/app/build/outputs/apk/release/app-release.apk", context.cwd + "/dist/releaseApk/app-release.apk");
fs.copyFileSync(context.cwd + "/dist/releaseApk/app-release.apk", context.cwd + "/dist/命令助手(" + context.buildConfig.version + ").apk");
}

View File

@ -1,19 +0,0 @@
const process = require("process");
const child_process = require("child_process");
module.exports = function(context, args) {
return new Promise(function(resolve, reject) {
var cmd = "gradlew --console plain --warning-mode all " + args;
console.log("Running " + args);
var child = child_process.exec(cmd, {
cwd : context.shellcwd
}, (error, stdout, stderr) => {
if (error) {
reject(error);
} else {
resolve();
}
});
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
});
}

View File

@ -1,12 +0,0 @@
module.exports = function(context, args) {
context.cwd = args[0];
context.shellcwd = args[1];
context.shellsign = args[2];
return context.execute("initDirectory")
.then(context.task("getBuildConfig", "debug"))
.then(context.task("getSourceCode"))
.then(context.pipe("shellEncryptScript"))
.then(context.pipe("shellWriteScript"))
.then(context.task("shellUpdateGradle"));
}
module.exports.input = "cli";

View File

@ -1,3 +0,0 @@
module.exports = function(context, args) {
return args[0].replace(/AndroidBridge\.HOTFIX/g, "true");
}

View File

@ -1,15 +0,0 @@
const fs = require("fs");
const child_process = require("child_process");
module.exports = function(context, args) {
var child = child_process.spawnSync(context.shellConfig.jarsignerPath, [
"-verbose",
"-keystore", context.shellcwd + "/app/signatures/release.keystore",
"-signedjar", context.shellcwd + "/app/build/outputs/apk/release/app-release-unaligned.apk",
context.shellcwd + "/app/build/outputs/apk/release/app-release-unsigned.apk",
"appkey"
], {
cwd : context.shellcwd,
input : fs.readFileSync(context.shellcwd + "/app/signatures/release.password")
});
if (child.error) throw error;
}

View File

@ -1,12 +0,0 @@
const fs = require("fs");
module.exports = function(context, args) {
var gradle = context.shellcwd + "/app/build.gradle", gradleConfig = context.gradleConfig = {};
var s = fs.readFileSync(gradle, "utf-8");
gradleConfig.versionCode = Math.floor(Date.parse(context.buildConfig.date) / 86400000);
gradleConfig.versionName = context.buildConfig.version;
gradleConfig.minSdkVersion = parseInt((s.match(/minSdkVersion (\d+)/) || [undefined, 1])[1]);
gradleConfig.shellVersion = parseInt((s.match(/buildConfigField "int", "SHELL_VERSION", "(\d+)"/) || [undefined, 0])[1]);
s = s.replace(/versionCode \d+/, "versionCode " + gradleConfig.versionCode);
s = s.replace(/versionName ".*"/, "versionName " + JSON.stringify(gradleConfig.versionName));
fs.writeFileSync(gradle, s);
}

View File

@ -1,5 +0,0 @@
const fs = require("fs");
module.exports = function(context, args) {
fs.writeFileSync(context.cwd + "/dist/hotfixApk/" + context.buildConfig.variants + ".js", args[0]);
return args[0];
}

View File

@ -1,32 +0,0 @@
const fs = require("fs");
const asLibrary = require("../js2lib");
module.exports = function(context, args) {
var bc = context.buildConfig;
var ver = bc.version.split(".").map((e) => parseInt(e));
fs.writeFileSync(context.cwd + "/dist/hotfix/" + context.buildConfig.variants + ".lib", asLibrary(Buffer.from([
'Plugins.inject(function(o){',
'const pub=' + JSON.stringify(bc.date) + ',ver=' + JSON.stringify(ver) + ',shell=' + JSON.stringify(context.gradleConfig.shellVersion) + ',ds=' + JSON.stringify(bc.description) + ';',
'function u(p,b){',
'var o=new java.io.FileOutputStream(p);',
'o.write(android.util.Base64.decode(b,2));',
'o.close();',
'}',
'o.name="命令助手尝鲜包 - "+pub;',
'o.description="命令助手Beta版安装器\\n";',
'o.uuid="64ac6220-cf64-465a-8af8-1c9dd2835cd0";',
'o.author="命令助手制作组";',
'o.version=ver;',
'if (Date.parse(CA.publishDate)>=Date.parse(pub)){',
'CA.Library.removeLibrary(path);',
'return void(o.description+="您正在使用本尝鲜版或更高版本\\n\\n"+ds);',
'}',
'if(MapScript.host!="Android")return void(o.description+="本安装器仅在App版上可用");',
'if(shell!=ScriptActivity.getShellVersion())return void(o.description+="本安装器不适用于您的版本");',
'u(MapScript.baseDir+"core.js",' + JSON.stringify(args[0].toString("base64")) + ');',
'u(MapScript.baseDir+"core.sign",' + JSON.stringify(fs.readFileSync(context.cwd + "/dist/hotfixApk/" + context.buildConfig.variants + ".sign").toString("base64")) + ');',
'Common.showTextDialog(o.description+="重新启动命令助手后即可使用");',
'})'
].join(""))));
fs.copyFileSync(context.cwd + "/dist/hotfix/" + context.buildConfig.variants + ".lib", context.cwd + "/dist/命令助手(" + bc.date + ").lib");
return args[0];
}

View File

@ -1,11 +0,0 @@
const fs = require("fs");
const crypto = require("crypto");
module.exports = function(context, args) {
var signature = crypto.createSign("RSA-SHA256");
signature.update(args[0]);
var signBytes = signature.sign(fs.readFileSync(context.shellcwd + "/app/signatures/privatekey.pem").toString());
var versionBytes = Buffer.alloc(4);
versionBytes.writeInt32LE(context.gradleConfig.versionCode, 0);
fs.writeFileSync(context.cwd + "/dist/hotfixApk/" + context.buildConfig.variants + ".sign", Buffer.concat([versionBytes, signBytes]));
return args[0];
}

View File

@ -1,4 +0,0 @@
const fs = require("fs");
module.exports = function(context, args) {
fs.writeFileSync(context.shellcwd + "/app/src/main/assets/script.js", args[0]);
}

View File

@ -1,28 +0,0 @@
const fs = require("fs");
const crypto = require("crypto");
function digestSHA1(data) {
var digest = crypto.createHash("sha1");
digest.update(data);
return digest.digest("base64");
}
module.exports = function(context, args) {
fs.writeFileSync(context.cwd + "/dist/hotfixApk/" + context.buildConfig.variants + ".json", JSON.stringify({
"time": context.buildConfig.publishTime,
"version": context.buildConfig.date,
"belongs": context.buildConfig.version,
"info": context.buildConfig.description,
"downloads": context.updateConfig.downloadSource,
"hotfix": {
"url": context.updateConfig.pageUrl + "hotfix/" + context.buildConfig.variants + ".js",
"sign": context.updateConfig.pageUrl + "hotfix/" + context.buildConfig.variants + ".sign",
"shell": context.gradleConfig.shellVersion,
"sha1": digestSHA1(fs.readFileSync(context.cwd + "/dist/hotfixApk/" + context.buildConfig.variants + ".js"))
},
"requirements": [
{
"type": "minsdk",
"value": context.gradleConfig.minSdkVersion
}
]
}));
}

View File

@ -1,5 +0,0 @@
const fs = require("fs");
module.exports = function(context, args) {
fs.writeFileSync(context.cwd + "/build/min.js", args[0]);
return args[0];
}

View File

@ -1,6 +0,0 @@
const fs = require("fs");
module.exports = function(context, args) {
fs.writeFileSync(context.cwd + "/dist/release/release.js", args[0]);
fs.copyFileSync(context.cwd + "/dist/release/release.js", context.cwd + "/dist/命令助手(" + context.buildConfig.date + ").js");
return args[0];
}

View File

@ -1,6 +0,0 @@
const fs = require("fs");
const zlib = require("zlib");
module.exports = function(context, args) {
fs.writeFileSync(context.cwd + "/dist/snapshot/snapshot.js", zlib.gzipSync(Buffer.from(args[0])));
return args[0];
}

View File

@ -1,28 +0,0 @@
const fs = require("fs");
const asLibrary = require("../js2lib");
module.exports = function(context, args) {
fs.writeFileSync(context.cwd + "/dist/snapshot/snapshot.lib", asLibrary(Buffer.from([
'Plugins.inject(function(o){',
'const id=' + JSON.stringify(context.buildConfig.date) + ';',
'function u(p,b){',
'var o=new java.io.FileOutputStream(p);',
'o.write(android.util.Base64.decode(b,2));',
'o.close();',
'}',
'o.name="命令助手快照包 - "+id;',
'o.description="命令助手快照安装器\\n";',
'o.uuid="f6cf1729-3861-481b-a9ac-e3f48cbc4a94";',
'o.author="命令助手制作组";',
'o.version=[1,0];',
'if (CA.publishDate==id){return void(o.description+="您正在使用本快照或更高版本\\n\\n"+ds)}',
'if(MapScript.host!="Android")return void(o.description+="本快照仅适用于App版");',
'u(MapScript.baseDir+"snapshot.js",' + JSON.stringify(Buffer.from(args[0]).toString("base64")) + ');',
'ctx.getSharedPreferences("user_settings",ctx.MODE_PRIVATE).edit().putString("debugSource",MapScript.baseDir+"snapshot.js").apply()',
'AndroidBridge.createShortcut(new android.content.Intent("com.xero.ca.DEBUG_EXEC").setComponent(new android.content.ComponentName("com.xero.ca","com.xero.ca.MainActivity")).addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK),"快照命令助手",com.xero.ca.R.mipmap.icon_small);',
'Common.showTextDialog(o.description+="快照已安装完毕,您可以在桌面找到快照版的快捷方式");',
'CA.Library.removeLibrary(path);',
'})'
].join("\n"))));
fs.copyFileSync(context.cwd + "/dist/snapshot/snapshot.lib", context.cwd + "/dist/命令助手快照" + context.buildConfig.date + ".lib");
return args[0];
}

View File

@ -1,19 +0,0 @@
const fs = require("fs");
const crypto = require("crypto");
function digestSHA1(data) {
var digest = crypto.createHash("sha1");
digest.update(data);
return digest.digest("base64");
}
module.exports = function(context, args) {
fs.writeFileSync(context.cwd + "/dist/snapshot/" + context.buildConfig.variants + ".json", JSON.stringify({
"time": context.buildConfig.publishTime,
"version": context.buildConfig.date,
"belongs": context.buildConfig.version,
"info": context.buildConfig.description,
"snapshot" : {
"url": context.updateConfig.pageUrl + context.buildConfig.variants + ".js",
"sha1": digestSHA1(fs.readFileSync(context.cwd + "/dist/snapshot/" + context.buildConfig.variants + ".js"))
}
}));
}

View File

@ -1,10 +0,0 @@
const fs = require("fs");
module.exports = function(context, args) {
fs.writeFileSync(context.cwd + "/dist/update/" + context.buildConfig.variants + ".json", JSON.stringify({
"time": context.buildConfig.publishTime,
"version": context.buildConfig.date,
"belongs": context.buildConfig.version,
"info": context.buildConfig.description,
"downloads": context.updateConfig.downloadSource
}));
}