koishi-plugin-aktmp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/evmOpenApi.d.ts +45 -0
- package/lib/api/evmOpenApi.js +158 -0
- package/lib/api/truckersMpApi.d.ts +34 -0
- package/lib/api/truckersMpApi.js +110 -0
- package/lib/api/truckersMpMapApi.d.ts +6 -0
- package/lib/api/truckersMpMapApi.js +25 -0
- package/lib/api/truckyAppApi.d.ts +12 -0
- package/lib/api/truckyAppApi.js +32 -0
- package/lib/command/tmpBind.d.ts +2 -0
- package/lib/command/tmpBind.js +19 -0
- package/lib/command/tmpDlcMap.d.ts +3 -0
- package/lib/command/tmpDlcMap.js +33 -0
- package/lib/command/tmpFootprint.d.ts +3 -0
- package/lib/command/tmpFootprint.js +82 -0
- package/lib/command/tmpMileageRanking.d.ts +3 -0
- package/lib/command/tmpMileageRanking.js +55 -0
- package/lib/command/tmpPosition.d.ts +3 -0
- package/lib/command/tmpPosition.js +95 -0
- package/lib/command/tmpQuery.d.ts +2 -0
- package/lib/command/tmpQuery.js +148 -0
- package/lib/command/tmpServer/tmpServer.d.ts +2 -0
- package/lib/command/tmpServer/tmpServer.js +15 -0
- package/lib/command/tmpServer/tmpServerImg.d.ts +3 -0
- package/lib/command/tmpServer/tmpServerImg.js +35 -0
- package/lib/command/tmpServer/tmpServerText.d.ts +2 -0
- package/lib/command/tmpServer/tmpServerText.js +40 -0
- package/lib/command/tmpTraffic/tmpTraffic.d.ts +2 -0
- package/lib/command/tmpTraffic/tmpTraffic.js +15 -0
- package/lib/command/tmpTraffic/tmpTrafficMap.d.ts +3 -0
- package/lib/command/tmpTraffic/tmpTrafficMap.js +119 -0
- package/lib/command/tmpTraffic/tmpTrafficText.d.ts +2 -0
- package/lib/command/tmpTraffic/tmpTrafficText.js +122 -0
- package/lib/command/tmpUnbind.js +17 -0
- package/lib/command/tmpVersion.d.ts +2 -0
- package/lib/command/tmpVersion.js +31 -0
- package/lib/database/guildBind.d.ts +22 -0
- package/lib/database/guildBind.js +55 -0
- package/lib/database/model.d.ts +2 -0
- package/lib/database/model.js +65 -0
- package/lib/database/translateCache.d.ts +14 -0
- package/lib/database/translateCache.js +31 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.js +59 -0
- package/lib/resource/dlc.html +115 -0
- package/lib/resource/footprint.html +241 -0
- package/lib/resource/mileage-leaderboard.html +363 -0
- package/lib/resource/package/SEGUIEMJ.TTF +0 -0
- package/lib/resource/package/ets-map.js +63 -0
- package/lib/resource/package/leaflet/heatmap.min.js +9 -0
- package/lib/resource/package/leaflet/leaflet-heatmap.js +246 -0
- package/lib/resource/package/leaflet/leaflet.min.css +1 -0
- package/lib/resource/package/leaflet/leaflet.min.js +1 -0
- package/lib/resource/position.html +229 -0
- package/lib/resource/server-list.html +309 -0
- package/lib/resource/traffic.html +207 -0
- package/lib/util/baiduTranslate.d.ts +2 -0
- package/lib/util/baiduTranslate.js +30 -0
- package/lib/util/common.d.ts +1 -0
- package/lib/util/common.js +5 -0
- package/lib/util/constant.d.ts +19 -0
- package/lib/util/constant.js +36 -0
- package/package.json +48 -0
- package/readme.md +86 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Server List</title>
|
|
6
|
+
<style>
|
|
7
|
+
* {
|
|
8
|
+
margin: 0;
|
|
9
|
+
padding: 0;
|
|
10
|
+
box-sizing: border-box;
|
|
11
|
+
}
|
|
12
|
+
body {
|
|
13
|
+
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
|
|
14
|
+
background-color: #0b1120;
|
|
15
|
+
}
|
|
16
|
+
#container {
|
|
17
|
+
width: 380px;
|
|
18
|
+
background: linear-gradient(180deg, #0f1a2e 0%, #0b1120 100%);
|
|
19
|
+
padding: 0 0 6px 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Header */
|
|
23
|
+
.header {
|
|
24
|
+
height: 42px;
|
|
25
|
+
background-color: rgba(0, 0, 0, 0.3);
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
|
|
30
|
+
}
|
|
31
|
+
.header .title {
|
|
32
|
+
color: #8bafff;
|
|
33
|
+
font-size: 14px;
|
|
34
|
+
font-weight: 600;
|
|
35
|
+
letter-spacing: 1px;
|
|
36
|
+
}
|
|
37
|
+
.header .subtitle {
|
|
38
|
+
color: #6e7a8a;
|
|
39
|
+
font-size: 11px;
|
|
40
|
+
margin-top: 2px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Server list */
|
|
44
|
+
.server-list {
|
|
45
|
+
padding: 6px 10px 0 10px;
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
gap: 5px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* Server card */
|
|
52
|
+
.server-card {
|
|
53
|
+
background: rgba(22, 33, 55, 0.8);
|
|
54
|
+
border-radius: 6px;
|
|
55
|
+
border: 1px solid rgba(139, 175, 255, 0.08);
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Card info */
|
|
60
|
+
.server-info {
|
|
61
|
+
padding: 7px 12px 5px 12px;
|
|
62
|
+
}
|
|
63
|
+
.server-row {
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
justify-content: space-between;
|
|
67
|
+
}
|
|
68
|
+
.server-left {
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
gap: 6px;
|
|
72
|
+
flex: 1;
|
|
73
|
+
min-width: 0;
|
|
74
|
+
}
|
|
75
|
+
.status-indicator {
|
|
76
|
+
width: 6px;
|
|
77
|
+
height: 6px;
|
|
78
|
+
border-radius: 50%;
|
|
79
|
+
flex-shrink: 0;
|
|
80
|
+
}
|
|
81
|
+
.status-indicator.online {
|
|
82
|
+
background-color: #34d058;
|
|
83
|
+
box-shadow: 0 0 5px rgba(52, 208, 88, 0.5);
|
|
84
|
+
}
|
|
85
|
+
.status-indicator.offline {
|
|
86
|
+
background-color: #484f58;
|
|
87
|
+
}
|
|
88
|
+
.server-name {
|
|
89
|
+
color: #e6edf3;
|
|
90
|
+
font-size: 13px;
|
|
91
|
+
font-weight: 600;
|
|
92
|
+
white-space: nowrap;
|
|
93
|
+
overflow: hidden;
|
|
94
|
+
text-overflow: ellipsis;
|
|
95
|
+
max-width: 200px;
|
|
96
|
+
}
|
|
97
|
+
.player-count {
|
|
98
|
+
color: #6e7a8a;
|
|
99
|
+
font-size: 11px;
|
|
100
|
+
white-space: nowrap;
|
|
101
|
+
flex-shrink: 0;
|
|
102
|
+
margin-left: 6px;
|
|
103
|
+
}
|
|
104
|
+
.player-count .num {
|
|
105
|
+
color: #c9d1d9;
|
|
106
|
+
font-weight: 700;
|
|
107
|
+
font-size: 12px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Features row */
|
|
111
|
+
.features {
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
gap: 8px;
|
|
115
|
+
margin-top: 3px;
|
|
116
|
+
}
|
|
117
|
+
.feature {
|
|
118
|
+
font-size: 10px;
|
|
119
|
+
color: #5a6572;
|
|
120
|
+
white-space: nowrap;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Queue badge */
|
|
124
|
+
.queue-badge {
|
|
125
|
+
color: #f0883e;
|
|
126
|
+
font-size: 10px;
|
|
127
|
+
margin-left: 6px;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* Chart area */
|
|
131
|
+
.chart-area {
|
|
132
|
+
position: relative;
|
|
133
|
+
height: 38px;
|
|
134
|
+
}
|
|
135
|
+
.chart-area svg {
|
|
136
|
+
display: block;
|
|
137
|
+
width: 100%;
|
|
138
|
+
height: 100%;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
</style>
|
|
142
|
+
</head>
|
|
143
|
+
<body>
|
|
144
|
+
<div id="container">
|
|
145
|
+
<div class="header">
|
|
146
|
+
<div class="title">TruckersMP 服务器状态</div>
|
|
147
|
+
<div class="subtitle" id="total-online"></div>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div class="server-list" id="server-list"></div>
|
|
151
|
+
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<script>
|
|
155
|
+
/**
|
|
156
|
+
* 构建 SVG 面积折线图
|
|
157
|
+
* maxPlayer 的 50% 作为余量,上限不超过 maxPlayer
|
|
158
|
+
*/
|
|
159
|
+
function buildChartSVG(data, width, height, maxPlayer) {
|
|
160
|
+
const padTop = 2;
|
|
161
|
+
const padBottom = 0;
|
|
162
|
+
const chartW = width;
|
|
163
|
+
const chartH = height - padTop - padBottom;
|
|
164
|
+
|
|
165
|
+
const dataMax = Math.max(...data, 1);
|
|
166
|
+
const max = Math.min(maxPlayer, maxPlayer * 0.12 + dataMax);
|
|
167
|
+
const step = chartW / (data.length - 1);
|
|
168
|
+
|
|
169
|
+
const points = data.map((v, i) => {
|
|
170
|
+
const x = i * step;
|
|
171
|
+
const y = padTop + chartH - (v / max) * chartH;
|
|
172
|
+
return [x, y];
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const lineD = points.map((p, i) => (i === 0 ? `M${p[0]},${p[1]}` : `L${p[0]},${p[1]}`)).join(' ');
|
|
176
|
+
const areaD = lineD
|
|
177
|
+
+ ` L${points[points.length - 1][0]},${padTop + chartH}`
|
|
178
|
+
+ ` L${points[0][0]},${padTop + chartH} Z`;
|
|
179
|
+
|
|
180
|
+
const gid = 'g' + Math.random().toString(36).slice(2, 8);
|
|
181
|
+
|
|
182
|
+
return `
|
|
183
|
+
<svg viewBox="0 0 ${width} ${height}" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
|
|
184
|
+
<defs>
|
|
185
|
+
<linearGradient id="${gid}" x1="0" y1="0" x2="0" y2="1">
|
|
186
|
+
<stop offset="0%" stop-color="rgba(79,139,255,0.4)"/>
|
|
187
|
+
<stop offset="100%" stop-color="rgba(79,139,255,0.02)"/>
|
|
188
|
+
</linearGradient>
|
|
189
|
+
</defs>
|
|
190
|
+
<path d="${areaD}" fill="url(#${gid})"/>
|
|
191
|
+
<path d="${lineD}" fill="none" stroke="#4f8bff" stroke-width="1.5" stroke-linejoin="round"/>
|
|
192
|
+
</svg>`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 将 playerHistory 标准化为 288 个点(24h,每5分钟一个点)
|
|
197
|
+
* 缺失的时间段填充为 0
|
|
198
|
+
* @param {Array<{updateTime: string, playerCount: number}>} playerHistory
|
|
199
|
+
*/
|
|
200
|
+
function normalizeHistory(playerHistory) {
|
|
201
|
+
const SLOT_COUNT = 288;
|
|
202
|
+
const SLOT_MS = 300000;
|
|
203
|
+
|
|
204
|
+
if (!playerHistory || playerHistory.length === 0) return [];
|
|
205
|
+
|
|
206
|
+
// API 返回的是北京时间(UTC+8),用 Date.UTC 生成时间戳再减去8小时偏移
|
|
207
|
+
function parseTime(str) {
|
|
208
|
+
const [datePart, timePart] = str.trim().replace('T', ' ').split(' ');
|
|
209
|
+
const [y, m, d] = datePart.split('-').map(Number);
|
|
210
|
+
const parts = timePart.split(':').map(Number);
|
|
211
|
+
const h = parts[0] || 0, min = parts[1] || 0;
|
|
212
|
+
return Date.UTC(y, m - 1, d, h, min, 0) - 8 * 3600000;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const now = Date.now();
|
|
216
|
+
const currentSlot = Math.floor(now / SLOT_MS) * SLOT_MS;
|
|
217
|
+
|
|
218
|
+
const dataMap = {};
|
|
219
|
+
for (const item of playerHistory) {
|
|
220
|
+
const ts = parseTime(item.updateTime);
|
|
221
|
+
if (isNaN(ts)) continue;
|
|
222
|
+
const slot = Math.floor(ts / SLOT_MS) * SLOT_MS;
|
|
223
|
+
dataMap[slot] = item.playerCount;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const result = [];
|
|
227
|
+
for (let i = 0; i < SLOT_COUNT; i++) {
|
|
228
|
+
const slotTime = currentSlot - (SLOT_COUNT - 1 - i) * SLOT_MS;
|
|
229
|
+
result.push(dataMap[slotTime] !== undefined ? dataMap[slotTime] : 0);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 渲染一个服务器卡片
|
|
237
|
+
*/
|
|
238
|
+
function createServerCard(server) {
|
|
239
|
+
const card = document.createElement('div');
|
|
240
|
+
card.className = 'server-card';
|
|
241
|
+
|
|
242
|
+
// 只展示存在的特性
|
|
243
|
+
let featuresHTML = '';
|
|
244
|
+
if (server.collisionsEnable === 1) {
|
|
245
|
+
featuresHTML += '<span class="feature">💥 碰撞</span>';
|
|
246
|
+
}
|
|
247
|
+
if (server.afkEnable === 0) {
|
|
248
|
+
featuresHTML += '<span class="feature">💤 挂机</span>';
|
|
249
|
+
}
|
|
250
|
+
if (server.policeCarEnable === 1) {
|
|
251
|
+
featuresHTML += '<span class="feature">🚓 警车</span>';
|
|
252
|
+
}
|
|
253
|
+
if (server.speedLimiterEnable === 1) {
|
|
254
|
+
featuresHTML += '<span class="feature">🐢 限速</span>';
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// 队列
|
|
258
|
+
let queueText = '';
|
|
259
|
+
if (server.queueCount > 0) {
|
|
260
|
+
queueText = `<span class="queue-badge">队列 ${server.queueCount}</span>`;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
card.innerHTML = `
|
|
264
|
+
<div class="server-info">
|
|
265
|
+
<div class="server-row">
|
|
266
|
+
<div class="server-left">
|
|
267
|
+
<span class="status-indicator ${server.isOnline === 1 ? 'online' : 'offline'}"></span>
|
|
268
|
+
<span class="server-name">${server.serverName}</span>
|
|
269
|
+
</div>
|
|
270
|
+
<span class="player-count"><span class="num">${server.playerCount}</span> / ${server.maxPlayer}${queueText}</span>
|
|
271
|
+
</div>
|
|
272
|
+
${featuresHTML ? '<div class="features">' + featuresHTML + '</div>' : ''}
|
|
273
|
+
</div>
|
|
274
|
+
<div class="chart-area">
|
|
275
|
+
${server.isOnline === 1 && server.playerHistory && server.playerHistory.length > 0
|
|
276
|
+
? (() => {
|
|
277
|
+
const normalized = normalizeHistory(server.playerHistory);
|
|
278
|
+
return normalized.length > 0 ? buildChartSVG(normalized, 380, 38, server.maxPlayer) : '';
|
|
279
|
+
})()
|
|
280
|
+
: ''}
|
|
281
|
+
</div>`;
|
|
282
|
+
|
|
283
|
+
return card;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* 主渲染函数
|
|
288
|
+
*/
|
|
289
|
+
function setData(apiData) {
|
|
290
|
+
if (!apiData || !apiData.data) return;
|
|
291
|
+
|
|
292
|
+
const servers = apiData.data;
|
|
293
|
+
const listEl = document.getElementById('server-list');
|
|
294
|
+
const totalOnlineEl = document.getElementById('total-online');
|
|
295
|
+
|
|
296
|
+
// 计算总在线人数
|
|
297
|
+
const totalOnline = servers.reduce((sum, s) => sum + (s.playerCount || 0), 0);
|
|
298
|
+
totalOnlineEl.textContent = '📊 总在线: ' + totalOnline + ' 人';
|
|
299
|
+
|
|
300
|
+
listEl.innerHTML = '';
|
|
301
|
+
|
|
302
|
+
servers.forEach(server => {
|
|
303
|
+
listEl.appendChild(createServerCard(server));
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
</script>
|
|
308
|
+
</body>
|
|
309
|
+
</html>
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title></title>
|
|
6
|
+
<link href="./package/leaflet/leaflet.min.css" rel="stylesheet">
|
|
7
|
+
<script src="./package/leaflet/leaflet.min.js"></script>
|
|
8
|
+
<script src="./package/leaflet/heatmap.min.js"></script>
|
|
9
|
+
<script src="./package/leaflet/leaflet-heatmap.js"></script>
|
|
10
|
+
<style>
|
|
11
|
+
body, html {
|
|
12
|
+
margin: 0;
|
|
13
|
+
padding: 0;
|
|
14
|
+
}
|
|
15
|
+
* {
|
|
16
|
+
font-family: "微软雅黑", serif;
|
|
17
|
+
}
|
|
18
|
+
#container {
|
|
19
|
+
width: 1000px;
|
|
20
|
+
position: relative;
|
|
21
|
+
}
|
|
22
|
+
.map {
|
|
23
|
+
width: 100%;
|
|
24
|
+
height: 900px;
|
|
25
|
+
background-color: #4b4b4b;
|
|
26
|
+
}
|
|
27
|
+
.traffic-box {
|
|
28
|
+
//position: absolute;
|
|
29
|
+
//bottom: 0;
|
|
30
|
+
//left: 0;
|
|
31
|
+
//z-index: 9999999;
|
|
32
|
+
width: 100%;
|
|
33
|
+
backdrop-filter: blur(3px);
|
|
34
|
+
background-color: #4b4b4b;
|
|
35
|
+
padding: 12px 16px;
|
|
36
|
+
box-sizing: border-box;
|
|
37
|
+
overflow-y: hidden;
|
|
38
|
+
}
|
|
39
|
+
.traffic-item {
|
|
40
|
+
color: #ffffff;
|
|
41
|
+
width: 33.3333%;
|
|
42
|
+
float: left;
|
|
43
|
+
margin-top: 8px;
|
|
44
|
+
font-size: 14px;
|
|
45
|
+
border-right: 1px solid rgba(255, 255, 255, 0.3);
|
|
46
|
+
box-sizing: border-box;
|
|
47
|
+
padding: 0 10px;
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: row;
|
|
50
|
+
align-items: center;
|
|
51
|
+
justify-content: center;
|
|
52
|
+
}
|
|
53
|
+
.traffic-item:nth-child(-n+3) {
|
|
54
|
+
margin-top: 0;
|
|
55
|
+
}
|
|
56
|
+
.traffic-item:last-child, .traffic-item:nth-child(3n) {
|
|
57
|
+
border-right: 0;
|
|
58
|
+
}
|
|
59
|
+
.traffic-item .region-info {
|
|
60
|
+
display: inline-block;
|
|
61
|
+
width: 72%;
|
|
62
|
+
white-space: nowrap;
|
|
63
|
+
overflow: hidden;
|
|
64
|
+
text-overflow: ellipsis;
|
|
65
|
+
}
|
|
66
|
+
.traffic-item .player-count {
|
|
67
|
+
display: inline-block;
|
|
68
|
+
width: 16%;
|
|
69
|
+
text-align: center;
|
|
70
|
+
}
|
|
71
|
+
.traffic-item .traffic-status {
|
|
72
|
+
display: inline-block;
|
|
73
|
+
width: 12%;
|
|
74
|
+
text-align: right;
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
77
|
+
</head>
|
|
78
|
+
<body>
|
|
79
|
+
<div id="container">
|
|
80
|
+
<div id="map" class="map"></div>
|
|
81
|
+
<div class="traffic-box"></div>
|
|
82
|
+
</div>
|
|
83
|
+
<script>
|
|
84
|
+
let mapConfig = {
|
|
85
|
+
ets: {
|
|
86
|
+
tileUrl: 'https://ets-map.oss-cn-beijing.aliyuncs.com/ets2/05102019/{z}/{x}/{y}.png',
|
|
87
|
+
multipliers: {
|
|
88
|
+
x: 70272,
|
|
89
|
+
y: 76157
|
|
90
|
+
},
|
|
91
|
+
breakpoints: {
|
|
92
|
+
uk: {
|
|
93
|
+
x: -31056.8,
|
|
94
|
+
y: -5832.867
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
bounds: {
|
|
98
|
+
y: 131072,
|
|
99
|
+
x: 131072
|
|
100
|
+
},
|
|
101
|
+
maxZoom: 8,
|
|
102
|
+
minZoom: 2,
|
|
103
|
+
// 游戏地转地图坐标
|
|
104
|
+
calculateMapCoordinate (x, y) {
|
|
105
|
+
return [
|
|
106
|
+
x / 1.609055 + mapConfig.ets.multipliers.x,
|
|
107
|
+
y / 1.609055 + mapConfig.ets.multipliers.y
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
promods: {
|
|
112
|
+
tileUrl: 'https://ets-map.oss-cn-beijing.aliyuncs.com/promods/05102019/{z}/{x}/{y}.png',
|
|
113
|
+
multipliers: {
|
|
114
|
+
x: 51953,
|
|
115
|
+
y: 76024
|
|
116
|
+
},
|
|
117
|
+
breakpoints: {
|
|
118
|
+
uk: {
|
|
119
|
+
x: -31056.8,
|
|
120
|
+
y: -5832.867
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
bounds: {
|
|
124
|
+
y: 131072,
|
|
125
|
+
x: 131072
|
|
126
|
+
},
|
|
127
|
+
maxZoom: 8,
|
|
128
|
+
minZoom: 2,
|
|
129
|
+
// 游戏地转地图坐标
|
|
130
|
+
calculateMapCoordinate (x, y) {
|
|
131
|
+
return [
|
|
132
|
+
x / 2.598541 + mapConfig.promods.multipliers.x,
|
|
133
|
+
y / 2.598541 + mapConfig.promods.multipliers.y
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 定义地图
|
|
140
|
+
let map = L.map('map', {
|
|
141
|
+
attributionControl: false,
|
|
142
|
+
crs: L.CRS.Simple,
|
|
143
|
+
zoomControl: false,
|
|
144
|
+
zoomSnap: 0.1
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
function setData(data) {
|
|
148
|
+
// 边界
|
|
149
|
+
let bounds = L.latLngBounds(
|
|
150
|
+
map.unproject([0, mapConfig[data.mapType].bounds.y], mapConfig[data.mapType].maxZoom),
|
|
151
|
+
map.unproject([mapConfig[data.mapType].bounds.x, 0], mapConfig[data.mapType].maxZoom)
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
// 瓦片地图
|
|
155
|
+
L.tileLayer(mapConfig[data.mapType].tileUrl, {
|
|
156
|
+
minZoom: 0,
|
|
157
|
+
maxZoom: 8,
|
|
158
|
+
minNativeZoom: 1,
|
|
159
|
+
maxNativeZoom: 8,
|
|
160
|
+
tileSize: 512,
|
|
161
|
+
bounds: bounds,
|
|
162
|
+
reuseTiles: true
|
|
163
|
+
}).addTo(map);
|
|
164
|
+
map.setMaxBounds(
|
|
165
|
+
new L.LatLngBounds(
|
|
166
|
+
map.unproject([0, mapConfig[data.mapType].bounds.y], mapConfig[data.mapType].maxZoom),
|
|
167
|
+
map.unproject([mapConfig[data.mapType].bounds.x, 0], mapConfig[data.mapType].maxZoom)
|
|
168
|
+
)
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// 展示地图全貌
|
|
172
|
+
map.fitBounds(bounds)
|
|
173
|
+
|
|
174
|
+
// 热力图
|
|
175
|
+
let heatmapLayer = new HeatmapOverlay({
|
|
176
|
+
radius: 3,
|
|
177
|
+
maxOpacity: 0.8,
|
|
178
|
+
scaleRadius: true,
|
|
179
|
+
useLocalExtrema: true,
|
|
180
|
+
latField: "lat",
|
|
181
|
+
lngField: "lng",
|
|
182
|
+
valueField: "count"
|
|
183
|
+
});
|
|
184
|
+
map.addLayer(heatmapLayer);
|
|
185
|
+
let heatmapData = []
|
|
186
|
+
for (const arrayElement of data.playerCoordinateList) {
|
|
187
|
+
let unprojected = map.unproject(mapConfig[data.mapType].calculateMapCoordinate(arrayElement[0], arrayElement[1]), 8);
|
|
188
|
+
heatmapData.push({ lat: unprojected.lat, lng: unprojected.lng, count: 1 });
|
|
189
|
+
}
|
|
190
|
+
heatmapLayer.setData({
|
|
191
|
+
min: 1,
|
|
192
|
+
max: 5000,
|
|
193
|
+
data: heatmapData
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
// 展示热门地区路况状态
|
|
197
|
+
for (const traffic of data.trafficList) {
|
|
198
|
+
document.getElementsByClassName('traffic-box')[0].insertAdjacentHTML('beforeend', `
|
|
199
|
+
<div class="traffic-item">
|
|
200
|
+
<span class="region-info"><strong>${traffic.country}</strong> ${traffic.province}</span><span class="player-count">${traffic.playerCount}人</span><span class="traffic-status" style="color: ${traffic.severity.color}">${traffic.severity.text}</span>
|
|
201
|
+
</div>
|
|
202
|
+
`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
</script>
|
|
206
|
+
</body>
|
|
207
|
+
</html>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const md5 = require('js-md5');
|
|
2
|
+
const translateCache = require('../database/translateCache');
|
|
3
|
+
const TRANSLATE_API = 'https://fanyi-api.baidu.com/api/trans/vip/translate';
|
|
4
|
+
module.exports = async (ctx, cfg, content, cache = true) => {
|
|
5
|
+
// 没有开启百度翻译功能,直接返回文本
|
|
6
|
+
if (!cfg.baiduTranslateEnable) {
|
|
7
|
+
return content;
|
|
8
|
+
}
|
|
9
|
+
// 如果开启了缓存,尝试从缓存中查询翻译
|
|
10
|
+
if (cfg.baiduTranslateCacheEnable && cache) {
|
|
11
|
+
let translateContent = await translateCache.getTranslate(ctx.database, md5(content));
|
|
12
|
+
if (translateContent) {
|
|
13
|
+
return translateContent;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// 创建请求秘钥
|
|
17
|
+
let randomInt = Math.floor(Math.random() * 10000);
|
|
18
|
+
let sign = md5(cfg.baiduTranslateAppId + content + randomInt + cfg.baiduTranslateKey);
|
|
19
|
+
// 调用请求
|
|
20
|
+
let result = await ctx.http.get(`${TRANSLATE_API}?q=${encodeURI(content)}&from=auto&to=zh&appid=${cfg.baiduTranslateAppId}&salt=${randomInt}&sign=${sign}`);
|
|
21
|
+
// 如果翻译失败,直接返回内容
|
|
22
|
+
if (result.error_code) {
|
|
23
|
+
return content;
|
|
24
|
+
}
|
|
25
|
+
// 如果开启了缓存,将翻译内容缓存到数据库
|
|
26
|
+
if (cfg.baiduTranslateCacheEnable && cache) {
|
|
27
|
+
translateCache.save(ctx.database, md5(content), content, result.trans_result[0].dst);
|
|
28
|
+
}
|
|
29
|
+
return result.trans_result[0].dst;
|
|
30
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function sleep(ms: any): Promise<any>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export namespace TmpTrafficType {
|
|
2
|
+
let text: number;
|
|
3
|
+
let heatMap: number;
|
|
4
|
+
}
|
|
5
|
+
export namespace MileageRankingType {
|
|
6
|
+
let total: number;
|
|
7
|
+
let today: number;
|
|
8
|
+
}
|
|
9
|
+
export namespace ServerAliasToId {
|
|
10
|
+
let s1: number;
|
|
11
|
+
let s2: number;
|
|
12
|
+
let p: number;
|
|
13
|
+
let a: number;
|
|
14
|
+
}
|
|
15
|
+
export let PromodsIds: number[];
|
|
16
|
+
export namespace ServerType {
|
|
17
|
+
let ets: number;
|
|
18
|
+
let promods: number;
|
|
19
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
/**
|
|
3
|
+
* 路况信息展示方式
|
|
4
|
+
*/
|
|
5
|
+
TmpTrafficType: {
|
|
6
|
+
text: 1, // 文本
|
|
7
|
+
heatMap: 2, // 热力图
|
|
8
|
+
},
|
|
9
|
+
/**
|
|
10
|
+
* 里程排行榜类型
|
|
11
|
+
*/
|
|
12
|
+
MileageRankingType: {
|
|
13
|
+
total: 1,
|
|
14
|
+
today: 2
|
|
15
|
+
},
|
|
16
|
+
/**
|
|
17
|
+
* 服务器别名映射ID
|
|
18
|
+
*/
|
|
19
|
+
ServerAliasToId: {
|
|
20
|
+
's1': 2,
|
|
21
|
+
's2': 41,
|
|
22
|
+
'p': 50,
|
|
23
|
+
'a': 7
|
|
24
|
+
},
|
|
25
|
+
/**
|
|
26
|
+
* P服务器ID集合
|
|
27
|
+
*/
|
|
28
|
+
PromodsIds: [50, 51],
|
|
29
|
+
/**
|
|
30
|
+
* 服务器类型
|
|
31
|
+
*/
|
|
32
|
+
ServerType: {
|
|
33
|
+
ets: 1,
|
|
34
|
+
promods: 2
|
|
35
|
+
}
|
|
36
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "koishi-plugin-aktmp",
|
|
3
|
+
"description": "欧洲卡车模拟2查询欧卡TruckersMP查询插件工具,作者:阿K*QQ737107334",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"typings": "lib/index.d.ts",
|
|
7
|
+
"homepage": "https://github.com/737107334/koishi-plugin-aktmp",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/737107334/koishi-plugin-aktmp"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/737107334/koishi-plugin-aktmp/issues"
|
|
14
|
+
},
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "阿K",
|
|
17
|
+
"url": "https://space.bilibili.com/606891061"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"lib",
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"scripts": {},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"chatbot",
|
|
27
|
+
"koishi",
|
|
28
|
+
"plugin",
|
|
29
|
+
"truckersmp",
|
|
30
|
+
"gametool",
|
|
31
|
+
"ets2",
|
|
32
|
+
"tmp"
|
|
33
|
+
],
|
|
34
|
+
"koishi": {
|
|
35
|
+
"service": {
|
|
36
|
+
"required": [
|
|
37
|
+
"database"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"koishi": "^4.18.7"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"dayjs": "^1.11.13",
|
|
46
|
+
"js-md5": "^0.8.3"
|
|
47
|
+
}
|
|
48
|
+
}
|