Skip to content

Commit

Permalink
Merge pull request #30 from EvoEsports/dev
Browse files Browse the repository at this point in the history
Version 0.3.8
  • Loading branch information
Chris92de authored Jun 28, 2024
2 parents 483ddda + 45a428a commit c1fe19b
Show file tree
Hide file tree
Showing 23 changed files with 3,407 additions and 1,007 deletions.
1 change: 1 addition & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker build -t minicontrol:test -f docker/Dockerfile .
Binary file modified bun.lockb
Binary file not shown.
8 changes: 7 additions & 1 deletion core/mapmanager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export interface Map {
AuthorNickname?: string;
AuthorTime: number;
GoldTime: number;
SilverTime: number;
BronzeTime: number;
CopperPrize: number;
FileName: string;
Environnement: string;
Mood: string;
Expand Down Expand Up @@ -61,13 +64,16 @@ class MapManager {
*/
async syncMaplist() {
this.maps = {};

const chunckedMaps: any = chunkArray(await tmc.server.call("GetMapList", -1, 0), 100);
let method = "GetMapInfo";
if (tmc.game.Name == "TmForever") method = "GetChallengeInfo";

for (const infos of chunckedMaps) {
let out = [];

for (const map of infos) {
out.push(["GetMapInfo", map.FileName]);
out.push([method, map.FileName]);
}

let res = await tmc.server.multicall(out) || [];
Expand Down
48 changes: 25 additions & 23 deletions core/minicontrol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class MiniControl {
* The version of MiniControl.
*/
readonly brand: string = "$n$o$eeeMINI$o$z$s$abccontrol$z$s¤white¤";
readonly version: string = "0.3.7";
readonly version: string = "0.3.8";
/**
* The start time of MiniControl.
*/
Expand Down Expand Up @@ -308,6 +308,7 @@ class MiniControl {
if (this.startComplete) return;
const port = Number.parseInt(process.env.XMLRPC_PORT || "5000");
this.cli("¤info¤Starting MiniControl...");
this.cli(`¤info¤Using Bun ¤white¤${Bun.version}`);
this.cli("¤info¤Connecting to Trackmania Dedicated server at ¤white¤" + (process.env.XMLRPC_HOST ?? "127.0.0.1") + ":" + port);
const status = await this.server.connect(process.env.XMLRPC_HOST ?? "127.0.0.1", port);
if (!status) {
Expand Down Expand Up @@ -352,38 +353,36 @@ class MiniControl {
plugins = plugins.concat(fs.readdirSync(process.cwd() + "/userdata/plugins", { withFileTypes: true, recursive: true }));
const exclude = process.env.EXCLUDED_PLUGINS?.split(",") || [];
let loadList = [];
for (const i in plugins) {
let include = false;
const plugin = plugins[i];
include = plugin && plugin.isDirectory();
const path = plugin.path.replace(process.cwd() + "/core/plugins", "").replace(process.cwd() + "/userdata/plugins", "");
let pluginName = plugin.name.replaceAll("\\", "/");
if (path != "") {
pluginName = (path.substring(1) +"/"+ plugin.name).replaceAll("\\", "/");
}

for (const excludeName of exclude) {
if (excludeName == "") continue;
if (pluginName.replaceAll("\\", "/").startsWith(excludeName.trim())) {
include = false;
break;
}
}

for (const plugin of plugins) {
let include = plugin && plugin.isDirectory();
const directory = plugin.path.replace(path.resolve("core", "plugins"), "").replace(path.resolve("userdata", "plugins"), "");
if (include) {
loadList.push(pluginName);
let pluginName = plugin.name;
if (directory != "") {
pluginName = (directory + "/" + plugin.name).replaceAll("\\", "/");
if (pluginName.startsWith("/")) pluginName = pluginName.substring(1);
}
for (const excludeName of exclude) {
if (excludeName == "") continue;
if (pluginName.startsWith(excludeName.trim())) {
include = false;
}
}
if (include) {
loadList.push(pluginName);
}
}
}

// load metadata
for (const name of loadList) {
const pluginName = process.cwd() + "/" + this.findPlugin(name)
const pluginName = this.findPlugin(name);
if (pluginName == null) {
const msg = `¤error¤Didn't find a plugin. resolved plugin name is null.`;
this.cli(msg);
continue;
}
const cls = await import(pluginName);
const cls = await import(process.cwd() + "/" + pluginName);
const plugin = cls.default;
if (plugin == undefined) {
const msg = `¤gray¤Plugin ¤cmd¤${name}¤error¤ failed to load. Plugin has no default export.`;
Expand Down Expand Up @@ -412,8 +411,11 @@ class MiniControl {
}
}
}

for (const plugin of this.pluginDependecies.overallOrder()) {
await this.loadPlugin(plugin)
if (loadList.includes(plugin)) {
await this.loadPlugin(plugin)
}
}

this.server.send("Echo", this.startTime, "MiniControl");
Expand Down
65 changes: 48 additions & 17 deletions core/playermanager.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,48 @@
import { sleep } from "bun";
import { clone } from "./utils";

// import casual from 'casual';
interface PlayerRanking {
Path: string;
Score: number;
Ranking: number;
TotalCount: number;
}

interface Avatar {
FileName: string;
Checksum: string;
}
interface LadderStats {
LastMatchScore: number;
NbrMAtchWins: number;
NbrMatchDraws: number;
nbrMatchLosses: number;
TeamName: string;
}
/**
* Player class
*/
export class Player {
login: string = "";
nickname: string = "";
isSpectator: boolean = false;
playerId: number = -1;
teamId: number = -1;
path = "";
language = "en";
clientVersion = "";
iPAddress = "";
downloadRate: number = -1;
uploadRate: number = -1;
isSpectator: boolean = false;
ladderRanking: number = 0;
ladderStats?: LadderStats;
avatar?: Avatar;
hoursSinceZoneInscription: number = -1;
/** 3 for united */
onlineRights = -1;
isAdmin: boolean = false;
spectatorTarget: number = 0;
flags: number = 0;
[key: string]: any; // Add index signature

async syncFromDetailedPlayerInfo(data: any) {
Expand All @@ -21,6 +52,9 @@ export class Player {
k = "nickname";
data[key] = data[key].replace(/[$][lh]\[.*?](.*?)([$][lh])?/i, "$1").replaceAll(/[$][lh]/gi, "");
}
if (k == "flags") {
this.spectatorTarget = Math.floor(data.Flags / 10000);
}
this[k] = data[key];
}
this.isAdmin = tmc.admins.includes(data.Login);
Expand Down Expand Up @@ -58,15 +92,6 @@ export default class PlayerManager {
if (data.PlayerId === 0) continue;
await this.getPlayer(data.Login);
}

// Generate mock players
/* for (let x = 0; x < 100; x++) {
const player = new Player();
player.login = "*Bot_"+casual.username;
player.nick = casual.full_name;
player.isSpectator = casual.coin_flip? true : false;
this.players.push(player);
} */
}

/**
Expand All @@ -81,8 +106,12 @@ export default class PlayerManager {
private async onPlayerConnect(data: any) {
await sleep(100);
const login = data[0];
const player = await this.getPlayer(login);
tmc.server.emit("TMC.PlayerConnect", player);
if (login) {
const player = await this.getPlayer(login);
tmc.server.emit("TMC.PlayerConnect", player);
} else {
tmc.debug("¤error¤Unknown player tried to connect, ignored.");
}
}

/**
Expand All @@ -92,18 +121,20 @@ export default class PlayerManager {
*/
private async onPlayerDisconnect(data: any) {
const login = data[0];
if (this.players[login]) {
if (login && this.players[login]) {
tmc.server.emit("TMC.PlayerDisconnect", clone(this.players[login]));
delete this.players[login];
} else {
tmc.debug("¤Error¤Unknown player tried to disconnect or player not found at server. ignored.")
}
}

/**
* get clone of players objects
* get players objects
* @returns {Player[]} Returns clone of the current playerlist
*/
get(): Player[] {
return clone(Object.values(this.players));
return Object.values(this.players);
}

/**
Expand All @@ -125,7 +156,7 @@ export default class PlayerManager {
*/
async getPlayer(login: string): Promise<Player> {
if (this.players[login]) return this.players[login];
tmc.debug(`$888 Player ${login} not found, fetching from server.`);
tmc.debug(`$888Player ${login} not found, fetching from server.`);

const data = await tmc.server.call("GetDetailedPlayerInfo", login);
const player = new Player();
Expand Down
2 changes: 1 addition & 1 deletion core/plugins/admin/LocalMapsWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default class LocalMapsWindow extends ListWindow {

async onAction(login: string, action: string, item: any) {
if (action == "Add") {
await tmc.chatCmd.execute(login, "//addlocal " + item.Name);
await tmc.chatCmd.execute(login, `//addlocal "${item.Name}"`);
}
}
}
3 changes: 2 additions & 1 deletion core/plugins/admin/PlayerListsWindow.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ListWindow from 'core/ui/listwindow';

export default class LocalMapsWindow extends ListWindow {
export default class PlayerListWindow extends ListWindow {

async onAction(login: string, action: string, item: any) {
if (action == "RemoveGuest") {
Expand All @@ -12,4 +12,5 @@ export default class LocalMapsWindow extends ListWindow {
await tmc.chatCmd.execute(login, "//blacklist show");
}
}

}
31 changes: 24 additions & 7 deletions core/plugins/admin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ export default class AdminPlugin extends Plugin {
}, "Send mode command");
tmc.addCommand("//guestlist", this.cmdGuestlist.bind(this), "Manage Guestlist");
tmc.addCommand("//blacklist", this.cmdBlacklist.bind(this), "Manage Blacklist");

tmc.addCommand("//togglemute", this.cmdToggleMute.bind(this), "Toggle Mute");
}

async onUnload() {
Expand All @@ -290,6 +290,7 @@ export default class AdminPlugin extends Plugin {
tmc.removeCommand("//warmup");
tmc.removeCommand("//ignore");
tmc.removeCommand("//unignore");
tmc.removeCommand("//togglemute");
tmc.removeCommand("//talimit");
tmc.removeCommand("//jump");
tmc.removeCommand("//wml");
Expand Down Expand Up @@ -386,12 +387,8 @@ export default class AdminPlugin extends Plugin {
let out = [];
for (let file of fs.readdirSync(tmc.mapsPath, { withFileTypes: true, recursive: true, encoding: "utf8" })) {
if (file.name.toLowerCase().endsWith(".gbx")) {
const split = escape(file.name.replaceAll(/[.](Map|Challenge)[.]Gbx/gi, "")).split(/[\\/]/);
let name = split[split.length - 1];
let path = "/";
if (split.length > 1) {
path = split.slice(0, split.length - 1).join("/") + "/";
}
let name = escape(file.name.replaceAll(/[.](Map|Challenge)[.]Gbx/gi, ""));
let path = file.path.replace(tmc.mapsPath, "");
out.push({
Name: name,
Path: path
Expand All @@ -415,6 +412,26 @@ export default class AdminPlugin extends Plugin {
}
}
}
async cmdToggleMute(login: any, args: string[]) {
if (args.length < 1) {
tmc.chat("Usage: ¤cmd¤//togglemute ¤white¤<login>", login);
return;
}
try {
let ignores = await tmc.server.call("GetIgnoreList", 1000, 0);
for (const ignore of ignores) {
if (ignore.Login == args[0]) {
tmc.server.send("UnIgnore", args[0]);
tmc.chat(`¤info¤UnIgnoring ¤white¤${args[0]}`, login);
return;
}
}
tmc.server.send("Ignore", args[0]);
tmc.chat(`¤info¤Ignoring ¤white¤${args[0]}`, login);
} catch (e: any) {
tmc.chat(e, login);
}
}

async cmdSetSetting(login: any, args: string[]) {
if (args.length < 2) {
Expand Down
4 changes: 2 additions & 2 deletions core/plugins/maps/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ export default class Maps extends Plugin {
tmc.storage["menu"]?.removeItem("Map Queue");
}

async onStart(): Promise<void> {
async onStart() {
if (tmc.storage["menu"]) {
tmc.storage["menu"].addItem({
category: "Map",
title: "Show: List",
action: "/maps"
action: "/list"
});
tmc.storage["menu"].addItem({
category: "Map",
Expand Down
10 changes: 8 additions & 2 deletions core/plugins/maps/mapsWindow.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Confirm from 'core/ui/confirm';
import ListWindow from 'core/ui/listwindow';
import { formatTime, escape, removeColors } from 'core/utils';

Expand Down Expand Up @@ -34,10 +35,15 @@ export default class MapsWindow extends ListWindow {
if (action == "Jump") {
await tmc.chatCmd.execute(login, "//jump " + item.Uid);
} else if (action == "Delete") {
await tmc.chatCmd.execute(login, "//remove " + item.UId);
await this.uiPaginate(login, "", []);
const confirm = new Confirm(login, "Confirm Delete", this.applyCommand.bind(this), [login, "//remove " + item.UId]);
await confirm.display();
} else if (action == "Queue") {
await tmc.chatCmd.execute(login, "/addqueue " + item.UId);
}
}

async applyCommand(login: string, action: string) {
await tmc.chatCmd.execute(login, action);
await this.uiPaginate(login, "", []);
}
}
19 changes: 16 additions & 3 deletions core/plugins/players/PlayerWindow.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
import Confirm from 'core/ui/confirm';
import ListWindow from 'core/ui/listwindow';

export default class PlayerWindow extends ListWindow {

async onAction(login: string, action: string, item: any): Promise<void> {
if (action == "Kick") {
await tmc.chatCmd.execute(login, "//kick " + item.login);
} else if (action == "Ban") {
await tmc.chatCmd.execute(login, "//ban " + item.login);
const confirm = new Confirm(login, `Kick ${item.nickname}`, this.applyCommand.bind(this), [login, "//kick " + item.login]);
await confirm.display();
}
if (action == "Ban") {
const confirm = new Confirm(login, `Ban ${item.nickname}`, this.applyCommand.bind(this), [login, "//ban " + item.login]);
await confirm.display();
}
if (action == "Mute") {
await tmc.chatCmd.execute(login, "//togglemute " + item.login);
}
}

async applyCommand(login: string, action: string) {
await tmc.chatCmd.execute(login, action);
await tmc.chatCmd.execute(login, "/players");
}

}
Loading

0 comments on commit c1fe19b

Please sign in to comment.