Skip to content
This repository was archived by the owner on Jul 28, 2024. It is now read-only.

Commit a5b17a8

Browse files
committed
update to 1.2.0
add Websocket async connect support, need lxl support fix some bugs export som APIs, see API/FpmApiTemplate for more detail
1 parent 70425d6 commit a5b17a8

6 files changed

Lines changed: 1608 additions & 1163 deletions

File tree

API/FpmApiTemplate.js

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
/* eslint-disable no-undef */
2+
3+
const PluginIdentifier = "FpmApiTemplate";
4+
5+
/**
6+
* async version of setTimeout
7+
* @param {Number} ms milliseconds to wait
8+
* @returns {Promise<void>}
9+
*/
10+
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
11+
12+
/////////////////////////////////////// FakePlayerManager API START ///////////////////////////////////////
13+
14+
const FPM_API_PREFIX = "FakePlayerManagerAPI";
15+
const FPM_API_DEBUG = false;
16+
17+
/**
18+
* @type {boolean} whether the FakePlayerManager is installed
19+
*/
20+
const FPM_INSTALLED = lxl.require("FakePlayerManager.lxl.js");
21+
if(!FPM_INSTALLED){
22+
// TODO when FakePlayerManager.lxl.js is not found
23+
}
24+
25+
/**
26+
* Import a FakePlayerManager API by name
27+
* @param {string} name the name of the API
28+
* @returns {(...args: any[]) => any} the API
29+
*/
30+
function fpmImport(name){
31+
if(FPM_INSTALLED){
32+
if(FPM_API_DEBUG) logger.info(`Importing FakePlayerManager API ${name}`);
33+
return lxl.import(`${FPM_API_PREFIX}_${name}`);
34+
}else{
35+
return ()=>{
36+
logger.error(`Can't call ${name} because FakePlayerManager is not installed.`);
37+
logger.error(`Please install FakePlayerManager.lxl.js first.`);
38+
logger.error(`You can download it from https://www.minebbs.com/resources/fakeplayermanager-gui.2945/`);
39+
if(FPM_API_DEBUG) throw new Error("FakePlayerManager is not installed.");
40+
};
41+
}
42+
}
43+
44+
/**
45+
* @param {string} identifier the identifier of the API
46+
* @param {string} resolveFuncName the name of the resolve function
47+
* @param {string} rejectFuncName the name of the reject function
48+
* @returns {void}
49+
* @type {(identifier: string, resolveFuncName: string, rejectFuncName: string) => void}
50+
*/
51+
const fpmResiterAsync = fpmImport("registerAsync");
52+
53+
/**
54+
* Import a async FakePlayerManager API by name
55+
* @param {string} name the name of the API, e.g. "list"
56+
* @returns {(...args: any[]) => Promise<any>} the API
57+
*/
58+
function fpmImportAsync(name){
59+
if(!FPM_INSTALLED){
60+
return async ()=>{
61+
logger.error(`Can't call ${name} because FakePlayerManager is not installed.`);
62+
logger.error(`Please install FakePlayerManager.lxl.js first.`);
63+
logger.error(`You can download it from https://www.minebbs.com/resources/fakeplayermanager-gui.2945/`);
64+
if(FPM_API_DEBUG) throw new Error("FakePlayerManager is not installed.");
65+
};
66+
}
67+
const fullName = `${FPM_API_PREFIX}_async_${PluginIdentifier}_${name}`;
68+
let resolveFunc = {};
69+
let rejectFunc = {};
70+
lxl.export((id, ...args)=>{
71+
if(Object.prototype.hasOwnProperty.call(resolveFunc, id)){
72+
resolveFunc[id](...args);
73+
delete resolveFunc[id];
74+
}
75+
}, `${fullName}_resolve`);
76+
lxl.export((id, ...args)=>{
77+
if(Object.prototype.hasOwnProperty.call(rejectFunc, id)){
78+
rejectFunc[id](...args);
79+
delete rejectFunc[id];
80+
}
81+
}, `${fullName}_reject`);
82+
83+
if(FPM_API_DEBUG) logger.info(`fpmResiterAsync ${fullName}`);
84+
setTimeout(() => {
85+
fpmResiterAsync(`${fullName}`,`${fullName}_resolve`,`${fullName}_reject`);
86+
}, 0);
87+
if(FPM_API_DEBUG) logger.info(`Importing FakePlayerManager API async_${name}`);
88+
const syncFunc = fpmImport(`async_${name}`);
89+
90+
return async(...args) => {
91+
if(!FpmApi.inited){
92+
await wait(0);
93+
FpmApi.inited = true;
94+
}
95+
return new Promise((resolve, reject) => {
96+
const id = system.randomGuid();
97+
resolveFunc[id] = resolve;
98+
rejectFunc[id] = reject;
99+
try{
100+
syncFunc(fullName, id, ...args);
101+
}catch(e){
102+
reject(e);
103+
}
104+
});
105+
};
106+
}
107+
108+
/**
109+
* FakePlayerManager API for LiteLoader Script Engine
110+
* @author xiaoqch
111+
* @version 1.2.0
112+
* @license MIT
113+
* @see https://www.minebbs.com/resources/fakeplayermanager-gui.2945/
114+
*/
115+
// eslint-disable-next-line no-unused-vars
116+
class FpmApi{
117+
/**
118+
* @type {boolean} whether the FakePlayerManager is installed
119+
*/
120+
inited = false;
121+
/**
122+
* get the list of all the fake players
123+
* @type {() => Promise<string[]>}
124+
* @example
125+
* FpmApi.list().then(list=>{
126+
* logger.info(`${list.length} players found.`);
127+
* }).catch(err=>{
128+
* logger.error(`${err.name}: ${err.message}`);
129+
* logger.error(err.stack);
130+
* });
131+
* @example
132+
* try{
133+
* const list = await FpmApi.list();
134+
* logger.info(`${list.length} players found.`);
135+
* }catch(err){
136+
* logger.error(`${err.name}: ${err.message}`);
137+
* logger.error(err.stack);
138+
* }
139+
*/
140+
static list = fpmImportAsync("list");
141+
142+
/**
143+
* add a fake player
144+
* @type {(name: string, allowChatControl: boolean?, skin: string?) => Promise<{success: boolean, reason: string}>}
145+
* @example:
146+
* const { success, reason } = await FpmApi.add("Player");
147+
*/
148+
static add = fpmImportAsync("add");
149+
150+
/**
151+
* connect to a fake player
152+
* @type {(name: string) => Promise<{success: boolean, reason: string}>}
153+
* @example
154+
* const { success, reason } = await FpmApi.connect("Player");
155+
*/
156+
static connect = fpmImportAsync("connect");
157+
158+
/**
159+
* disconnect a fake player
160+
* @type {(name: string) => Promise<{name:string, success:boolean, reason:string}>}
161+
*/
162+
static disconnect = fpmImportAsync("disconnect");
163+
164+
/**
165+
* get state of a fake player
166+
* @type {(name: string) => Promise<{name:string, success:boolean, resaon: string, state: string}>}
167+
* @example
168+
* const { success, reason, state } = await FpmApi.getState("Player");
169+
*/
170+
static getState = fpmImportAsync("getState");
171+
172+
/**
173+
* get states of all fake players
174+
* @type {() => Promise<object>}
175+
* @example
176+
* const states = await FpmApi.getStates();
177+
* const playerNames = Object.keys(states);
178+
* for(const name of playerNames){
179+
* const state = states[name].state;
180+
* const allowChatControl = states[name].allowChatControl;
181+
* logger.info(`${name} is ${state}`);
182+
* }
183+
*/
184+
static getAllState = fpmImportAsync("getAllState");
185+
186+
/**
187+
* remove a fake player
188+
* @type {(name: string) => Promise<{success: boolean, reason: string}>}
189+
* @example
190+
* const { success, reason } = await FpmApi.remove("Player");
191+
*/
192+
static remove = fpmImportAsync("remove");
193+
194+
/**
195+
* remove all fake players
196+
* @type {() => Promise<string[]>}
197+
* @example
198+
* const list = await FpmApi.removeAll();
199+
* logger.info(`${list.length} players removed.`);
200+
*/
201+
static removeAll = fpmImportAsync("removeAll");
202+
203+
/**
204+
* connect all fake players
205+
* @type {() => Promise<string[]>}
206+
* @example
207+
* const list = await FpmApi.connectAll();
208+
* logger.info(`${list.length} players connected.`);
209+
*/
210+
static connectAll = fpmImportAsync("connectAll");
211+
212+
/**
213+
* disconnect all fake players
214+
* @type {() => Promise<string[]>}
215+
* @example
216+
* const list = await FpmApi.disconnectAll();
217+
* logger.info(`${list.length} players disconnected.`);
218+
*/
219+
static disconnectAll = fpmImportAsync("disconnectAll");
220+
221+
/**
222+
* set chat control of a fake player
223+
* @type {(name: string, allowChatControl: boolean) => Promise<{success: boolean, reason: string}>}
224+
* @example
225+
* const { success, reason } = await FpmApi.setChatControl("Player", true);
226+
* @example
227+
* const { success, reason } = await FpmApi.setChatControl("Player", false);
228+
*/
229+
static setChatControl = fpmImportAsync("setChatControl");
230+
231+
/**
232+
* reconnect FakePlayerManager WebSocket
233+
* @type {() => Promise<boolean>}
234+
*/
235+
static reconnect = fpmImportAsync("reconnect");
236+
237+
/**
238+
* whether the FakePlayerManager is ready
239+
* @type {() => boolean}
240+
*/
241+
static _isReady = fpmImport("isReady");
242+
/**
243+
* FakePlayerManager version
244+
* @type {() => number[]}
245+
*/
246+
static _version = fpmImport("version");
247+
248+
/**
249+
* whether the FakePlayerManager is ready
250+
* @type {() => boolean}
251+
*/
252+
static get ready(){ return FPM_INSTALLED && FpmApi._isReady(); }
253+
/**
254+
* FakePlayerManager version
255+
* @type {() => number[]}
256+
*/
257+
static get version(){ return FpmApi._version(); }
258+
static get versionString(){ return FpmApi.version.join("."); }
259+
260+
/**
261+
* disable the constructor
262+
* @private
263+
* @constructor
264+
*/
265+
constructor(){
266+
throw new Error("This is a static class.");
267+
}
268+
}
269+
270+
/////////////////////////////////////// FakePlayerManager API END ///////////////////////////////////////
271+
272+
if(FPM_API_DEBUG) {
273+
(async () => {
274+
const list = await FpmApi.list();
275+
logger.info(`${list.length} players found.`);
276+
logger.info(`list: ${list.join(", ")}`);
277+
for (const name of list) {
278+
if (!name.startsWith("test_"))
279+
continue;
280+
const { success, reason } = await FpmApi.connect(name);
281+
if (!success) {
282+
logger.error(`${name} connect failed: ${reason}`);
283+
}
284+
}
285+
})().catch(err => {
286+
logger.error(err.stack);
287+
});
288+
}

0 commit comments

Comments
 (0)